美文网首页
Android多线程和异步任务详解

Android多线程和异步任务详解

作者: WuJiaJun | 来源:发表于2017-08-15 03:30 被阅读0次

    Android开发中使用多线程的原因

    • 避免ANR(Application is not responding)
    • 实现异步,比如从云端获取图片比较费时,不应该使用同步阻塞获取结果,使用异步加载完成一个刷新一个
    • 多任务,比如多线程下载

    Android事件处理机制

    在Android中事件处理的原则是:耗时的操作放到其他线程中处理,Main线程中处理不太耗时的操作,否则事件在5秒内无法得到响应就会出现ANR现象,在Main线程中一般是处理UI,处理Activity事件(OnCreat()等)和事件处理方法(OnClick()等)。

    同步和异步的理解

    有些事件必须使用同步比如用户的注册,需要得到结果后才能进行下面的操作,有些事件需要异步,比如微博的点赞,只需要点赞完成后提示我一下就行了,没必要在与服务器沟通的过程中采用同步处理不可以干其他的事情。

    Java中多线程的创建

    通过继承Thread类

    Thread类的本质是一个实现了Runnable接口的类,继承Thread类,复写run()方法,最后在通过.start()调用。

    通过接口Runnable

    Runnable的好处是接口比继承更自由,新建对象后实例一个Thread对象将Runnable传入并调用.start(),如果多个Thread对象传入了同一个Runnable它们将共享数据,比如这个卖火车票的例子。

    package info.wujiajun.threadlearning;
    
    import android.support.v7.app.AppCompatActivity;
    import android.os.Bundle;
    import android.view.View;
    
    public class MainActivity extends AppCompatActivity {
    
        @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
    
    public void btnOnClickByThread(View view){
        ThreadText text1 = new ThreadText();
        ThreadText text2 = new ThreadText();
        text1.start();
        text2.start();
    }
    public void btnOnClickByRunnable(View view){
        RunnableText text1 = new RunnableText();
        RunnableText text2 = new RunnableText();
        Thread t1 = new Thread(text1);
        Thread t2 = new Thread(text2);
        t1.start();
        t2.start();
    }
    public void saleTicket(View view){
        SaleTicket text = new SaleTicket();
        Thread t1 = new Thread(text);
        Thread t2 = new Thread(text);
        t1.start();
        t2.start();
    }
    

    SaleTicket.java

    package info.wujiajun.threadlearning;
    
    import android.util.Log;
    
    /**
     * Email:amojury@outlook.com
     * Github:https://github.com/amojury
     * Created by Jun on 2017/7/27.
     */
    
    public class SaleTicket implements Runnable {
        private int ticket = 20;
        @Override
        public void run() {
            while (true){
                if(ticket > 0){
                    Log.d("TAG",Thread.currentThread().getName()+"卖出了第"+(20-ticket+1)+"张票");
                    ticket--;
                    try {
                        Thread.sleep(2000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                else
                    break;
            }
    
        }
    
    }
    

    线程池的应用

    new Thread的弊端

    • 性能差
    • 缺乏统一管理,无序竞争
    • 无法定时定期执行

    线程池

    Java通过Executors提供了四种线程池

    • newCachedThreadPool 可缓存线程池,回收闲置线程
    • newFixedThreadPool 定长线程池,有最大并发数
    • newScheduledThreadPool 可定时定长线程池
    • newSingleThreadExecutor 制定顺序单线程池

    实现多线程之间的通讯

    Android线程通讯原理

    原理图原理图

    Handle(send方法)

    实现两秒后改变button上的文字


    public class MainActivity extends AppCompatActivity {
    @BindView(R.id.btnHelloWorld)
    Button btnHelloWorld;
    
    private Handler mHandler = new Handler(){
        @Override
        public void handleMessage(Message msg) {  //回调方法,复写handleMessage,处理要放在主线程的事情
            if(msg.what == 1)
                btnHelloWorld.setText("Not HelloWorld");
        }
    };
    
    
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ButterKnife.bind(this);
    }
    
    
    @OnClick(R.id.btnHelloWorld)
    public void onViewClicked() {
        new Thread(new Runnable() {   //开启新线程
            @Override
            public void run() {
                try {
                    Thread.sleep(2000);  //模拟网络请求
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                mHandler.sendEmptyMessage(1);  //使用send方法发送一个空消息,标识是1
    
            }
        }).start();
    }
    }
    

    send的一些方法

    • sendEmptyMessage(int)
    • sendMessage(Message)
    • sendMessageAtTime(Message,long)
    • sendMessageDelayer(Message,long)

    Handle(post方法)

    post方法允许你排列一个Runnable对象在主线程中

    • post(Runnable)
    • postAtTime(Runnable,long)
    • postDelayer(Runnabld)

    三种更新UI的方法

    • post
    • View.post()
    • RunOnUiThread()

    AsyncTask类(可以在子线程和UI线程中跳转)

    解决使用Handle较为繁琐
    AsyncTask是一个抽象类,我们需要一个子类继承它并提供三个泛型参数。

    1. Params 参数
    2. Progress 进度
    3. Result 返回结果

    class DownloadTask extend AsyncTask< Void,Integer,Boolean>
    Void表示不需要传参数给后台,Integer表示用整形的数来表示过程,Boolean表示用布尔值表示结果。

    重写方法

    1. OnPreExecute() 在后台任务开始之前调用,用于初始化UI界面等

    2. doInBackground(Params) 所有代码都在子线程用于耗时操作,完成后返回结果,如果第三个参数是Void,不用返回,如果需要反馈任务进度调用publishProgress()方法

    3. OnProgressUpdate(Progress),当执行publishProgress()方法后被调用用于界面更新(不一定会被调用)

    4. OnPostEcecute(Result) 后台任务执行完毕返回参数。
      使用AsyncTask实现下载器



      public class MainActivity extends AppCompatActivity {
      @BindView(R.id.btn)
      Button btn;
      @BindView(R.id.pb)
      ProgressBar pb;
      private int progress = 0;
      private Handler mHandler = new Handler();
      
      @Override
      protected void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
          setContentView(R.layout.activity_main);
          ButterKnife.bind(this);
      }
      
      @OnClick(R.id.btn)
      public void onViewClicked() {
          new DownloadTask().execute();
      }
      
      class DownloadTask extends AsyncTask<Void,Integer,Boolean>{
      
          @Override
          protected void onPreExecute() {
              KLog.d("开始下载");
              pb.setVisibility(View.VISIBLE);
          }
      
          @Override
          protected Boolean doInBackground(Void... voids) {
              KLog.d("开始下载");
              while (true){
                  try {
                      Thread.sleep(1000);
                      progress += 10;
                      publishProgress(progress);
                      if(progress >= 100)
                          break;
      
                  } catch (InterruptedException e) {
                      e.printStackTrace();
                      return false;
                  }
              }
              return true;
          }
      
          @Override
          protected void onProgressUpdate(Integer... values) {
              KLog.d("正在下载"+values[0]);
              pb.setProgress(values[0]);
          }
      
          @Override
          protected void onPostExecute(Boolean aBoolean) {
              if(aBoolean){
                  KLog.d("下载成功");
                  pb.setVisibility(View.GONE);
              }else{
                  KLog.d("下载失败");
              }
          }
      }
      

      }


    AsyncTask优点:简单,快捷
    缺点:当有多个异步操作时并需要变更ui复杂

    相关文章

      网友评论

          本文标题:Android多线程和异步任务详解

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