zoukankan      html  css  js  c++  java
  • Android多线程分析之一:使用Thread异步下载图像

    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 呢?这样做有什么后果?这些问题将在后文详细解答。

  • 相关阅读:
    Balanced Binary Tree
    Swap Nodes in Pairs
    Reverse Nodes in k-Group
    Reverse Linked List II
    Remove Nth Node From End of List
    Remove Duplicates from Sorted List II
    Remove Duplicates from Sorted List
    Partition List
    Merge Two Sorted Lists
    【Yii2.0】1.2 Apache检查配置文件语法
  • 原文地址:https://www.cnblogs.com/kesalin/p/android_thread_demo.html
Copyright © 2011-2022 走看看