Android线程间通信二主线程发消息给子线程

来源:互联网 发布:剑灵外形数据 编辑:程序博客网 时间:2024/04/28 22:11

线程间通信是Android开发中经常使用的技术,上篇文章示范了子线程完成耗时操作把结果告诉主线程,不过上个例子有个漏洞,我们常见的应用都是需要下载大量图片的,比如淘宝、京东、QQ、微信等都是在使用过程中需要大量下载图片,如果我们每次下载一张图片都new出一个子线程,那么我们应用很有可能因为创建太多子线程而崩溃,这个问题该怎么解决呢?

问题是出在为了下载图片,创建了过多的子线程引起的,那么如果我们只创建一个子线程,让这一个子线程去下载图片,当一张图片下载完了继续下载下一张图片,这样就把问题解决了,这样就可以当主线程需要下载的时候告诉子线程,让子线程去下载,子线程下载完后把结果告诉主线程;

结果图:


代码:

import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.os.Bundle;import android.os.Handler;import android.os.Looper;import android.os.Message;import android.support.v7.app.AppCompatActivity;import android.view.View;import android.widget.Button;import android.widget.TextView;import java.io.IOException;import java.io.InputStream;import java.net.HttpURLConnection;import java.net.MalformedURLException;import java.net.URL;/** * Created by wyx on 2015/12/28. */public class QueueActivity extends AppCompatActivity implements View.OnClickListener {    private Button mBtnAddDownload;    private TextView tvDownloadCount;    private int allCount;    private int successCount;    private int failedCount;    static final int DOWNLOAD_SUCCESS = 0;    static final int DOWNLOAD_FAILED = 1;    static final int ADD_DOWNLOAD = 2;    Handler mSubThreadHandler;    Handler mHandler = new Handler(){        @Override        public void handleMessage(Message msg) {            switch (msg.what){                case DOWNLOAD_SUCCESS:                    successCount++;                    break;                case DOWNLOAD_FAILED:                    failedCount ++;                    break;            }            StringBuilder buffer = new StringBuilder();            buffer.append("下载总数:").append(allCount).append('\n')                    .append("成功次数:").append(successCount).append('\n')                    .append("失败次数:").append(failedCount);            tvDownloadCount.setText(buffer.toString());        }    };    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_queue);        initUI();        startQueue();    }    private void initUI() {        this.mBtnAddDownload = (Button)findViewById(R.id.btn_add_download);        this.tvDownloadCount = (TextView) findViewById(R.id.tv_download_count);        mBtnAddDownload.setOnClickListener(this);    }    @Override    public void onClick(View v) {        switch (v.getId()){            case R.id.btn_add_download:                // 增加一天下载数                allCount++;                // 告诉子线程添加下载任务                mSubThreadHandler.sendEmptyMessage(ADD_DOWNLOAD);                break;        }    }    /**     * 开启一个子线程,使用Looper+Handler完成一个轮循处理机制,     */    private void startQueue() {        new Thread(new Runnable() {            @Override            public void run() {                Looper.prepare();                mSubThreadHandler = new Handler(Looper.myLooper()){                    @Override                    public void handleMessage(Message msg) {                        switch (msg.what){                            case ADD_DOWNLOAD:                                dowanload();                                break;                        }                    }                };                Looper.loop();            }        }).start();    }    private void dowanload() {        InputStream is = null;        try {            URL url = new URL(MainActivity.IMG_PATH);            // 获取网络连接对象            HttpURLConnection con = (HttpURLConnection) url.openConnection();            // 得到网络资源输入流            is = con.getInputStream();            // 利用图片工厂把输入流转换成图片            Bitmap bitmap = BitmapFactory.decodeStream(is);            // 新建消息对象            Message msg = new Message();            // 设置消息动作含义            msg.what = DOWNLOAD_SUCCESS;            msg.obj = bitmap;            // 完成下载发送消息给主线程;            mHandler.sendMessage(msg);        } catch (MalformedURLException e) {            // 出现URL异常发送给主线程            Message msg = new Message();            msg.what = DOWNLOAD_FAILED;            // mHandler.sendEmptyMessage(IMG_DOWNLOAD_URL_ERROR);            mHandler.sendMessage(msg);        } catch (IOException e) {            // 出现IO异常发送给主线程            Message msg = new Message();            msg.what = DOWNLOAD_FAILED;            mHandler.sendMessage(msg);        }finally{            // 关闭流            if(is != null){                try {                    is.close();                } catch (IOException e) {                }            }        }    }    @Override    public void finish() {        super.finish();        if(mSubThreadHandler!=null){            // 队列不需要的时候要清除掉            mSubThreadHandler.getLooper().quit();        }    }}
布局文件代码:

<?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"              android:padding="8dp">    <Button        android:id="@+id/btn_add_download"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="增加一次下载"        android:textSize="16sp"        />    <TextView        android:id="@+id/tv_download_count"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:textSize="16sp"        android:layout_marginTop="8dp"        /></LinearLayout>
分析:

有上一篇例子的内容基础,这次改变就在于把下载操作都放在了一个线程里面,使用Looper+Handler的方式进行循环处理子线的消息;在onCreat()方法中调用了startQueue(),在startQueue()中开启了一个子线程,子线程的run()方法里调用了Looper.prepare(),mSubThreadHandler = new Handler(Looper.myLooper()),Looper.loop(),这三个步骤在子线程中不能缺少才能完成循环队列的设置,其中mSubThreadHandler = new Handler(Looper.myLooper())是表示new出一个当前线程的消息处理器,当前线程是子线程,所以是子线程的消息处理器,当主线程使用mSubThreadHandler发送消息时,是在子线程中处理消息;




0 0
原创粉丝点击