由于原文的结构有些不是很容易看清,先整理如下:
原文:http://www.eoeandroid.com/thread-210082-1-1.html

清单文件

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"package="com.example.test"android:versionCode="1"android:versionName="1.0" ><uses-permission android:name="android.permission.INTERNET" /><uses-sdk
        android:minSdkVersion="8"android:targetSdkVersion="8" /><application
        android:allowBackup="true"android:icon="@drawable/ic_launcher"android:label="@string/app_name"android:theme="@style/AppTheme" ><activity
            android:name="com.example.test.MainActivity"android:label="@string/app_name" ><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter></activity><activity
            android:name="com.example.test.MainActivity0"android:label="@string/app_name" ></activity><activity
            android:name="com.example.test.MainActivity1"android:label="@string/app_name" ></activity><activity
            android:name="com.example.test.MainActivity2"android:label="@string/app_name" ></activity><activity
            android:name="com.example.test.MainActivity3"android:label="@string/app_name" ></activity></application></manifest>

菜单Activity(XML+Java文件)

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:id="@+id/container"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical" ><Buttonandroid:id="@+id/bt0"android:layout_width="wrap_content"android:layout_height="wrap_content"android:onClick="zero"android:text="0" /><Buttonandroid:id="@+id/bt1"android:layout_width="wrap_content"android:layout_height="wrap_content"android:onClick="one"android:text="1" /><Buttonandroid:id="@+id/bt2"android:layout_width="wrap_content"android:layout_height="wrap_content"android:onClick="two"android:text="2" /><Buttonandroid:id="@+id/bt3"android:layout_width="wrap_content"android:layout_height="wrap_content"android:onClick="three"android:text="3" /></LinearLayout>

Java文件

public class MainActivity extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);}public void zero(View v){Intent intent = new Intent(MainActivity.this, MainActivity0.class);startActivity(intent);}public void one(View v){Intent intent = new Intent(MainActivity.this, MainActivity1.class);startActivity(intent);}public void two(View v){Intent intent = new Intent(MainActivity.this, MainActivity2.class);startActivity(intent);}public void three(View v){Intent intent = new Intent(MainActivity.this, MainActivity3.class);startActivity(intent);}}

1Handler+Runnable模式(XML+Java文件,加载图片共用的XML)

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:id="@+id/container"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical" ><ImageView
        android:id="@+id/i1"android:layout_width="100dp"android:layout_height="100dp" /><ImageView
        android:id="@+id/i2"android:layout_width="100dp"android:layout_height="100dp" /><ImageView
        android:id="@+id/i3"android:layout_width="100dp"android:layout_height="100dp" /><ImageView
        android:id="@+id/i4"android:layout_width="100dp"android:layout_height="100dp" /></LinearLayout>
public class MainActivity0 extends Activity {@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main0);loadImage0("http://www.baidu.com/img/baidu_logo.gif", R.id.i1);loadImage0("http://www.chinatelecom.com.cn/images/logo_new.gif",R.id.i2);loadImage0("http://cache.soso.com/30d/img/web/logo.gif", R.id.i3);loadImage0("http://csdnimg.cn/www/images/csdnindex_logo.gif", R.id.i4);}private Handler handler = new Handler();private void loadImage0(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.d("test", e.getMessage());}if (drawable == null) {Log.d("test", "null drawable");} else {Log.d("test", "not null drawable");}// 为了测试缓存而模拟的网络延时SystemClock.sleep(2000);((ImageView) findViewById(id)).setImageDrawable(drawable);}});}
}

分析:此种加载方式会阻塞UI线程,在较新的Android版本,是不允许这样做的,如果UI线程访问网络,会抛出异常:NetworkOnMainThreadException,因此大家看到我的清单文件中的版本是很低的,为了能够让程序运行起来。另外,这种方式需要等4张图片一张张加载完才会显示UI,所以用户体验是相当差的。

2Handler+Thread+Message模式(Java文件)

