基于移动客户端的软件特别强调实时性,Android程序更是如此,任何一个程序超过5s没有响应,都会被系统强制杀掉。而且Android也不允许在UI线程中进行任何网络操作,否则就会产生NetworkOnMainThreadException 异常。因此,凡是耗时的操作,都不应该直接出现在UI线程中。今天,我通过最简单直观地示例总结下Android开发中最常用的两种处理耗时操作的方法:一个是线程,另一个是异步任务。

首先,看看示例效果,点击Download后,进度条每1秒中增加1%,直到增加到100%。

我将分别用两种方式实现这个功能。

首先,给出 XML 的布局文件:

<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"><Buttonandroid:layout_width="match_parent"android:layout_height="wrap_content"android:layout_margin="10dp"android:text="Download"android:onClick="onClickDownLoad"/><TextViewandroid:id="@+id/TextShow"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginLeft="10dp"android:text="0%"/><ProgressBarandroid:id="@+id/ProgressBar"android:layout_margin="10dp"android:layout_width="match_parent"android:layout_height="30dp"                  style="@android:style/Widget.ProgressBar.Horizontal"/>
</LinearLayout>

(1) 线程(Thread,Runnable)

第一种方法是通过线程的形式来实现,代码如下:

public class DownloadRunnable implements Runnable {private RunnableStateListener mStateListener;private String mURL;public static interface RunnableStateListener {public void onRunnableUpdate(int progress);public void onRunnableComplete(boolean isSuccess);}public DownloadRunnable(RunnableStateListener listener, String url ) {mStateListener = listener;mURL = url;}@Overridepublic void run() {Log.d("DownloadTask", "Begin download, the URL is " + mURL );for( int i=1; i<=100; i++ ) {mStateListener.onRunnableUpdate(i);try {Thread.sleep(500);}catch (InterruptedException e) {         e.printStackTrace();mStateListener.onRunnableComplete(false);return;}}mStateListener.onRunnableComplete(true);}
}

Android/Java中,线程是通过 new Thread(Runnable runnable).start(); 来创建和执行的,所以可以先定义一个类实现 Runnalbe 接口,在 run 函数中完成耗时的操作。本类中,定义RunnableStateListener ,是为了方便线程与外界(调用者)交流,将线程中的任务运行状态传递到外界。

(2) 异步任务(AsyncTask)

另一种方法则是采用异步任务来实现,代码如下:

public class DownloadTask extends AsyncTask<String,Integer,Boolean> {private TaskStateListener mTaskStateListener;public static interface TaskStateListener {public void onTaskUpdate(int progress);public void onTaskComplete(boolean isSuccess);}public DownloadTask(TaskStateListener listener) {mTaskStateListener = listener;}@Overrideprotected Boolean doInBackground(String ... params )Log.d("DownloadTask", "Begin download, the URL is " + params[0] );for( int i=1; i<=100; i++ ) {//会回调onProgressUpdatesuper.publishProgress(i);try {Thread.sleep(500);}catch (InterruptedException e) {         e.printStackTrace();return Boolean.FALSE;}}return Boolean.TRUE;}@Overrideprotected void onProgressUpdate(Integer... values){         mTaskStateListener.onTaskUpdate(values[0]); super.onProgressUpdate(values);}@Overrideprotected void onPostExecute(Boolean result) {mTaskStateListener.onTaskComplete(result);}
}

异步任务与线程的实现方式有很大不同,异步任务主要通过实例化AsyncTask类来实现,该类有三个接口,doInBackground,该函数是任务的主体部分,将耗时的操作可以放在这里;onProgressUpdate是由系统回调的函数,当doInBackground主体中调用了publishProgress后,则会进入onProgressUpdate更新当前任务的状态,因此,在这里可以通过本类定义的TaskStateListener将状态传递给外界(调用者);而onPostExecute则是在doInBackground主体任务return(结束)后由系统回调。

AsyncTask的原型定义如下:AsyncTask<Params, Progress, Result>,有点像C++里的模板,子类可以实例化这三个参数,依次对应 doInBackground 的参数,onProgressUpdate的参数,onPostExecute的返回值。

AsyncTask 通过 new AsyncTask().execute() 来启动,其中 execute 的参数会被传递给 doInBackground 函数。AsyncTask可以通过 getStatus 来获取当前任务的执行状态,通过 cancel来取消。

(3) MainActivity 的实现

MainActivity 的代码如下,我把两种方式的代码都集成在里面了。

public class MainActivity extends Activity implements TaskStateListener,RunnableStateListener {private TextView mProgressShow;private ProgressBar mProgressBar;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);mProgressShow = (TextView)findViewById(R.id.TextShow);mProgressBar  = (ProgressBar)findViewById(R.id.ProgressBar);}public void onClickDownLoad(View v) {//new DownloadTask(this).execute("blog.ticktick.51cto.com");new Thread(new DownloadRunnable(this,"blog.ticktick.51cto.com")).start();}@Overridepublic void onTaskUpdate(int progress) { mProgressShow.setText(progress+"%");mProgressBar.setProgress(progress);}@Overridepublic void onTaskComplete(boolean isSuccess) {if( isSuccess ) {Toast.makeText(this,"Download Complete",Toast.LENGTH_LONG).show();}else {Toast.makeText(this,"Download Failed",Toast.LENGTH_LONG).show();}}@Overridepublic void onRunnableUpdate(final int progress) {this.runOnUiThread(new Runnable() {  @Overridepublic void run() {      mProgressShow.setText(progress+"%");mProgressBar.setProgress(progress);}});      }@Overridepublic void onRunnableComplete(final boolean isSuccess) {this.runOnUiThread(new Runnable() {  @Overridepublic void run() {      if( isSuccess ) {Toast.makeText(MainActivity.this,"Download Complete",Toast.LENGTH_LONG).show();}else {Toast.makeText(MainActivity.this,"Download Failed",Toast.LENGTH_LONG).show();}}});      }
}

