zoukankan      html  css  js  c++  java
  • 13、Android的多线程与异步任务

    课程目标:学习Android中异步操作的三大方式

    重点难点:Handler与线程的关系   Handler消息队列的实现

    考核目标:

    使用Handler是异步的,它会建立新线程么? no

    Handler是在主线程内么?

    Handler的post 和 sentMessage方法,使用的是一个队列还是两个?

    子线程中建立一个handler,然后sendMessage会怎样?

    子线程建立handler , 构造的时候传入主线程的,Looper?  Yes   

     

     

     

    一、回顾Java多线程基础

     Runnable

    Thread

    ThreadPool

    ScheduleExecutor

    线程同步:Synchronized\Lock\Semaphore。

     

    二、在Android中使用多线程

    1>为何使用多线程

    对于耗时操作,我们应该放到非主线程中运行,从而避免阻塞主线程。

    为了保证良好的用户体验,建议对超过50ms的操作,都使用线程处理。

    aIO操作(文件操作、网络操作、数据库操作...).

    b复杂运算.

    c定时操作.

    2>如何使用多线程或异步操作

     

    3>多线程和界面交互

      在Android源代码中,我们可以看到Android UI的代码是没有做同步处理的,也就是说,他们不是线程安全的。

      那么,Android是如何保证UI的正常运行的?

      当我们在非主线程操作UI时,Android会抛出异常,所以我们应当确保UI操作应该在主线程运行。

    a>Activity.runOnUiThread(Runnable)

    b>View.post(Runnable) ; View.postDelay(Runnable , long)

    c>Handler

    d>AsyncTask

    4>Android UI 主线程简单原则

    不要Block UI Thread

    不要在UI线程外直接操作UI

     

    三、使用Handler-异步时或不可缺的组件

    问题:使用多线程时遇到的问题。

    我想和UI进行交互,但每次都创建Runnable看起来很别扭,而且代码很难管理。

    我的程序中需要不断的加载更新的数据,我该怎么确保数据的正确性?

    用户快速的点击按钮,我的程序无法有足够快的响应,该怎么办?

    问题:什么是Handler及其作用。

    Hanlder作用:

    1)执行计划任务,你可以再预定的实现执行某些任务,可以模拟定时器

    2)线程间通信。在Android的应用启动时,会创建一个主线程,主线程会创建一个消息队列来处理各种消息。当你创建子线程时,你可以再你的子线程中拿到父线程中创建的Handler对象,就可以通过该对象向父线程的消息队列发送消息了。由于Android要求在UI线程中更新界面,因此,可以通过该方法在其它线程中更新界面。

    3) 确保操作始终在某个特定的线程中运行。例如当我们从数据库加载数据时,除了程序启动时需要加载外,每当我们收到数据改变的通知时也需要重新加载。为了确保数据的有效性(始终使用最后一次查询时得到的数据),并减少不必要的查询操作,我们应当确保他们在同一个线程中运行。

     

     角色描述

    1.Looper:(相当于隧道) 一个线程可以产生一个Looper 对象,由它来管理此线程里的Message Queue( 车队,消息隧道)

    2.Handler: 你可以构造Handler 对象来与Looper 沟通,以便push 新消息到Message Queue 里;或者接收Looper( 从Message Queue 取出) 所送来的消息。

    3. Message Queue( 消息队列): 用来存放线程放入的消息。

    4 .线程:UI thread 通常就是main thread ,而Android 启动程序时会替它建立一个Message Queue

     

    每一个线程里可含有一个Looper 对象以及一个MessageQueue 数据结构。在你的应用程序里,可以定义Handler 的子类别来接收Looper 所送出的消息。

    线程必须调用Looper.loop()让其开始消息处理过程,且此时该线程无法执行其他代码。

    【误区: Handler 一定是在主线程么?】

     

     问题:让我们通过代码来了解问题。

    1>Handler实例与消息处理是关联的,发送和接收要匹配

    2>只能依附在HandlerThread

    3>可以通过设置Looper来选择其依附的线程

    4>所有操作都是在用一个线程中

    5>removeMessage只能移除队列中的Message

     

    四、使用AsyncTask快速实现异步任务

    1>什么是AsyncTask

    Android为了降低异步操作开发难度,结合Handler和线程池,提供了AsyncTask。AsyncTask就是一个封装过的后台任务类,顾名思义就是异步任务。他具有可以在后台执行耗时操作,同时可以讲执行进度与UI进行同步的优点。

    2>如何使用AsyncTask

    AsyncTask定义了三种泛型类型 Params,Progress和Result

    Params 启动任务执行的输入参数,比如HTTP请求的URL

    Progress 后台任务执行的百分比。

    Result 后台执行任务最终返回的结果,比如String

    AsyncTask方法

    doInBackground(Params…) 后台执行,比较耗时的操作都可以放在这里。注意这里不能直接操作UI。此方法在后台线程执行,完成任务的主要工作,通常需要较长的时间。在执行过程中可以调用publicProgress(Progress…)来更新任务的进度。

    onPostExecute(Result)  相当于Handler 处理UI的方式,在这里面可以使用在doInBackground 得到的结果处理操作UI此方法在主线程执行,任务执行的结果作为此方法的参数返回

    可选方法:

    onProgressUpdate(Progress…)   可以使用进度条增加用户体验度。 此方法在主线程执行,用于显示任务执行的进度。

    onPreExecute()        这里是最终用户调用Excute时的接口,当任务执行之前开始调用此方法,可以在这里显示进度对话框。

    onCancelled()             用户调用取消时,要做的操作

    AsyncTask三个状态:pending , running , finished

     【规则】

    AsyncTask必须在主线程创建;

    execute() 只能调用一次;

    execute() 必须在主线程执行;

    不要自己调用onPreExecute(), onPostExecute(), doInBackground(), onProgressUpdate();

    3>分析AsyncTask的实现原理

    4>分析AsyncTask和Handler谁更消耗资源

    如何分析一个进程占用内存的大小。

    5>探讨什么使用使用AsyncTask, 什么时候使用Handler

    任务可以被中止,并需要不断和使用时AsyncTask;

    任务需要被多次重复执行,且和UI交互少时用Handler;

     

    、检测程序中是否有需要使用多线程的地方

    1>StrictMode.ThreadPolicy

    detectDiskReads()

    detectDiskWrites()

    detectNetwork()

    2>检测后的处理方法

    penaltyLog()

    penaltyDeath()

    penaltyDialog()

    penaltyDropBox()

    penaltyFlashScreen()

  • 相关阅读:
    创建一个简单的图片服务器
    spring-boot系列:初试spring-boot
    java的动态代理机制
    jedis连接池详解(Redis)
    使用logback.xml配置来实现日志文件输出
    redis在mac上的安装
    理解RESTful架构
    分布式应用框架Akka快速入门
    [Java基础]Java通配符
    Mac vim iterm2配色方案
  • 原文地址:https://www.cnblogs.com/androidsj/p/3972616.html
Copyright © 2011-2022 走看看