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


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



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


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


                                                                                                                                                                                                                                                              


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


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


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


更多相关文章

  1. Android中子线程真的不能更新UI吗?
  2. Android中Handler的简析
  3. Android中的Looper类&Handler &Message
  4. Android中 AsyncTask的使用
  5. android的5种数据存储方式
  6. android线程间通信之handler
  7. Android(安卓)Handler Looper
  8. Android简明开发教程十九:线程 Bezier曲线
  9. Android之网络请求5————OkHttp源码2:发送请求

随机推荐

  1. Android使edittext弹出的软键盘位于输入
  2. 手动编译源码,打造自己的增量更新。
  3. 去掉WebView中的白色背景
  4. Android中点击按钮后隐藏输入法
  5. 删除Android(安卓)Studio中的工作空间(pro
  6. Android添加ButterKnife时报错Error:(2,
  7. 编译android源码
  8. Android事件总线 浅谈 EventBus
  9. 2018 Android(安卓)框架汇总(转)
  10. Android:如何显示网络图片