Android初识多线程

作者: _执_念__ | 来源:发表于2017-10-13 16:41 被阅读26次

    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容器)
    
    • 向消息队列发送消息,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初识多线程

        本文链接:https://www.haomeiwen.com/subject/mdgzyxtx.html