【Android】消息机制应用

通过一个例子来熟悉下 Android 消息机制的使用,这个例子中主线程中有一个EditText、ImageView 和一个 Button,在 EditText 中输入图片地址后,点击 Button,主线程向后台线程发送消息请求下载图片,后台线程下载完图片后向主线程发送消息请求更新UI以显示下载的图片。通过这个例子一方面熟悉消息机制过的使用,另一方面理解 Handler 的双向传递。最终的效果如下:

这里写图片描述

主线程向后台线程发消息

这里写图片描述

后台线程向主线程发消息

这里写图片描述

示例源代码

布局文件 res/layout/activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">
    <EditText
        android:id="@+id/edittext_url"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
    <Button
        android:id="@+id/button_download"
        android:text="Download Image"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
    <ImageView
        android:id="@+id/imageview_image"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scaleType="center"
        />
</LinearLayout>

MainActivity 用于显示界面,作为主线程,它接收和处理更新界面的消息。

package com.wuhui.testhandler;

import android.app.Activity;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;

/**
 * Created by Administrator on 2015/5/6.
 */
public class MainActivity extends Activity {
    private EditText mEditText;
    private Button mButton;
    private ImageView mImageView;
    private Downloader mDownloader;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mEditText = (EditText)findViewById(R.id.edittext_url);
        mImageView = (ImageView)findViewById(R.id.imageview_image);

        /* 创建一个与主线程关联的 Handler,并传作为构造函数参数递给 Downloader 对象 */
        mDownloader = new Downloader(new Handler() {
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                switch (msg.what) {
                    case Downloader.MESSAGE_DOWNLOAD:
                        if (msg.obj != null) {
                            Bitmap bitmap = (Bitmap) msg.obj;
                            // 更新图片
                            mImageView.setImageBitmap(bitmap);
                        }
                        break;
                    default:
                        break;
                }
            }
        });
        mDownloader.start();        // 启动后台线程
        mDownloader.getLooper();    // 确保后台线程中的消息循环初始化

        mButton = (Button)findViewById(R.id.button_download);
        mButton.setOnClickListener(new Button.OnClickListener(){
            @Override
            public void onClick(View v) {
                // 下载图片
                mDownloader.downloadImage(mEditText.getText().toString());
            }
        });

    }
}

Downloader 类是一个后台线程,其继承自 HandlerThread 类,所以它具有消息循环。Downloader类负责接收和处理下载图片的消息。

package com.wuhui.testhandler;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Message;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

/**
 * Created by Administrator on 2015/5/6.
 */
public class Downloader extends HandlerThread{
    private static final String mName = "Downloader";
    public static final int MESSAGE_DOWNLOAD = 1;
    private Handler mHandler;               // 当前线程的 Handler
    private Handler mResponseHandler;       // 主线程的 Handler

    Downloader (Handler handler) {
        super(mName);
        mResponseHandler = handler;         // 保存主线程的 Handler
    }

    // 该函数在消息循环开始前被调用
    @Override
    protected void onLooperPrepared() {    
        super.onLooperPrepared();
        // 创建当前线程的 Handler
        mHandler = new Handler() {        
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                String imageUrl = (String)msg.obj;
                // 下载图片
                handleDownloadImage(imageUrl);
            }
        };
    }

    public void downloadImage(String imageUrl) {
        /**
         * 这里没有直接调用 handleDownloadImage 来下载图片,而是发送消息,
         * 这样做的好处是,如果连续有多张图片要下载,该方法也可以立即返回,
         * 由后台线程根据消息队列中的请求依次下载图片。
         * */

        // 将下载图片的消息发送给当前线程的消息队列
        mHandler.obtainMessage(MESSAGE_DOWNLOAD, imageUrl)
                .sendToTarget();
    }

    private void handleDownloadImage(String imageUrl) {
        try {
            URL url =  new URL(imageUrl);
            HttpURLConnection connection = (HttpURLConnection)url.openConnection();
            connection.connect();
            if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) {
                return;
            }
            InputStream in = connection.getInputStream();
            byte[] buffer = new byte[512];
            int readSize = 0;
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            while ((readSize = in.read(buffer)) > 0) {
                out.write(buffer, 0, readSize);
            }
            out.close();
            byte[] bitmapBytes= out.toByteArray();

            // 从下载的字节数据中解码出图片
            Bitmap bitmap = BitmapFactory.decodeByteArray(bitmapBytes, 0, bitmapBytes.length);

            // 向主线程发送消息,将下载的图片作为消息参数
            mResponseHandler.obtainMessage(MESSAGE_DOWNLOAD, bitmap)
                            .sendToTarget();

        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

上面就是全部代码了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值