Android多线程分析之一:使用Thread异步下载图像

CC 许可,转载请注明出处
 

打算整理一下对 Android Framework 中多线程相关知识的理解,主要集中在 Framework 层的 Thread, Handler, Looper, MessageQueue, Message, AysncTask,当然不可避免地要涉及到 native 方法,因此也会分析 dalvik 中和线程以及消息处理相关的代码:如 dalvik 中的 C++ Thread 类以及 MessageQueue 类。本文将从一个使用 Thread 的简单 应用入手,引入 Thread 这个话题,接下来的几篇文章会依次介绍前面提到的那些主题。

这是一个使用 Android Thread 从网络上异步下载图片并在 ImageView 中显示的的简单示例。因为需要访问网络,所以要在 manifest.xml 中添加网络访问权限:

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

布局文件很简单,一个 Button,一个 ImageView:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="10dip" > <Button
android:id="@+id/LoadButton"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Load">
</Button> <ImageView
android:id="@+id/ImageVivew"
android:layout_width="match_parent"
android:layout_height="400dip"
android:scaleType="centerInside"
android:padding="2dp">
</ImageView> </LinearLayout>

接下来看代码:

首先来看定义:图片的 url 路径,两个消息值以及一些控件:

    private static final String sImageUrl = "http://fashion.qqread.com/ArtImage/20110225/0083_13.jpg";

    private static final int MSG_LOAD_SUCCESS = 0;
private static final int MSG_LOAD_FAILURE = 1; private Button mLoadButton;
private ProgressDialog mProgressBar;
private ImageView mImageView;

然后来看控件的设置:

	protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); Log.i("UI thread", " >> onCreate()"); mProgressBar = new ProgressDialog(this);
mProgressBar.setCancelable(true);
mProgressBar.setMessage("Image downloading ...");
mProgressBar.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
mProgressBar.setMax(100); mImageView = (ImageView)this.findViewById(R.id.ImageVivew); mLoadButton = (Button)this.findViewById(R.id.LoadButton);
mLoadButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mProgressBar.setProgress(0);
mProgressBar.show(); new Thread() {
@Override
public void run() {
Log.i("Load thread", " >> run()");
Bitmap bitmap = loadImageFromUrl(sImageUrl);
if (bitmap != null) {
Message msg = mHandler.obtainMessage(MSG_LOAD_SUCCESS, bitmap);
mHandler.sendMessage(msg);
}
else {
Message msg = mHandler.obtainMessage(MSG_LOAD_FAILURE, null);
mHandler.sendMessage(msg);
}
}
}.start();
}
});
}

loadImageFromUrl 是一个从网络下载 Bitmap 的 static 函数:

    static Bitmap loadImageFromUrl(String uil) {
Bitmap bitmap = null;
try{
InputStream in = new java.net.URL(sImageUrl).openStream();
bitmap = BitmapFactory.decodeStream(in);
in.close();
}
catch (Exception e) {
e.printStackTrace();
}
return bitmap;
}

mHandler 是主线程也就是 UI 线程中处理自定义消息的 Handler:

    private Handler mHandler= new Handler(){
@Override
public void handleMessage(Message msg) {
Log.i("UI thread", " >> handleMessage()"); switch(msg.what){
case MSG_LOAD_SUCCESS:
Bitmap bitmap = (Bitmap) msg.obj;
mImageView.setImageBitmap(bitmap); mProgressBar.setProgress(100);
mProgressBar.setMessage("Image downloading success!");
mProgressBar.dismiss();
break; case MSG_LOAD_FAILURE:
mProgressBar.setMessage("Image downloading failure!");
mProgressBar.dismiss();
break;
}
}
};

纵观上面的代码,当点击 load 按钮时,会创建一个匿名 Thread,并调用其 start() 启动运行线程,在这个线程中进行图像下载并解码成 Bitmap,然后通过 Handler 向 UI 线程发送消息以通知下载结果。这都是在匿名 Thead 中处理的。主线程也就是 UI 线程收到消息之后,会分发给 Handler,在它的 handleMessage 方法中根据消息 id 来处理下载结果,要么成功要么失败,并相应地更新 UI。运行该示例,你可以从 logcat 中看到 UI thread 和 Load thread 的线程id 是不同的,因为它们是两个独立的线程。

在匿名线程下载完毕之后,为什么不直接在这个线程的 run() 中更新 UI 呢?这样做有什么后果?这些问题将在后文详细解答。

