一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

實例演示Android異步加載圖片

 杰出天下 2012-10-05

本文給大家演示異步加載圖片的分析過程。讓大家了解異步加載圖片的好處,以及如何更新UI。
首先給出main.xml布局文件:
簡單來說就是 LinearLayout 布局,其下放了2個TextView和5個ImageView。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
	xmlns:android="http://schemas./apk/res/android"
	android:orientation="vertical"
	android:layout_width="fill_parent"
	android:layout_height="fill_parent">
	<TextView
		android:text="圖片區(qū)域開始"
		android:id="@+id/textView2"
		android:layout_width="wrap_content"
		android:layout_height="wrap_content" />
	<ImageView
		android:id="@+id/imageView1"
		android:layout_height="wrap_content"
		android:src="@drawable/icon"
		android:layout_width="wrap_content" />
	<ImageView
		android:id="@+id/imageView2"
		android:layout_height="wrap_content"
		android:src="@drawable/icon"
		android:layout_width="wrap_content" />
	<ImageView
		android:id="@+id/imageView3"
		android:layout_height="wrap_content"
		android:src="@drawable/icon"
		android:layout_width="wrap_content" />
	<ImageView
		android:id="@+id/imageView4"
		android:layout_height="wrap_content"
		android:src="@drawable/icon"
		android:layout_width="wrap_content" />
	<ImageView
		android:id="@+id/imageView5"
		android:layout_height="wrap_content"
		android:src="@drawable/icon"
		android:layout_width="wrap_content" />
	<TextView
		android:text="圖片區(qū)域結(jié)束"
		android:id="@+id/textView1"
		android:layout_width="wrap_content"
		android:layout_height="wrap_content" />
</LinearLayout>

我們將演示的過程是異步從服務(wù)器上下載5張不同圖片,依次放入這5個ImageView。上下2個TextView 是為了方便我們看是否阻塞了UI的顯示。
當(dāng)然 AndroidManifest.xml 文件中要配置好網(wǎng)絡(luò)訪問權(quán)限。

<uses-permission android:name="android.permission.INTERNET" />

1)Handler+Runnable模式
我們先看一個并不是異步線程加載的例子,而是使用 Handler+Runnable模式。
注意這里不是新開的線程,這里的代碼其實是在UI主線程中下載圖片的。
我們運行下面代碼時,會發(fā)現(xiàn)它其實是阻塞了整個界面的顯示,需要所有圖片都加載完成后,才能顯示界面。

package com.szy.textviewimagedemo;

import java.io.IOException;
import java.net.URL;

import android.app.Activity;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Handler;
import android.os.SystemClock;
import android.util.Log;
import android.widget.ImageView;

/**
 *@author coolszy
 *@date 2012-2-13
 *@blog http://blog.
 *
 */
public class MainActivity extends Activity
{
	@Override
	public void onCreate(Bundle savedInstanceState)
	{
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
		loadImage("http://www.baidu.com/img/baidu_logo.gif", R.id.imageView1);
		loadImage("http://www./images/logo_new.gif", R.id.imageView2);
		loadImage("http://cache.soso.com/30d/img/web/logo.gif", R.id.imageView3);
		loadImage("http:///www/images/csdnindex_logo.gif", R.id.imageView4);
		loadImage("http://images.cnblogs.com/logo_small.gif", R.id.imageView5);
	}

	private Handler handler = new Handler();

	private void loadImage(final String url, final int id)
	{
		handler.post(new Runnable()
		{
			public void run()
			{
				Drawable drawable = null;
				try
				{
					drawable = Drawable.createFromStream(new URL(url).openStream(), "image.gif");
				} catch (IOException e)
				{
					Log.i("MainActivity", e.getMessage());
				}
				if (drawable == null)
				{
					Log.i("MainActivity", "null drawable");
				} else
				{
					Log.i("MainActivity", "not null drawable");
				}
				// 為了測試緩存而模擬的網(wǎng)絡(luò)延時
				SystemClock.sleep(2000);
				((ImageView) MainActivity.this.findViewById(id)).setImageDrawable(drawable);
			}
		});
	}
}

