研究了android從網路上非同步載入映像,現總結如下:
(1)由於android UI更新支援單一線程原則,所以從網路上取資料並更新到介面上,為了不阻塞主線程首先可能會想到以下方法。
在主線程中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.png"); } catch (IOException e) { } ((ImageView) LazyLoadImageActivity.this.findViewById(id)).setImageDrawable(drawable); } }); }
上面這個方法缺點很顯然,經測試,如果要載入多個圖片,這並不能實現非同步載入,而是等到所有的圖片都載入完才一起顯示,因為它們都運行在一個線程中。
然後,我們可以簡單改進下,將Handler+Runnable模式改為Handler+Thread+Message模式不就能實現同時開啟多個線程嗎?
(2)在主線程中new 一個Handler對象,代碼如下:
final Handler handler2=new Handler(){ @Overridepublic void handleMessage(Message msg) { ((ImageView) LazyLoadImageActivity.this.findViewById(msg.arg1)).setImageDrawable((Drawable)msg.obj); } };
對應載入映像代碼如下:
//採用handler+Thread模式實現多線程非同步載入 private void loadImage2(final String url, final int id) { Thread thread = new Thread(){ @Overridepublic void run() { Drawable drawable = null; try { drawable = Drawable.createFromStream(new URL(url).openStream(), "image.png"); } catch (IOException e) { } Message message= handler2.obtainMessage() ; message.arg1 = id; message.obj = drawable; handler2.sendMessage(message); } }; thread.start(); thread = null; }
這樣就簡單實現了非同步載入了。細想一下,還可以最佳化的,比如引入線程池、引入緩衝等,我們先介紹線程池。
(3)引入ExecutorService介面,於是代碼可以最佳化如下:
在主線程中加入:private ExecutorService executorService = Executors.newFixedThreadPool(5);
對應載入映像方法更改如下:
// 引入線程池來管理多線程 private void loadImage3(final String url, final int id) { executorService.submit(new Runnable() { public void run() { try { final Drawable drawable = Drawable.createFromStream(new URL(url).openStream(), "image.png"); handler.post(new Runnable() { public void run() { ((ImageView) LazyLoadImageActivity.this.findViewById(id)).setImageDrawable(drawable); } }); } catch (Exception e) { throw new RuntimeException(e); } } }); }