Android多线程分析之一:使用Thread异步下载图像的更多相关文章

  1. Android多线程分析之中的一个:使用Thread异步下载图像

    Android多线程分析之中的一个:使用Thread异步下载图像 罗朝辉 (http://blog.csdn.net/kesalin) CC 许可.转载请注明出处 打算整理一下对 Android Fr ...

  2. Android多线程分析之五:使用AsyncTask异步下载图像

    Android多线程分析之五:使用AsyncTask异步下载图像 罗朝辉 (http://www.cnblogs.com/kesalin) CC 许可,转载请注明出处 在本系列文章的第一篇<An ...

  3. Android多线程分析之二:Thread的实现

    Android多线程分析之二:Thread的实现 罗朝辉 (http://www.cnblogs.com/kesalin/) CC 许可,转载请注明出处   在前文<Android多线程分析之一 ...

  4. Android多线程分析之三:Handler,Looper的实现

    Android多线程分析之三:Handler,Looper的实现 罗朝辉 (http://www.cnblogs.com/kesalin/) CC 许可,转载请注明出处 在前文<Android多 ...

  5. Android多线程分析之四:MessageQueue的实现

    Android多线程分析之四:MessageQueue的实现 罗朝辉 (http://www.cnblogs.com/kesalin/) CC 许可,转载请注明出处 在前面两篇文章<Androi ...

  6. Android Telephony分析(七) ---- 接口扩展(异步转同步)

    本文是基于上一篇<Android Telephony分析(六) —- 接口扩展(实践篇)>来写的.上一篇介绍的接口扩展的方法需要实现两部分代码:1. 从APP至RIL,发送请求:2. 从R ...

  7. ANDROID_MARS学习笔记_S04_009_用java.lang.ref.SoftReference作缓存,android.os.Handler和new Thread异步加载略图片

    一.简介 二.代码流程 1.private Map<String, SoftReference<Drawable>> imageCache = new HashMap<S ...

  8. UML分析AsyncDisplayKit框架-ASMuplexImageNode异步下载时序图。

    PS:博客园图片服务器不正常工作,数据上传后服务器返回http500,园方迟迟还没解决. 我从2016-01-18 05:52向园方反馈问题-请问博客园的图片服务器有在正常运行吗,至此时2016-01 ...

  9. Android四个多线程分析:MessageQueue实现

    Android四个多线程分析:MessageQueue的实现 罗朝辉 (http://blog.csdn.net/kesalin) CC 许可,转载请注明出处 在前面两篇文章<Android多线 ...

随机推荐

  1. 如何使用Nginx对抗DDoS攻击?

    时不时的就有客户会被DDoS一下.很多时候攻击很简单也容易封堵,但是攻击的目标是应用的时候就更难防御.在这里云端卫士介绍一下使用Nginx作为代理过滤器来封堵一些这种攻击. Apache DDoS攻击 ...

  2. RPLIDAR使用和测试

    采购的RPLIDAR刚刚到货,先拆封,内部包括雷达主机.线缆.串口USB转接.USB线.   根据说明在此处下载驱动和SDK,雷达的数据实际是通过串口输出的,所以驱动只是针对串口USB转换芯片CP21 ...

  3. 跟我学-Java底层技术系列文章

    对于工作中经常用到的东西,还是多看看实现原理,这样用着才能放心. 源码思想学习计划: 1.java基础库  HashCode深入理解 java线程框架窥探 2.集合类     java枚举类使用 递归 ...

  4. Hibernate-list()与iterate()方法的区别

    对于list方法而言,实际上Hibernate是通过一条Select SQL获取所有的记录.并将其读出,填入到POJO中返回.而iterate 方法,则是首先通过一条Select SQL 获取所有符合 ...

  5. Block循环引用问题研究

    自从苹果在objc中添加Block功能支持以后已经过了很久.目前网上对于Block的使用有很多介绍.不过对于Block的内存管理问题,则是众说纷纭.再加上objc开始使用ARC以后,对于Block的内 ...

  6. JavaScript-事件坐标

    事件坐标: 1.参照屏幕左上角e.screenX,e.screenY 2.参照文档显示区左上角:e.clientX||e.x , e.clientY||e.y 3.参照所在父元素的左上角:e.offs ...

  7. Unity4升级Unity5后Image Effects问题

    Assets\Editor\Image Effects\CameraMotionBlurEditor.js 会出现Ambiguous reference 'preview'错误提示,解决方法 查找pr ...

  8. Smarty缓存的5个知识点

    (1)页面缓存:整个页面全局的缓存 需要4个步骤: ①开启缓存  $smarty->caching = true; ②设置缓存的生命周期  $smarty->cache_lifetime ...

  9. 访问控制public/protected/private的区别

    Java支持四种不同的访问权限: 修饰符 说明 public 共有的,对所有类可见. protected 受保护的,对同一包内的类和所有子类可见. private 私有的,在同一类内可见. 默认的 在 ...

  10. centos7.2进入单用户模式

    1 - 在启动grub菜单,选择编辑选项启动 2 - 按键盘e键,来进入编辑界面 3 - 找到Linux 16的那一行,将ro改为rw init=/sysroot/bin/sh 4 - 现在按下 Co ...