2)Handler+Thread+Message模式
這種模式使用了線程,所以可以看到異步加載的效果。
核心代碼:

package com.szy.textviewimagedemo;

import java.io.IOException;
import java.net.URL;

import android.app.Activity;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;
import android.util.Log;
import android.widget.ImageView;

/**
 *@author coolszy
 *@date 2012-2-13
 *@blog http://blog.
 *
 */
public class MainActivity extends Activity
{
	@Override
	public void onCreate(Bundle savedInstanceState)
	{
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
		Log.i("MainActivity", "MainThread ID:"+Thread.currentThread().getId());
		loadImage("http://www.baidu.com/img/baidu_logo.gif", R.id.imageView1);
		loadImage("http://www./images/logo_new.gif", R.id.imageView2);
		loadImage("http://cache.soso.com/30d/img/web/logo.gif", R.id.imageView3);
		loadImage("http:///www/images/csdnindex_logo.gif", R.id.imageView4);
		loadImage("http://images.cnblogs.com/logo_small.gif", R.id.imageView5);
	}

	final Handler handler = new Handler()
	{
		@Override
		public void handleMessage(Message msg)
		{
			Log.i("MainActivity", "UpdateUIThread ID:"+Thread.currentThread().getId());
			((ImageView) MainActivity.this.findViewById(msg.arg1)).setImageDrawable((Drawable) msg.obj);
		}
	};

	// 采用handler+Thread模式實現(xiàn)多線程異步加載
	private void loadImage(final String url, final int id)
	{
		Thread thread = new Thread()
		{
			@Override
			public void run()
			{
				Drawable drawable = null;
				try
				{
					Log.i("MainActivity", "Thread ID:"+Thread.currentThread().getId());
					drawable = Drawable.createFromStream(new URL(url).openStream(), "image.png");
				} catch (IOException e)
				{
					Log.i("MainActivity", e.getMessage());
				}

				// 模擬網(wǎng)絡(luò)延時
				SystemClock.sleep(2000);

				Message message = handler.obtainMessage();
				message.arg1 = id;
				message.obj = drawable;
				handler.sendMessage(message);
			}
		};
		thread.start();
		thread = null;
	}
}

這時候我們可以看到實現(xiàn)了異步加載, 界面打開時,五個ImageView都是沒有圖的,然后在各自線程下載完后才把圖自動更新上去。
3)Handler+ExecutorService(線程池)+MessageQueue模式
能開線程的個數(shù)畢竟是有限的,我們總不能開很多線程,對于手機更是如此。
這個例子是使用線程池。Android擁有與Java相同的ExecutorService實現(xiàn),我們就使用它。
線程池的基本思想還是一種對象池的思想,開辟一塊內(nèi)存空間,里面存放了眾多(未死亡)的線程,池中線程執(zhí)行調(diào)度由池管理器來處理。當(dāng)有線程任務(wù)時,從池中取一個,執(zhí)行完成后線程對象歸池,這樣可以避免反復(fù)創(chuàng)建線程對象所帶來的性能開銷,節(jié)省了系統(tǒng)的資源。
下面的演示例子是創(chuàng)建一個可重用固定線程數(shù)的線程池。
核心代碼

package com.szy.textviewimagedemo;

import java.net.URL;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import android.app.Activity;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Handler;
import android.os.SystemClock;
import android.util.Log;
import android.widget.ImageView;

/**
 *@author coolszy
 *@date 2012-2-13
 *@blog http://blog.
 *
 */
public class MainActivity extends Activity
{
	@Override
	public void onCreate(Bundle savedInstanceState)
	{
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
		Log.i("MainActivity", "MainThread ID:"+Thread.currentThread().getId());
		loadImage("http://www.baidu.com/img/baidu_logo.gif", R.id.imageView1);
		loadImage("http://www./images/logo_new.gif", R.id.imageView2);
		loadImage("http://cache.soso.com/30d/img/web/logo.gif", R.id.imageView3);
		loadImage("http:///www/images/csdnindex_logo.gif", R.id.imageView4);
		loadImage("http://images.cnblogs.com/logo_small.gif", R.id.imageView5);
	}