这里注意,由线程类回调的onRunnableUpdate和onRunnableComplete函数中,通过this.runOnUiThread的方式在更新UI,而由AsynTask回调的则不需要采用这种方式,因为Android不允许非UI线程改变UI元素,所以必须通过runOnUiThread的方式来更新,而AsynTask则是在内部通过handle收发消息的方式自动切换到了UI线程,所以可以直接更新UI。

关于Android开发中常用的两种耗时操作的处理方式就总结到这儿了,主要通过一个简单的示例程序示范了Runnable和AsynTask的使用方法,工程代码见文章后面的附件。有不清楚的地方,欢迎留言或者来信lujun.hust@gmail.com交流,或者关注我的新浪微博 @卢_俊 获取最新的文章和资讯。

转载于:https://blog.51cto.com/ticktick/1329760

Android开发实践:线程与异步任务相关推荐

  1. android并发命令,Android开发实践:基于命令模式的异步任务线程

    关于Android的异步操作,我在文章<Android开发实践:线程与异步任务>中介绍了两种方法,一种是采用线程,另一种是采用AsyncTask,今天再深入探讨下另一种模型:命令式的异步任 ...

  2. Android开发实践:Java层与Jni层的数组传递

    Android开发中,经常会在Java代码与Jni层之间传递数组(byte[]),一个典型的应用是Java层把需要发送给客户端的数据流传递到Jni层,由Jni层的Socket代码发送出去,当然,Jni ...

  3. Xamarin.Android开发实践(十七)

    Xamarin.Android开发实践(十七) 原文:Xamarin.Android开发实践(十七) Xamarin.Android之定位 一.前言 打开我们手中的应用,可以发现越来越多的应用使用了定 ...

  4. Xamarin.Android开发实践(十四)

    原文:Xamarin.Android开发实践(十四) Xamarin.Android之ListView和Adapter 一.前言 如今不管任何应用都能够看到列表的存在,而本章我们将学习如何使用Xama ...

  5. Xamarin.Android开发实践(一)

    原文:Xamarin.Android开发实践(一) 一.准备工作 1.创建一个空的解决方案,并命名为Phoneword 2.右击解决方案 新建->新建项目 并命名为Phoneword_Droid ...

  6. Android开发之线程池管理ThreadPoolExecutor和Executors.newSingleThreadExecutor()

    在Android开发中网络请求数据在Android4.0以后禁止在主线程请求,那么我们只有新开启线程请求数据了 一般都喜欢简单点这样写: new Thread(new Runnable() {@Ove ...

  7. Android单例模式和线程安全,Android 开发单例模式线程安全与序列化

    前言 单例模式是最常用到的设计模式之一,熟悉设计模式的朋友对单例模式都不会陌生.一般介绍单例模式都只会提到饿汉式和懒汉式这两种实现方式. 看完本章后,你可能会发现项目中的并没有正确的使用创建单例,本文 ...

  8. android开发实践

    # Android 开发最佳实践   从[Futurice](http://www.futurice.com)公司Android开发者中学到的经验. 遵循以下准则,避免重复发明轮子.若您对开发iOS或 ...

  9. Android开发实践:屏幕旋转的处理

    最近开发Android Camera相关的程序,被屏幕旋转搞得头大,一方面得考虑屏幕旋转后布局的变化,另一方面得搞清楚屏幕的旋转方向.角度与Camera的Preview角度的关系.本来通过重载Acti ...

最新文章

  1. 小米note3无线显示电脑连接服务器,小米note3如何连接电脑 小米note3连接电脑没反应怎么办...
  2. swift 组件化_京东商城订单模块基于 Swift 的改造方案与实践
  3. 使用Git,显示一个分支中的所有提交,但不显示其他分支中的所有提交
  4. python容易学吗-python容易学么
  5. 网络:TCP/IP各层的协议
  6. Leetcode-最长回文子串(5)
  7. 仿抖音注册Dialog实现
  8. 分计算iv值_一文读懂评分卡的IV、KS、AUC、GINI指标
  9. checkbox已设置为checked--true-但不勾选问题解决方法(只第一次勾选有效)
  10. Joomla2.5模板简明教程
  11. Spring Boot 打成war包的方法
  12. 部署到gcp_将S/4部署在“大型公有云”上
  13. 边学边写,琐碎记载oracle
  14. 优客365 v2.9版本 后台存在SQL注入
  15. 筋膜悬吊面部提升术后悔死了,几天消肿多久有效果
  16. 总体、样本、样本的抽样分布
  17. 实测:熊猫烧香考验五大杀毒软件
  18. Hugo博客双线部署
  19. 人生的色彩,是五彩斑斓还是单调无味?
  20. python if语句单行_单行的'if'/'for'语句是否使用Python样式好? - python

热门文章

  1. linux命令(56):环境变量:/etc/profile、/etc/bashrc 、~/.profile、~/.bashrc
  2. 在命令行中使用ssh连接远程服务器
  3. day4-软件目录开发规范
  4. Android开发— 2016_最流行的Android组件、工具、框架大全(二)
  5. VS 母版使用配置技巧
  6. hdu 1024(dp)
  7. android查看第三方libs的jar源码
  8. OpenCV学习(17) 细化算法(5)
  9. 【To Do】LeetCode 28. Implement strStr() 和KMP算法
  10. LeetCode 19. Remove Nth Node From End of List