public class MainActivity1 extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main0);loadImage2("http://www.baidu.com/img/baidu_logo.gif", R.id.i1);loadImage2("http://www.chinatelecom.com.cn/images/logo_new.gif",R.id.i2);loadImage2("http://cache.soso.com/30d/img/web/logo.gif", R.id.i3);loadImage2("http://csdnimg.cn/www/images/csdnindex_logo.gif", R.id.i4);}final Handler handler2 = new Handler() {@Overridepublic void handleMessage(Message msg) {((ImageView) findViewById(msg.arg1)).setImageDrawable((Drawable) msg.obj);}};public void loadImage2(final String url, final int id) {Thread thread = new Thread() {@Overridepublic void run() {super.run();Drawable drawable = null;try {drawable = Drawable.createFromStream(new URL(url).openStream(), "image.png");// 模拟网络延时SystemClock.sleep(2000);// 更新UI需要放到主线程Message message = handler2.obtainMessage();message.arg1 = id;message.obj = drawable;handler2.sendMessage(message);} catch (MalformedURLException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}};thread.start();thread = null;}
}

* 分析 * :同时开启4个thread访问图片

3Handler+ExecutorService(线程池)+MessageQueue模式(Java文件)

public class MainActivity2 extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main0);loadImage3("http://www.baidu.com/img/baidu_logo.gif", R.id.i1);loadImage3("http://www.chinatelecom.com.cn/images/logo_new.gif",R.id.i2);loadImage3("http://cache.soso.com/30d/img/web/logo.gif", R.id.i3);loadImage3("http://csdnimg.cn/www/images/csdnindex_logo.gif", R.id.i4);}private ExecutorService executorService = Executors.newFixedThreadPool(5);private Handler handler = new Handler();// 引入线程池来管理多线程public void loadImage3(final String url, final int id) {executorService.submit(new Runnable() {@Overridepublic void run() {try {final Drawable drawable = Drawable.createFromStream(new URL(url).openStream(), "image.png");// 模拟网络延时SystemClock.sleep(2000);handler.post(new Runnable() {public void run() {if (null != drawable) {((ImageView) findViewById(id)).setImageDrawable(drawable);}}});} catch (MalformedURLException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}});}
}

分析
能开线程的个数毕竟是有限的,我们总不能开很多线程,对于手机更是如此。
这个例子是使用线程池。Android拥有与Java相同的ExecutorService实现,我们就来用它。
线程池的基本思想还是一种对象池的思想,开辟一块内存空间,里面存放了众多(未死亡)的线程,池中线程执行调度由池管理器来处理。当有线程任务时,从池中取一个,执行完成后线程对象归池,这样可以避免反复创建线程对象所带来的性能开销,节省了系统的资源。
线程池的信息可以参看这篇文章:Java&Android的线程池-ExecutorService(应该是这篇)演示例子是创建一个可重用固定线程数的线程池。

4Handler+ExecutorService(线程池)+MessageQueue+缓存模式(Java文件)

public class AsyncImageLoader3 {// 为了加快速度,在内存中开启缓存(主要应用于重复图片较多时,或者同一个图片要多次被访问,比如在ListView时来回滚动)public Map<String, SoftReference<Drawable>> imageCache = new HashMap<String, SoftReference<Drawable>>();private ExecutorService executorService = Executors.newFixedThreadPool(5); // 固定五个线程来执行任务private final Handler handler = new Handler();public Drawable loadDrawable(final String imageUrl,final ImageCallback callback) {// 如果缓存过就从缓存中取出数据if (imageCache.containsKey(imageUrl)) {SoftReference<Drawable> softReference = imageCache.get(imageUrl);if (softReference.get() != null) {return softReference.get();}}// 缓存中没有图像,则从网络上取出数据,并将取出的数据缓存到内存中executorService.submit(new Runnable() {@Overridepublic void run() {final Drawable drawable = loadImageFromUrl(imageUrl);imageCache.put(imageUrl, new SoftReference<Drawable>(drawable));handler.post(new Runnable() {public void run() {callback.imageLoaded(drawable);}});}});return null;}// 从网络上取数据方法public Drawable loadImageFromUrl(String imageUrl) {try {// 测试时,模拟网络延时,实际时这行代码不能有SystemClock.sleep(2000);return Drawable.createFromStream(new URL(imageUrl).openStream(),"image.png");} catch (Exception e) {throw new RuntimeException(e);}}// 对外界开放的回调接口public interface ImageCallback {// 注意 此方法是用来设置目标对象的图像资源public void imageLoaded(Drawable imageDrawable);}
}
public class MainActivity3 extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main0);loadImage4("http://www.baidu.com/img/baidu_logo.gif", R.id.i1);loadImage4("http://www.chinatelecom.com.cn/images/logo_new.gif",R.id.i2);loadImage4("http://cache.soso.com/30d/img/web/logo.gif", R.id.i3);loadImage4("http://csdnimg.cn/www/images/csdnindex_logo.gif", R.id.i4);}private AsyncImageLoader3 asyncImageLoader3 = new AsyncImageLoader3();// 引入线程池,并引入内存缓存功能,并对外部调用封装了接口,简化调用过程private void loadImage4(final String url, final int id) {// 如果缓存过就会从缓存中取出图像,ImageCallback接口中方法也不会被执行Drawable cacheImage = asyncImageLoader3.loadDrawable(url,new AsyncImageLoader3.ImageCallback() {// 请参见实现:如果第一次加载url时下面方法会执行public void imageLoaded(Drawable imageDrawable) {((ImageView) findViewById(id)).setImageDrawable(imageDrawable);}});if (cacheImage != null) {((ImageView) findViewById(id)).setImageDrawable(cacheImage);}}
}

