Android多线程(一)
2015-10-06 14:18
447 查看
在Android应用的开发过程中,我们不可避免的要使用多线程,获取服务器数据、下载网络数据、遍历文件目录查找特定文件等等耗时的工作都离不开线程的知识。Android继承了Java的多线程体系,同时又实现了许多更加简易的API来操作线程。通过这些API,我们可以方便快捷的实现线程的创建、线程间的交互。我打算记下最近自己学习Android多线程机制时的学习笔记,一来可以供以后翻阅查看,二来为那些正疑惑与此的朋友提供一条解决问题的途径。
先大致说一下我想写的内容:
一、AsyncTask
二、Thread 与 Handler
三、HandlerThread
全部内容分为3篇Bolg。
下面正式开始第一部分吧!
[b]一、AsyncTask[/b]
(0)参考文档:http://developer.android.com/reference/android/os/AsyncTask.html
(1)简单介绍:
AsyncTask这是一个很便捷的关于线程的API,它将比较耗时(几秒)的工作放在非UI线程中运行,然后将结果的展示放在UI线程中。整个过程不涉及到任何关于Thread、Handler及Message等的处理。
先来说说AsyncTask的构造吧,它接收3个泛型参数,分别代表了后台工作的传入参数类型、进度的参数类型、结果的参数类型。每一个的具体含义会在接下来的AsyncTask的执行过程中讲到。要想使用AsyncTask就必须拓展为它的子类同时指定3个泛型参数,然后在子类的中重写几个重要的方法。下面就AsyncTask的执行过程来写。
(2)AsyncTask的执行过程:
AsyncTask中的回调方法有:
onPreExecute(),UI线程中执行,一般用来处理执行异步任务前的准备工作,比如弹出一个进度条,展现一个对话框告知用户正在执行一项任务。
doInBackground(Params...),在非UI线程中执行,这里是异步任务的核心,所有需要耗时的工作全在这里执行,因为不是在UI线程中,因此不会存在阻塞UI线程的危险,不会引发ANR错误。
onProgressUpdate(Progress...),在UI 线程中执行,一般用来更新任务执行的进度,它的调用时在publishProgress(Progress...)调用之后接着被调用的,我们可以在doInBackground(Params...)中多次调用publishProgress(Progress...)来告知用户任务的执行状态。
onPostExecute(Result),在UI线程中执行,任务完成后(doInBackground(Params...)执行结束)且任务没被取消时,会执行该方法,用来处理异步任务得到的结果。
onCancelled(Result),在UI线程中执行,当任务以柔和的方式结束(AsyncTask.cancel(false))这个方法会取代onPostExecute(Result)得以执行(当然这里也要看程序的执行逻辑,有没有在doInBackground(Params...)中检测任务是否被取消)
关于泛型参数:
三个泛型参数分别是:Params,Progress,Result。在上面的回调方法接受中我们可以看到它们分别所处那个方法,Params是启动异步任务时传入的参数,比如启动异步任务从网上下载一张图片传入图片的URL地址。Progress是进度参数类型,调用publishProgress(Progress...)时的参数需和Progress类型相容。比如用一个整数去描述进度,Progress及时Integer。Result是结果参数类型,异步任务完成后,如需返回一个结果,那么这个结果的类型就是Result类型。特别地,可以用Void去代替任何一个或多个泛型参数,这样做就以为着不需要参数。
(3)一个简单的例子:
话说百闻不如一见,下面我就用一个极简单的例子说明AsyncTask的使用过程。先说我要干啥,我用一个异步任务来更新一个进度条(简单吧!粗暴吧!颤抖吧,地球人!O(∩_∩)O)
注:示例没什么格式,强迫症患者见谅!!
先给出布局:
下面是AsyncTask的逻辑代码:
LogCat日志:
执行完毕,没有中途取消任务:
10-06 13:55:05.871 6737-6737/comfallblank.github.asynctasktest D/MyTask: onPreExecute
10-06 13:55:05.891 6737-13040/comfallblank.github.asynctasktest D/MyTask: doInBackground
10-06 13:55:06.922 6737-6737/comfallblank.github.asynctasktest D/MyTask: onProgressUpdate
10-06 13:55:07.923 6737-6737/comfallblank.github.asynctasktest D/MyTask: onProgressUpdate
10-06 13:55:08.914 6737-6737/comfallblank.github.asynctasktest D/MyTask: onProgressUpdate
10-06 13:55:09.925 6737-6737/comfallblank.github.asynctasktest D/MyTask: onProgressUpdate
10-06 13:55:09.975 6737-6753/comfallblank.github.asynctasktest W/art: Suspending all threads took: 18.035ms
10-06 13:55:10.926 6737-6737/comfallblank.github.asynctasktest D/MyTask: onProgressUpdate
10-06 13:55:11.937 6737-6737/comfallblank.github.asynctasktest D/MyTask: onProgressUpdate
10-06 13:55:12.938 6737-6737/comfallblank.github.asynctasktest D/MyTask: onProgressUpdate
10-06 13:55:13.939 6737-6737/comfallblank.github.asynctasktest D/MyTask: onProgressUpdate
10-06 13:55:14.950 6737-6737/comfallblank.github.asynctasktest D/MyTask: onProgressUpdate
10-06 13:55:15.951 6737-6737/comfallblank.github.asynctasktest D/MyTask: onProgressUpdate
10-06 13:55:15.971 6737-6737/comfallblank.github.asynctasktest D/MyTask: Task executed
10-06 13:55:15.971 6737-6737/comfallblank.github.asynctasktest D/MyTask: onPostExecute
中途取消任务:
10-06 13:56:10.644 14129-14129/comfallblank.github.asynctasktest D/MyTask: onPreExecute
10-06 13:56:10.654 14129-14302/comfallblank.github.asynctasktest D/MyTask: doInBackground
10-06 13:56:11.665 14129-14129/comfallblank.github.asynctasktest D/MyTask: onProgressUpdate
10-06 13:56:12.666 14129-14129/comfallblank.github.asynctasktest D/MyTask: onProgressUpdate
10-06 13:56:13.667 14129-14129/comfallblank.github.asynctasktest D/MyTask: onProgressUpdate
10-06 13:56:14.668 14129-14129/comfallblank.github.asynctasktest D/MyTask: onProgressUpdate
10-06 13:56:15.689 14129-14129/comfallblank.github.asynctasktest D/MyTask: Task cancelled
10-06 13:56:15.689 14129-14129/comfallblank.github.asynctasktest D/MyTask: onCancelled
关于AsyncTask的一些注意事项:
(1)AsyncTask对象只能使用一次,也就是说一个对象执行完毕或者中途被cancel后,不能再次调用execute().
(2)AsyncTask.execute()只能在主线程中调用。
(3)AsyncTask不能处理并发,多个AsyncTask也是有执行顺序的,且同一个应用的所有AsyncTask都是在同一进程中执行,按照队列排序依次执行。
(4)AsyncTask只能处理那些耗时不是特别长的任务,对于需要长时间执行的任务最好自己实现Thread。
AsyncTask很方便,它屏蔽了所有Thread、Handler、Looper、Message及Messagequene的细节,这或许就是封装的魅力吧!但当你真正明白了Android的线程通讯之后你就会明白那些良好设计带来的美感。
以此抛砖引玉!可能多有偏颇,望多交流!
先大致说一下我想写的内容:
一、AsyncTask
二、Thread 与 Handler
三、HandlerThread
全部内容分为3篇Bolg。
下面正式开始第一部分吧!
[b]一、AsyncTask[/b]
(0)参考文档:http://developer.android.com/reference/android/os/AsyncTask.html
(1)简单介绍:
AsyncTask这是一个很便捷的关于线程的API,它将比较耗时(几秒)的工作放在非UI线程中运行,然后将结果的展示放在UI线程中。整个过程不涉及到任何关于Thread、Handler及Message等的处理。
先来说说AsyncTask的构造吧,它接收3个泛型参数,分别代表了后台工作的传入参数类型、进度的参数类型、结果的参数类型。每一个的具体含义会在接下来的AsyncTask的执行过程中讲到。要想使用AsyncTask就必须拓展为它的子类同时指定3个泛型参数,然后在子类的中重写几个重要的方法。下面就AsyncTask的执行过程来写。
(2)AsyncTask的执行过程:
AsyncTask中的回调方法有:
onPreExecute(),UI线程中执行,一般用来处理执行异步任务前的准备工作,比如弹出一个进度条,展现一个对话框告知用户正在执行一项任务。
doInBackground(Params...),在非UI线程中执行,这里是异步任务的核心,所有需要耗时的工作全在这里执行,因为不是在UI线程中,因此不会存在阻塞UI线程的危险,不会引发ANR错误。
onProgressUpdate(Progress...),在UI 线程中执行,一般用来更新任务执行的进度,它的调用时在publishProgress(Progress...)调用之后接着被调用的,我们可以在doInBackground(Params...)中多次调用publishProgress(Progress...)来告知用户任务的执行状态。
onPostExecute(Result),在UI线程中执行,任务完成后(doInBackground(Params...)执行结束)且任务没被取消时,会执行该方法,用来处理异步任务得到的结果。
onCancelled(Result),在UI线程中执行,当任务以柔和的方式结束(AsyncTask.cancel(false))这个方法会取代onPostExecute(Result)得以执行(当然这里也要看程序的执行逻辑,有没有在doInBackground(Params...)中检测任务是否被取消)
关于泛型参数:
三个泛型参数分别是:Params,Progress,Result。在上面的回调方法接受中我们可以看到它们分别所处那个方法,Params是启动异步任务时传入的参数,比如启动异步任务从网上下载一张图片传入图片的URL地址。Progress是进度参数类型,调用publishProgress(Progress...)时的参数需和Progress类型相容。比如用一个整数去描述进度,Progress及时Integer。Result是结果参数类型,异步任务完成后,如需返回一个结果,那么这个结果的类型就是Result类型。特别地,可以用Void去代替任何一个或多个泛型参数,这样做就以为着不需要参数。
(3)一个简单的例子:
话说百闻不如一见,下面我就用一个极简单的例子说明AsyncTask的使用过程。先说我要干啥,我用一个异步任务来更新一个进度条(简单吧!粗暴吧!颤抖吧,地球人!O(∩_∩)O)
注:示例没什么格式,强迫症患者见谅!!
先给出布局:
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_margin="15dp"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerHorizontal="true" android:text="AsyncTask示例" android:textSize="30sp"/> <ProgressBar android:id="@+id/progress" style="@android:style/Widget.ProgressBar.Horizontal" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_centerInParent="true"/> <Button android:id="@+id/cancel" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:text="cancel"/> <Button android:id="@+id/start" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_above="@+id/cancel" android:text="start"/> </RelativeLayout>
下面是AsyncTask的逻辑代码:
package comfallblank.github.asynctasktest; import android.os.AsyncTask; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.ProgressBar; public class MainActivity extends AppCompatActivity { private ProgressBar mProgressBar; private Button mStartButton; private Button mCancelButton; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mProgressBar = (ProgressBar) findViewById(R.id.progress); //设置ProgressBar暂时不可见,一会在异步任务的中显示它。 mProgressBar.setVisibility(View.GONE); final MyTask myTask = new MyTask(); mStartButton = (Button) findViewById(R.id.start); mStartButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { myTask.execute(); } }); mCancelButton = (Button) findViewById(R.id.cancel); mCancelButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { myTask.cancel(false); } }); } private class MyTask extends AsyncTask<Void,Integer,String>{ private static final String TAG = "MyTask"; @Override protected void onPreExecute() { super.onPreExecute(); //准备工作,显示进度条 mProgressBar.setVisibility(View.VISIBLE); //打印日志,查看执行路径,下同 Log.d(TAG,"onPreExecute"); } @Override protected String doInBackground(Void... voids) { Log.d(TAG,"doInBackground"); //每1s对进度条更新10% synchronized (this){ for (int i = 1;i<=10;i++){ try { Thread.sleep(1000*1); publishProgress(i*10); if (isCancelled()){ return "Task cancelled"; } } catch (InterruptedException e) { e.printStackTrace(); } } } return "Task executed"; } @Override protected void onProgressUpdate(Integer... values) { super.onProgressUpdate(values); mProgressBar.setProgress(values[0]); Log.d(TAG,"onProgressUpdate"); } @Override protected void onPostExecute(String s) { super.onPostExecute(s); Log.d(TAG, s); Log.d(TAG,"onPostExecute"); } @Override protected void onCancelled(String s) { super.onCancelled(s); Log.d(TAG, s); Log.d(TAG, "onCancelled"); } } }
LogCat日志:
执行完毕,没有中途取消任务:
10-06 13:55:05.871 6737-6737/comfallblank.github.asynctasktest D/MyTask: onPreExecute
10-06 13:55:05.891 6737-13040/comfallblank.github.asynctasktest D/MyTask: doInBackground
10-06 13:55:06.922 6737-6737/comfallblank.github.asynctasktest D/MyTask: onProgressUpdate
10-06 13:55:07.923 6737-6737/comfallblank.github.asynctasktest D/MyTask: onProgressUpdate
10-06 13:55:08.914 6737-6737/comfallblank.github.asynctasktest D/MyTask: onProgressUpdate
10-06 13:55:09.925 6737-6737/comfallblank.github.asynctasktest D/MyTask: onProgressUpdate
10-06 13:55:09.975 6737-6753/comfallblank.github.asynctasktest W/art: Suspending all threads took: 18.035ms
10-06 13:55:10.926 6737-6737/comfallblank.github.asynctasktest D/MyTask: onProgressUpdate
10-06 13:55:11.937 6737-6737/comfallblank.github.asynctasktest D/MyTask: onProgressUpdate
10-06 13:55:12.938 6737-6737/comfallblank.github.asynctasktest D/MyTask: onProgressUpdate
10-06 13:55:13.939 6737-6737/comfallblank.github.asynctasktest D/MyTask: onProgressUpdate
10-06 13:55:14.950 6737-6737/comfallblank.github.asynctasktest D/MyTask: onProgressUpdate
10-06 13:55:15.951 6737-6737/comfallblank.github.asynctasktest D/MyTask: onProgressUpdate
10-06 13:55:15.971 6737-6737/comfallblank.github.asynctasktest D/MyTask: Task executed
10-06 13:55:15.971 6737-6737/comfallblank.github.asynctasktest D/MyTask: onPostExecute
中途取消任务:
10-06 13:56:10.644 14129-14129/comfallblank.github.asynctasktest D/MyTask: onPreExecute
10-06 13:56:10.654 14129-14302/comfallblank.github.asynctasktest D/MyTask: doInBackground
10-06 13:56:11.665 14129-14129/comfallblank.github.asynctasktest D/MyTask: onProgressUpdate
10-06 13:56:12.666 14129-14129/comfallblank.github.asynctasktest D/MyTask: onProgressUpdate
10-06 13:56:13.667 14129-14129/comfallblank.github.asynctasktest D/MyTask: onProgressUpdate
10-06 13:56:14.668 14129-14129/comfallblank.github.asynctasktest D/MyTask: onProgressUpdate
10-06 13:56:15.689 14129-14129/comfallblank.github.asynctasktest D/MyTask: Task cancelled
10-06 13:56:15.689 14129-14129/comfallblank.github.asynctasktest D/MyTask: onCancelled
关于AsyncTask的一些注意事项:
(1)AsyncTask对象只能使用一次,也就是说一个对象执行完毕或者中途被cancel后,不能再次调用execute().
(2)AsyncTask.execute()只能在主线程中调用。
(3)AsyncTask不能处理并发,多个AsyncTask也是有执行顺序的,且同一个应用的所有AsyncTask都是在同一进程中执行,按照队列排序依次执行。
(4)AsyncTask只能处理那些耗时不是特别长的任务,对于需要长时间执行的任务最好自己实现Thread。
AsyncTask很方便,它屏蔽了所有Thread、Handler、Looper、Message及Messagequene的细节,这或许就是封装的魅力吧!但当你真正明白了Android的线程通讯之后你就会明白那些良好设计带来的美感。
以此抛砖引玉!可能多有偏颇,望多交流!
相关文章推荐
- Android Material Design: NavigationView抽屉导航菜单
- 10.6 CheckButtonTest工程
- [Android基础]读写xml、json格式的数据
- Android Chronometer实现时分秒的显示
- Android New package not yet registered with the system 错误解决方法和邪恶的360
- Android,Java开发不能不知道的误区盲点
- Android开发艺术探索读书笔记(三)
- Android实现获取签名及公钥的方法
- Android Material Design : CollapsingToolbarLayout使用简介
- android---(PopupWindows、Notification)
- android电源信息查看(电量、温度、电压)实例代码
- 文章标题
- Android调用堆栈跟踪实例分析
- Android 在ScorllView中ListView和GridView冲突解决方案
- Android XUtils框架学习及注意事项
- java(android)客户端post方式上传多图片至服务器
- Activity四种启动模式
- androidstudio 查看数字签名
- java.lang.ClassCastException:java.lang.ClassCastException: android.view.AbsSavedState$1..解决方法
- Java super关键字(android中常见)