	private Handler handler = new Handler();

	private ExecutorService executorService = Executors.newFixedThreadPool(5);

	// 引入線程池來管理多線程
	private void loadImage(final String url, final int id)
	{
		executorService.submit(new Runnable()
		{
			public void run()
			{
				try
				{
					Log.i("MainActivity", "Thread ID:"+Thread.currentThread().getId());
					final Drawable drawable = Drawable.createFromStream(new URL(url).openStream(), "image.png");
					// 模擬網(wǎng)絡(luò)延時
					SystemClock.sleep(2000);
					handler.post(new Runnable()
					{
						public void run()
						{
							Log.i("MainActivity", "UpdateUIThread ID:"+Thread.currentThread().getId());
							((ImageView) MainActivity.this.findViewById(id)).setImageDrawable(drawable);
						}
					});
				} catch (Exception e)
				{
					throw new RuntimeException(e);
				}
			}
		});
	}
}

這里我們象第一步一樣使用了
handler.post(new Runnable() { }) 更新前段顯示當(dāng)然是在UI主線程,我們還有 executorService.submit(new Runnable() { }) 來確保下載是在線程池的線程中。
4)Handler+ExecutorService(線程池)+MessageQueue+緩存模式
下面比起前一個做了幾個改造:
把整個代碼封裝在一個類中,同時為了避免出現(xiàn)同時多次下載同一幅圖的問題,使用了本地緩存封裝的類:

package com.szy.textviewimagedemo;

import java.lang.ref.SoftReference;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.SystemClock;
import android.util.Log;

/**
 *@author coolszy
 *@date 2012-2-13
 *@blog http://blog.
 */

public class AsyncImageLoader
{
	// 為了加快速度,在內(nèi)存中開啟緩存(主要應(yīng)用于重復(fù)圖片較多時,或者同一個圖片要多次被訪問,比如在ListView時來回滾動)
	public Map<String, SoftReference<Drawable>> imageCache = new HashMap<String, SoftReference<Drawable>>();

	private ExecutorService executorService = Executors.newFixedThreadPool(5); // 固定五個線程來執(zhí)行任務(wù)
	private final Handler handler = new Handler();

	/**
	 *
	 * @param imageUrl
	 *            圖像url地址
	 * @param callback
	 *            回調(diào)接口
	 * @return 返回內(nèi)存中緩存的圖像,第一次加載返回null
	 */
	public Drawable loadDrawable(final String imageUrl, final ImageCallback callback)
	{
		// 如果緩存過就從緩存中取出數(shù)據(jù)
		if (imageCache.containsKey(imageUrl))
		{
			SoftReference<Drawable> softReference = imageCache.get(imageUrl);
			if (softReference.get() != null)
			{
				Log.i("MainActivity", "圖片存在緩存中.");
				return softReference.get();
			}
		}
		// 緩存中沒有圖像,則從網(wǎng)絡(luò)上取出數(shù)據(jù),并將取出的數(shù)據(jù)緩存到內(nèi)存中
		executorService.submit(new Runnable()
		{
			public void run()
			{
				try
				{
					Log.i("MainActivity", "下載圖片...");
					final Drawable drawable = loadImageFromUrl(imageUrl);
					imageCache.put(imageUrl, new SoftReference<Drawable>(drawable));
					handler.post(new Runnable()
					{
						public void run()
						{
							callback.imageLoaded(drawable);
						}
					});
				} catch (Exception e)
				{
					throw new RuntimeException(e);
				}
			}
		});
		return null;
	}

	// 從網(wǎng)絡(luò)上取數(shù)據(jù)方法
	protected Drawable loadImageFromUrl(String imageUrl)
	{
		try
		{
			// 測試時,模擬網(wǎng)絡(luò)延時,實際時這行代碼不能有
			SystemClock.sleep(2000);
			return Drawable.createFromStream(new URL(imageUrl).openStream(), "image.png");

		} catch (Exception e)
		{
			throw new RuntimeException(e);
		}
	}