比起前一个做了几个改造:

  • 把整个代码封装在一个类中
  • 为了避免出现同时多次下载同一幅图的问题,使用了本地缓存

另外还记得享元模式么,这边第四种加载图片方式其实就是享元模式的运用,记不得请看这里。

Android Handler加载图片的几种方式(完)相关推荐

  1. iOS关于加载图片的几种方式选择

    最近在开发过程中遇到一些性能优化的东西,这次来说说关于图片加载的性能优化和选择. 大家都知道创建UIImage常用以下几种方式 + (nullable UIImage *)imageNamed:(NS ...

  2. QML for Android 加载图片资源的几种方式

    前言 前段时间用 QML 做一个简单的 android 程序,需要打开 android手机本地图片,原本是一个非常简单的功能,但是碰到一些坑着实的被坑了一把,然而在网上并没有找到相关的文档,这里做个总 ...

  3. Android Glide加载图片成圆形

    今天,简单讲解android使用glide加载图片成圆形. 这个很简单,因为之前需要在RecyclerView里加载圆形图片,所以在网上查找了资料,很简单就解决了. 1.导入依赖 implementa ...

  4. android webview 太大,Android应用开发之Android WebView加载图片显示过大的处理教程(代码教程)...

    本文将带你了解Android应用开发Android  WebView加载图片显示过大的处理教程(代码教程),希望本文对大家学Android有所帮助. Webview加载图片时,经常会遇到图片显示不符合 ...

  5. android glide圆形图片,Android Glide加载图片成圆形

    释放双眼,带上耳机,听听看~! 今天,简单讲解android使用glide加载图片成圆形. 这个很简单,因为之前需要在RecyclerView里加载圆形图片,所以在网上查找了资料,很简单就解决了. 1 ...

  6. Android Glide加载图片时转换为圆形、圆角、毛玻璃等图片效果

     Android Glide加载图片时转换为圆形.圆角.毛玻璃等图片效果 附录1简单介绍了Android开源的图片加载框架.在实际的开发中,虽然Glide解决了快速加载图片的问题,但还有一个问题悬 ...

  7. ajax加载vue数据,详解使用Vue.Js结合Jquery Ajax加载数据的两种方式

    整理文档,搜刮出一个使用vue.js结合jquery ajax加载数据的两种方式的代码,稍微整理精简一下做下分享. 废话不多说,直接上代码 html代码 demo {{message }} 测试jqu ...

  8. vue.js 动态加载 html,Vue加载组件、动态加载组件的几种方式

    什么是组件: 组件是Vue.js最强大的功能之一.组件可以扩展HTML元素,封装可重用的代码.在较高层面上,组件是自定义的元素,Vue.js的编译器为它添加特殊功能.在有些情况下,组件也可以是原生HT ...

  9. Vue动态加载组件的四种方式

    动态加载组件的四种方式: 1.使用import导入组件,可以获取到组件 var name = 'system'; var myComponent =() => import('../compon ...

最新文章

  1. 如何在CentOS/RHEL 7上借助ssm管理LVM卷?
  2. 非域计算机上模拟域用户,App-V如何让非域内(工作组)PC 也能享受应用程序虚拟化...
  3. IoT与大数据 如何激发数字营销最大潜能?
  4. 通过docker build --build-arg 传值进 Dockerfile 动态构建容器
  5. rmmod无法卸载驱动_AMD芯片组驱动更新:优化了RYZEN CPU供电调节
  6. 在开发过程中调试报表插件详细教程
  7. dat文件导入cad画图步骤_怎么样给CAD文件加密?
  8. 微型计算机系统评课,微机课评课稿.pdf
  9. 开源音乐软件——落雪
  10. was升级jdk版本_was升级jdk1.7
  11. 浅谈0-day漏洞的在野利用
  12. k8s学习-深入理解Pod对象
  13. 计算机软著发明,时健
  14. 集中型计算机控制有什么特点,什么叫分散控制系统?它有什么特点?
  15. 低轨卫星传播特性仿真与分析
  16. B. Nick and Array(数学+贪心)Codeforces Round #569 (Div. 2)
  17. docker安装firefox
  18. 关于加减运算时能否使用等价无穷小的问题
  19. HR推荐:应届生简历制作的细节
  20. 基于LM2596和ESP32的数控直流电源

热门文章

  1. python数据挖掘与分析实战pdf_《Python数据分析与挖掘实战》PDF+完整源码
  2. 炸掉卡西欧991CNX
  3. mysql5.7 的 user表的密码字段从 password 变成了 authentication_string
  4. ArcGIS API for JavaScript:Layer之间那点儿事
  5. C# Wpf异步修改UI,多线程修改UI(二)
  6. 读《大道至简》第三章 有感
  7. SqlMap异常的处理
  8. 关于Paralle.For和Paralle.ForEach
  9. [新闻]炫目的全景与视频监控结合应用
  10. MIX08,迎来Silverlight2的新时代