zoukankan      html  css  js  c++  java
  • Android 线程_笔记

    多线程

    一、为什么要使用多线程

    1、提高用户体验或避免ANR

    在事件处理代码中需要使用多线程,响应时间超过5s,即会出现ANR(Application is not responding),并因为响应较慢导致用户体验很差。

    2、ANR详解

         Android的main线程负责处理UI的绘制,为了防止应用程序反应较慢导致系统无法正常运行做如下处理:

    • 当用户输入事件(Activity)在5秒内无法得到响应,那么系统会弹出ANR对话框
    • BroadcastReciever 超过10秒没执行完也会弹出ANR对话

         事件处理的原则:所有可能耗时的操作都放到其他线程去处理。

    3、异步

         应用中有些情况下并不一定需要同步阻塞去等待返回结果,可以通过多线程来实现异步

    例如:某个Activity需要从云端获取一些图片,加载图片比较耗时,这时需要使用异步加载,加载完成一个图片刷新一个

    4、主线程Activity与子线程

    默认启动的第一个Activity成为主线程 由此Activity创建的线程(子线程)无法对主线程控制的内容进行修改 只有UI线程才能更新UI

    二、Handler线程通信

    1、怎样解决跨线程更新UI呢???

    方式1:其他线程委托UI线程更新UI 方式2:通过Handler发送Message给UI线程,令UI线程根据Message消息更新UI 方式3:使用Android提供的AsyncTask  

    1. 其他线程委托UI线程更新UI (此种方式最简单,只适用较简单的情况!)
     Activity.runOnThread(Runnable)    
     View.post(Runnable)   
     View.postDelayed(Runnable,long)  
    
    2. Handler线程间通讯
     >1、 Handler在android里负责发送和处理消息,通过它可以实现其他线程与Main线程之间的消息通讯。  
     >2、Looper负责管理线程的消息队列和消息循环。  
     >3、Message是线程间通讯的消息载体。两个码头之间运输货物,Message充当集装箱的功能,里面可以存放任何你想要传递的消息。    
     >4、MessageQueue是消息队列,先进先出,它的作用是保存有待线程处理的消息。
    
    3、Message:

           通过obtain获取Message对象,利用Android的内存回收机制,提高效率.        Message msg = Message.obtain();    或 Message msg=hanler.obtainMessage();   

    4、Message传递大量数据:

           若线程间通讯的数据比较复杂,比如需要使用键值对来存放大量数据,此时需要使用setData()和getData()方法,用Bundle对象来封装数据,封装好后,使用Handler对象将此Message发送出去.

        Message msg = Message.obtain();
        msg.what = 101;
        Bundle bundle = new Bundle();
        bundle.putInt("number",12);
        bundle.putString("Name","Rice");
        bundle.putString("Hobby","Swimming");
        msg.setData(bundle);
    
    5、Handler:
    两个主要用途:
    1. 将Message或Runnable对象发送给其他线程
    2. 处理来自其他线程的Message.  
    主要方法:

    1、发送Message:sendEmptyMessage(int)、sendMessage(Message)、sendMessageAtTime(Message,long)、sendMessageDelayed(Message,long) 2、处理Message:handleMessage(Message)

    6、Handler Post方法

    在Handler中,关于Post方式的方法有:  

    1. boolean post(Runnable r):把一个Runnable入队到消息队列中,UI线程从消息队列中取出这个对象后,立即执行。  
    2. boolean postAtTime(Runnable r,long uptimeMillis):把一个Runnable入队到消息队列中,UI线程从消息队列中取出这个对象后,在特定的时间执行。  
    3. boolean postDelayed(Runnable r,long delayMillis):把一个Runnable入队到消息队列中,UI线程从消息队列中取出这个对象后,延迟delayMills秒执行   
    4. void removeCallbacks(Runnable r):从消息队列中移除一个Runnable对象。
    7、Handler Message方法

    在Handler中,与Message发送消息相关的方法有:    

    1. Message obtainMessage():获取一个Message对象。  
    2. boolean sendMessage():发送一个Message对象到消息队列中,并在UI线程取到消息后,立即执行。   
    3. boolean sendMessageDelayed():发送一个Message对象到消息队列中,在UI线程取到消息后,延迟执行。  
    4. boolean sendEmptyMessage(int what):发送一个空的Message对象到队列中,并在UI线程取到消息后,立即执行。  
    5. void removeMessage():从消息队列中移除一个未响应的消息  
    6. boolean sendEmptyMessageDelayed(int what,long delayMillis):发送一个空Message到消息队列中,延迟执行。
    

    8、Thread+Handler 缺陷

    • 线程的开销较大,如果每个任务都要创建一个线程,那么程序的效率要低很多。
    • 线程无法管理,匿名线程创建并启动后就不受程序的控制了,如果有很多个请求发送,那么就会启动非常多的线程,系统将不堪重负。
    • 另外,在新线程中更新UI还必须要引入handler,这让代码看上去非常臃肿。

    三、AsyncTask异步任务

    1、AsyncTask

    • AsyncTask的特点是任务在主UI线程之外运行,而回调方法是在主UI线程中,这就有效地避免了使用Handler带来的麻烦。   
    • AsyncTask定义了三种泛型类型                                
      1. Params 启动任务执行的输入参数。
      2. Progress 后台任务执行的百分比。
      3. Result 后台执行任务返回的结果。

    2、使用AsyncTask简化多线程开发

    • AsyncTask专门用于完成非UI线程更新UI的任务      
    • 本质上也是开启新线程执行耗时操作,然后将结果发送给UI线程         
    • 优点:简化代码,减少编写线程间通信代码这一繁琐且易出错的过程
    • 要点:   

      1.  AsyncTask为抽象类,必须先子类化   
      2.  onPreExecute():开始执行前的准备工作   
      3.  doInBackground(Params ...):开始执行后台处理,并调用publishProgress(Progress )方法来更新实时的任务进度  
      4.  onProgressUpdate(Progress  ...):在publishProgress()方法被调用后,UI线程将调用这个方法从而在界面上展示任务的进展情况  
      5.  onPostExecute(Result):执行完成后的操作,传送结果给UI线程
      

    3、要遵守的准则:

    • Task的实例必须在UI 线程中创建     
    • execute方法必须在UI 线程中调用   
    • 不要手动的调用onPreExecute(), onPostExecute(Result),doInBackground(Params...), onProgressUpdate(Progress...)这几个方法,需要在UI线程中实例化这个task来调用。  
    • 该task只能被执行一次,否则多次调用时将会出现异常  
    • doInBackground方法和onPostExecute的参数必须对应,这两个参数在AsyncTask声明的泛型参数列表中指定,第一个为doInBackground接受的参数,第二个为显示进度的参数,第三个为  doInBackground返回和onPostExecute传入的参数。

    4、构造参数解读

    • private class task extends AsyncTask<String, String, String>
    • AsyncTask<>的参数类型由用户设定,这里设为三个String
    • 第一个String代表输入到任务的参数类型,也即是doInBackground()的参数类型,调用execute()方法时传入的参数类型
    • 第二个String代表处理过程中的参数类型,也就是doInBackground()执行过程中的产出参数类型,通过publishProgress()发消息,传递给onProgressUpdate()一般用来更新界面
    • 第三个String代表任务结束的产出类型,也就是doInBackground()的返回值类型,和onPostExecute()的参数类型
  • 相关阅读:
    03_Redis数据类型(List)
    02_Redis数据类型(String、Hash)
    01_Redis基础
    22_AOP_切面——静态切面
    21_AOP_Advice增强2(异常、引介)
    20_AOP_Advice增强1(前置、后置、环绕)
    19_AOP概述
    18_CGLib动态代理
    利用NTP搭建自己的ntp服务
    VM设置BIOS延长时间
  • 原文地址:https://www.cnblogs.com/zhangxiangguo/p/5542550.html
Copyright © 2011-2022 走看看