Handler实现线程之间的通信下载文件动态更新进度条

所属分类: 软件编程 / Android 阅读数: 25
收藏 0 赞 0 分享

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()的区别:https://www.jb51.net/article/120624.htm

4. 内存泄漏

https://www.jb51.net/article/120627.htm

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

以上所述是小编给大家介绍的Handler实现线程之间的通信下载文件动态更新进度条,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对脚本之家网站的支持!

更多精彩内容其他人还在看

Android中加入名片扫描功能实例代码

这篇文章主要介绍了Android中加入名片扫描功能实例代码的相关资料,需要的朋友可以参考下
收藏 0 赞 0 分享

Android仿微信发表说说实现拍照、多图上传功能

这篇文章主要为大家详细介绍了Android仿微信发表说说实现拍照、多图上传功能,使用Retrofit2.0技术,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
收藏 0 赞 0 分享

设置Android系统永不锁屏永不休眠的方法

在进行Android系统开发的时候,有些特定的情况需要设置系统永不锁屏,永不休眠。本篇文章给大家介绍Android 永不锁屏,开机不锁屏,删除设置中休眠时间选项,需要的朋友一起学习吧
收藏 0 赞 0 分享

Android Retrofit 2.0框架上传图片解决方案

这篇文章主要介绍了Android Retrofit 2.0框架上传一张与多张图片解决方案,感兴趣的小伙伴们可以参考一下
收藏 0 赞 0 分享

Android自定义等待对话框

这篇文章主要为大家详细介绍了Android自定义等待对话框的实现方法,感兴趣的小伙伴们可以参考一下
收藏 0 赞 0 分享

Android中Window添加View的底层原理

这篇文章主要介绍了Android中Window添加View的底层原理,需要的朋友可以参考下
收藏 0 赞 0 分享

Android调用系统默认浏览器访问的方法

这篇文章主要介绍了Android调用系统默认浏览器访问的方法的相关资料,需要的朋友可以参考下
收藏 0 赞 0 分享

Android开发退出程序的方法汇总

Android程序有很多Activity,比如说主窗口A,调用了子窗口B,子窗口B又调用子窗口C,back返回子窗口B后,在B中如何关闭整个Android应用程序呢? 下面脚本之家小编就给大家介绍android开发退出程序的几种方法,感兴趣的朋友参考下吧
收藏 0 赞 0 分享

Android程序开发中单选按钮(RadioGroup)的使用详解

在android程序开发中,无论是单选按钮还是多选按钮都非常的常见,接下来通过本文给大家介绍Android程序开发中单选按钮(RadioGroup)的使用,需要的朋友参考下吧
收藏 0 赞 0 分享

Android实现仿网易今日头条等自定义频道listview 或者grideview等item上移到另一个view中

这篇文章主要介绍了Android实现仿网易今日头条等自定义频道listview 或者grideview等item上移到另一个view中 的相关资料,需要的朋友可以参考下
收藏 0 赞 0 分享
查看更多