android 多线程异步,Android开发实践:线程与异步任务

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

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

ef9a71d05b3906b92ca4a324e6fe9c32.png

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

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

xmlns:tools="http://schemas.android.com/tools"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:orientation="vertical">

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:layout_margin="10dp"

android:text="Download"

android:onClick="onClickDownLoad"/>

android:id="@+id/TextShow"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:layout_marginLeft="10dp"

android:text="0%"/>

android:id="@+id/ProgressBar"

android:layout_margin="10dp"

android:layout_width="match_parent"

android:layout_height="30dp"

style="@android:style/Widget.ProgressBar.Horizontal"/>

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

}

@Override

public 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 {

private TaskStateListener mTaskStateListener;

public static interface TaskStateListener {

public void onTaskUpdate(int progress);

public void onTaskComplete(boolean isSuccess);

}

public DownloadTask(TaskStateListener listener) {

mTaskStateListener = listener;

}

@Override

protected Boolean doInBackground(String ... params )

Log.d("DownloadTask", "Begin download, the URL is " + params[0] );

for( int i=1; i<=100; i++ ) {

//会回调onProgressUpdate

super.publishProgress(i);

try {

Thread.sleep(500);

}

catch (InterruptedException e) {

e.printStackTrace();

return Boolean.FALSE;

}

}

return Boolean.TRUE;

}

@Override

protected void onProgressUpdate(Integer... values)

{

mTaskStateListener.onTaskUpdate(values[0]);

super.onProgressUpdate(values);

}

@Override

protected void onPostExecute(Boolean result) {

mTaskStateListener.onTaskComplete(result);

}

}

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

AsyncTask的原型定义如下:AsyncTask,有点像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;

@Override

protected 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();

}

@Override

public void onTaskUpdate(int progress) {

mProgressShow.setText(progress+"%");

mProgressBar.setProgress(progress);

}

@Override

public 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();

}

}

@Override

public void onRunnableUpdate(final int progress) {

this.runOnUiThread(new Runnable() {

@Override

public void run() {

mProgressShow.setText(progress+"%");

mProgressBar.setProgress(progress);

}

});

}

@Override

public void onRunnableComplete(final boolean isSuccess) {

this.runOnUiThread(new Runnable() {

@Override

public 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交流,或者关注我的新浪微博 @卢_俊 获取最新的文章和资讯。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值