zoukankan      html  css  js  c++  java
  • Handler实现线程之间的通信-下载文件动态更新进度条

    1. 原理

    每一个线程对应一个消息队列MessageQueue,实现线程之间的通信,可通过Handler对象将数据装进Message中,再将消息加入消息队列,而后线程会依次处理消息队列中的消息。

    2. Message

    初始化:一般使用Message.obtain()方法获取一个消息对象,该方法会检查Message对象池中是否存在可重复利用的对象,若无,才会new一个新对象。

    what:相当于Message的标识符,区别于其它消息。

    arg1、arg2:int类型,可传递整数。

    obj:object类型,可传递任意对象。

    3. 发送消息

    在子线程中可调用主线程的handler.sendMessage(msg)进行发送消息,经过一系列方法调用,会触发handler的handleMessage方法,从而进行消息处理。

    发送消息的主要方法:

    handler.sendMessage(Message msg);
    handler.sendMessageAtTime(Message msg, int time);
    handler.sendMessageDelayed(Message msg, int time);
    

    sendMessageAtTime()和sendMessageDelayed()区别在于前者是在指定时间发送消息,可配合SystemClock.uptimeMillis()使用;而后者则是延时发送消息。

    除了SendMessage()方法以外,还可以通过post()方法发送消息:

    handler.post(Runnable r);
    handler.postDelayed(Runnable r, int time);
    

    sendMessage()与post()的区别:http://blog.csdn.net/u013168615/article/details/47024073

    4. 内存泄漏

    http://www.cnblogs.com/xujian2014/p/5025650.html

    5. 通过Handler对象实现下载文件动态更新进度条

    AndroidManifest加入权限声明:

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

    布局:

    <?xml version="1.0" encoding="utf-8"?>
    <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="10dp"
        tools:context="com.studying.network.DownloadActivity">
    
        <ProgressBar
            android:id="@+id/progress_bar"
            style="?android:progressBarStyleHorizontal"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:max="100" />
    
        <Button
            android:id="@+id/download"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            android:text="@string/download" />
    
    </LinearLayout>
    

    Activity:

    public class DownloadActivity extends Activity {
    
        private static final int DOWNLOAD_MESSAGE_CODE = 100001;
        private static final int DOWNLOAD_MESSAGE_FAIL_CODE = 100002;
        private static final String APP_URL = "http://clfile.imooc.com/class/assist/119/1328281/Android%20Studio%20教辅%20.pdf";
        private MyHandler mHandler;
        private ProgressBar mProgressBar;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_download);
    
            findViewById(R.id.download).setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    //开启子线程
                    new Thread(new Runnable() {
                        @Override
                        public void run() {
                            download(APP_URL);
                        }
                    }).start();
                }
            });
            mProgressBar = (ProgressBar) findViewById(R.id.progress_bar);
            mHandler = new MyHandler(this);
        }
    
        private void download(String appUrl) {
            try {
                URL url = new URL(appUrl);
                URLConnection conn = url.openConnection();
    
                InputStream in = conn.getInputStream();
                int contentLength = conn.getContentLength();//获取文件总大小
    
                String downloadPath = Environment.getExternalStorageDirectory() + File.separator + "imooc" + File.separator;
                File file = new File(downloadPath);
                if (!file.exists()) {
                    file.mkdir();
                }
    
                String fileName = downloadPath + "test.pdf";
                File apkFile = new File(fileName);
                if (apkFile.exists()) {
                    apkFile.delete();
                }
    
                int downloadSize = 0;//记录已经下载的大小
                byte[] bytes = new byte[1024];
                int length = 0;
    
                OutputStream out = new FileOutputStream(fileName);
                while ((length = in.read(bytes)) != -1) {
                    out.write(bytes, 0, length);
                    downloadSize += length;
    
                    Message msg = Message.obtain();
                    msg.obj = downloadSize / contentLength * 100;//progress的值为0到100,因此得到的百分数要乘以100
                    msg.what = DOWNLOAD_MESSAGE_CODE;
                    mHandler.sendMessage(msg);
                }
    
                in.close();
                out.close();
    
            } catch (IOException e) {
                notifyDownloadFailed();
                e.printStackTrace();
            }
        }
    
        private void notifyDownloadFailed() {
            Message msg = Message.obtain();
            msg.what = DOWNLOAD_MESSAGE_FAIL_CODE;
            mHandler.sendMessage(msg);
        }
    
        private static class MyHandler extends Handler{
    
            private WeakReference<DownloadActivity> weakReference;
    
            MyHandler(DownloadActivity activity) {
                this.weakReference = new WeakReference<>(activity);//以弱引用的形式传递Activity,避免内存泄漏
            }
    
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                DownloadActivity activity = weakReference.get();
                //消息处理
                switch (msg.what) {
                    case DOWNLOAD_MESSAGE_CODE:
                        activity.mProgressBar.setProgress((Integer) msg.obj);
                        break;
                    case DOWNLOAD_MESSAGE_FAIL_CODE:
                        Toast.makeText(activity, "下载失败!", Toast.LENGTH_SHORT).show();
                        break;
                }
            }
        }
    }
  • 相关阅读:
    16.小程序request请求
    15.小程序接入百度地图获取地理位置
    14. 微信小程序之wxss
    13.小程序视图层的模板
    es6字符串几个方法的理解
    记一次仿京东首页的轮播图效果
    ES6中Promise使用方法
    关于新版VS编辑环境下提示fopen不安全的问题报C4996错误的解决办法
    css布局拓展
    HTML的表单元素
  • 原文地址:https://www.cnblogs.com/joahyau/p/7301546.html
Copyright © 2011-2022 走看看