Handler實現線程之間的通信-下載文件動態更新進度條

来源:http://www.cnblogs.com/joahyau/archive/2017/08/07/7301546.html
-Advertisement-
Play Games

1. 原理 每一個線程對應一個消息隊列MessageQueue,實現線程之間的通信,可通過Handler對象將數據裝進Message中,再將消息加入消息隊列,而後線程會依次處理消息隊列中的消息。 2. Message 初始化:一般使用Message.obtain()方法獲取一個消息對象,該方法會檢查 ...


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;
            }
        }
    }
}

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 示例代碼,關鍵位置做了註釋,請查看代碼: 執行運行代碼,效果為: ...
  • css ...
  • Web前端技術由html、css和javascript三大部分構成,是一個龐大而複雜的技術體系,其複雜程度不低於任何一門後端語言。而我們在學習它的時候往往是先從某一個點切入,然後不斷地接觸和學習新的知識點,因此對於初學者很難理清楚整個體系的脈絡結構。本文將對Web前端知識體系進行簡單的梳理,對應的每 ...
  • 以下是正常請求ajax的格式,其中當後臺介面支持跨域時,dataType需設置成jsonp;當後臺返回格式為json且不支持跨域時,dataType要設置成json; 但是有時候請求狀態為200,卻還是進入error,這時需查看後臺的回調函數名稱是否為預設(callback),如不是則需在參數中加入 ...
  • 這兩天看了看angular4的文檔,發現他和angular1.X的差別真的是太大了,官方給出的那個管理英雄的Demo是一個非常好的入門項目,這裡給出一個管理個人計劃的小項目,從頭至尾一步一步講解如何去實現他,希望對你有所幫助。這篇文章不會講解如何去用angular,這部分東西你可以參考官網,本文講解... ...
  • 一,工程圖。 二,代碼。 ViewController.m #import "ViewController.h" #import "ScanViewController.h" @interface ViewController () @end @implementation ViewControll ...
  • DatePicker日期與時間控制項 一、簡介 二、方法 最日常的使用方法了 日期控制項DatePicker 時間控制項TimePicker 月份從0開始 三、代碼實例 效果圖: 代碼: fry.Activity01 /DatePicherDemo1/res/layout/activity01.xml 四 ...
  • bitmap==null 一、問題介紹 調試找bug的過程出現bitmap==null,而傳過來創建bitmap的byte array有數據, 結果看了函數說明: 果斷知道是那個圖片沒有辦法decode,換了圖片果然就對了 二、收穫 發這篇文章其實是想提醒自己,多去看函數說明,多去看源碼,事半功倍。 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...