	// 對外界開放的回調(diào)接口
	public interface ImageCallback
	{
		// 注意 此方法是用來設(shè)置目標(biāo)對象的圖像資源
		public void imageLoaded(Drawable imageDrawable);
	}
}

說明:
final參數(shù)是指當(dāng)函數(shù)參數(shù)為final類型時,你可以讀取使用該參數(shù),但是無法改變該參數(shù)的值。
這里使用SoftReference 是為了解決內(nèi)存不足的錯誤(OutOfMemoryError)的。
前端調(diào)用:

package com.szy.textviewimagedemo;

import android.app.Activity;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.widget.ImageView;

/**
 *@author coolszy
 *@date 2012-2-13
 *@blog http://blog.
 *
 */
public class MainActivity extends Activity
{
	@Override
	public void onCreate(Bundle savedInstanceState)
	{
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
		loadImage("http://www.baidu.com/img/baidu_logo.gif", R.id.imageView1);
		loadImage("http://www./images/logo_new.gif", R.id.imageView2);
		loadImage("http://cache.soso.com/30d/img/web/logo.gif", R.id.imageView3);
		loadImage("http:///www/images/csdnindex_logo.gif", R.id.imageView4);
		loadImage("http://images.cnblogs.com/logo_small.gif", R.id.imageView5);
	}

	private AsyncImageLoader asyncImageLoader = new AsyncImageLoader();

	// 引入線程池,并引入內(nèi)存緩存功能,并對外部調(diào)用封裝了接口,簡化調(diào)用過程
	private void loadImage(final String url, final int id)
	{
		// 如果緩存過就會從緩存中取出圖像,ImageCallback接口中方法也不會被執(zhí)行
		Drawable cacheImage = asyncImageLoader.loadDrawable(url, new AsyncImageLoader.ImageCallback()
		{
			// 請參見實現(xiàn):如果第一次加載url時下面方法會執(zhí)行
			public void imageLoaded(Drawable imageDrawable)
			{
				((ImageView) findViewById(id)).setImageDrawable(imageDrawable);
			}
		});
		if (cacheImage != null)
		{
			((ImageView) findViewById(id)).setImageDrawable(cacheImage);
		}
	}
}

若水工作室

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多

    91精品视频全国免费| 日本黄色录像韩国黄色录像| 欧美日韩中国性生活视频| 亚洲伦理中文字幕在线观看| 日本人妻免费一区二区三区| 国产成人精品一区在线观看| 高清不卡视频在线观看| 99精品国产自在现线观看| 亚洲av熟女一区二区三区蜜桃 | 国产精品一区二区香蕉视频| 99久久精品国产日本| 福利专区 久久精品午夜| 91精品国产综合久久不卡| 亚洲欧美国产网爆精品| 激情中文字幕在线观看| 久久精品国产亚洲av麻豆| 精品高清美女精品国产区| 国产欧美日韩精品一区二| 日韩一区二区三区高清在| 男人操女人下面国产剧情| 国产又长又粗又爽免费视频| 国产成人精品午夜福利| 美女被草的视频在线观看| 加勒比人妻精品一区二区| 熟女少妇久久一区二区三区| 中文字字幕在线中文乱码二区| 好吊色免费在线观看视频| 精品丝袜一区二区三区性色| 风间中文字幕亚洲一区| 69老司机精品视频在线观看| 99精品人妻少妇一区二区人人妻| 日韩av亚洲一区二区三区| 国产三级视频不卡在线观看| 日本大学生精油按摩在线观看| 久久综合狠狠综合久久综合| 亚洲中文字幕熟女丝袜久久 | 国产精品内射婷婷一级二级| 亚洲女同一区二区另类| 国产成人人人97超碰熟女| 成人欧美一区二区三区视频| 日本特黄特色大片免费观看|