Android初识多线程

Android多线程

  • 一个Android的应用程序运行在一个独立的进程中,运行在一个独立的虚拟机(dvk)上。 (进程名为包名)

  • Android应用程序开启后,默认开启一个主线程(UI线程)
    Activity,Service,BroadcastReceiver组件运行在主线程中
    Android应用程序退出后,保留空UI线程,可以加快应用程序启动速度

  • 用户不能在UI主线程中做耗时的操作,一旦该操作超过5s,应用程序抛一个ANR异常(Application not respond)。
    如何避免ANR错误?
    将耗时的操作放入子线程中。(耗时的操作包括:长时间的休眠,计数,联网,复杂的运算。)

  • 只有主线程才能操作Widget控件。
    如果在子线程中操作Widget控件,系统抛出CalledFromWrongThreadException异常。

  • 系统为什么要这么做?
    避免出现同步问题。

Handler机制。

  • Goolge为什么设计这套机制?
    主要是为了解决非UI线程中不能更新Widget控件的问题

  • Handler机制剖析
    子线程发送消息给底层的消息队列。
    handler.sendMessage(msg)
    主线程查询消息队列,处理消息对象。
    handlerMessage(msg)
    MessageQueue 消息队列
    负责存储消息对象

  • Looper
    给UI线程安排代码,一个UI线程只能有一个Looper对象,否则多个Looper对象都在UI线程上安排代码,解决冲突就是个大问题。 Looper对象会线性安排在UI线程上执行的代码,它通过一个队列管理各个Handler对象提交的代码。

  • Message消息对象

//从消息池中获取消息对象
Message msg = handler.obtainMessage();
//在消息对象上绑定int类型数据
msg.arg1 = count;
//在消息对象上绑定其它类型数据
msg.setData(Bundle);        //Bundler为数据集(类似于HashMap容器)
Android初识多线程_第1张图片
  • 向消息队列发送消息,1000毫秒后执行Runnable对象中的代码。
myHandler.postDelayed(new Runnable() { 
           @Override 
          public void run() { 
                 // TODO Auto-generated method stub 
                 Log.e("Test", "thread name = "+Thread.currentThread().getName());
           }
}, 1000);

异步任务(AsyncTask)

  • 概念
    封装多线程和Handler机制。给用户提供重写接口的方式,不需要用户手动创建子线程和Handler对象。

  • 异步任务的优点
    Handler模式需要为每一个任务创建一个新的线程,任务完成后通过Handler实例向UI主线程发送消息,完成界面的更新,这种方式对于整个过程的控制比较精细,但是也有缺点,代码臃肿,在多个任务同时执行时,不易对线程进行精确的控制。为了简化操作,Android1.5提供了一个工具类AsyncTask,它是创建异步任务变的更加简单,不再需要编写任务线程和Handler实例就可完成任务。

  • 异步任务的局限性
    多个异步任务不能同时执行,在某个时间内,只能执行一个异步任务。

  • 执行异步任务的步骤:

  1. execute(Params... params),执行一个异步任务,需要我们在代码中调用此方法,触发异步任务的执行。
  2. onPreExecute(),在execute(Params... params)被调用后立即执行,一般用来在执行后台任务前对UI做一些标记。
  3. doInBackground(Params... params),在onPreExecute()完成后立即执行,用于执行较为费时的操作,此方法将接收输入参数和返回计算结果。在执行过程中可以调publishProgress(Progress... values)来更新进度信息。
  4. onProgressUpdate(Progress... values),在调用publishProgress(Progress... values)时,此方法被执行,直接将进度信息更新到UI组件上。
  5. onPostExecute(Result result),当后台操作结束时,此方法将会被调用,计算结果将做为参数传递到此方法中,直接将结果显示到UI组件上。
  • 取消异步任务
/** 
*cancel(true) 取消当前的异步任务,传入的true,表示当中断异步任务时继续已经运行的线程的操作, 
*但是为了线程的安全一般为让它继续设为true 
**/ 
mTask.cancel(true); 
/** 
* 但是重新运行后会发现还是不能起到效果, 
* 注意:这是因为cancel方法只是发出一个请求取消异步任务的信号, 
* 将对应当前的异步任务标记为CANCEL状态,而并不是真正取消线程的执行,
 * 而此时异步任务中的线程仍然在执行并没有结束 
* 所以效果依然是这样的,并且在java中我们是无法直接暴力将一个线程给停止掉
 * 既然我们知道无法去取消一个已经正在运行的线程,但是我们如何去解决这个BUG呢? 
* 在异步任务中还给我们提供一个isCanceled的回调方法,也就是当我已经给当前的异步任务 
* 调用了cancel(true)方法,发出一个请求取消异步任务的信号,那么此时的isCanceled的回调方法 
* 会直接返回一个true,那么我们就可以通过判断当前异步任务isCanceled是否为true,来终止
* 线程中的操作而不是去终止线程,从而达到了界面显示好像线程中的操作被终止了,而实际上 
* 该线程依然在运行
* */
  • 注意
  1. 异步任务对象只能执行一次。
  2. 异步任务对象必须在UI主线程中创建。execute(Params... params)方法必须在UI线程中调用。
  3. 不要手动调用onPreExecute(),doInBackground(Params... params),onProgressUpdate(Progress... values),onPostExecute(Result result)这几个方法。
  4. 不能在doInBackground(Params... params)中更改UI组件的信息。

你可能感兴趣的:(Android初识多线程)