Android基础之六:多线程开发

  • 多线程开发为复杂的耗时处理功能提高了效率,同时也不影响UI界面的显示效果,是在Android开发或者Java开发中经常用到的一种开发机制
  • 首先理解多线程的概念:
    • 多线程并不是真正的多个任务在同一时间点上并发执行,而是分时间片来执行,即同一个时间点上执行的任务只有一个,但是从一小段时间来看,却是许多任务并发执行
    • 多线程需要注重资源的分配
    • 需要注意Java中多线程机制
    • 主线程:即应用的UI线程
    • 辅线程:即工作线程,不能直接操作UI
  • Android中的多线程
    • Handler类
      • post方法
        • post方法并没有新起线程,仍然运行在UI线程中,其本质上还是UI线程,只是是UI现成的子线程,可以优化UI操作性能
        • 与View自带的post方法原理相同,都是在UI子线程中操作UI变化
        • Handler handler=new Handler();
          handler.post(new Runnable() {
                @Override
                 public void run() {
                        //ToDo
                 }
          });
        • 注意:进行UI操作,例如修改UI控件属性等,虽然直接修改一般不会出现问题,但是如果在UI执行耗时操作时会造成卡顿,通常使用post来通过UI子线程来操作
      • sendMessage方法
        • post方法只适合在单独操作UI的情况下使用,如果其中涉及到耗时操作以及UI操作,例如:UI与Service通信,根据Service返回的结果修改UI,Service通常是一个比较耗时的操作,在这种情况下就不能直接使用post将耗时操作放到UI线程中,而是需要开启辅线程
        • 辅线程是独立于UI线程之外的工作线程,在工作线程中能够处理复杂的业务逻辑计算等耗时操作,但是不能直接操作UI
        • 辅线程(工作线程)与UI线程之间的交互
          • UI线程中创建Handler
          • Handler handler=new Handler(){
                @Override
                public void handleMessage(Message msg) {
                    super.handleMessage(msg);
                    //UI 操作
                }
            };
          • 辅线程中创建Message消息,并向主线程的handler传递消息
          • Message message=new Message();
            message.setData(new Bundle());
            handler.sendMessage(message);
          • 这样就可以实现工作线程执行耗时操作,UI线程负责界面处理
    • HandlerThread类
      • HandlerThread可以另起新线程,但不能操作UI,属于工作线程
      • 通过HandlerThread的Looper创建的Handler使用post方法也不能操作UI,只有通过主线程的Looper创建的Handler才能操作UI,即Handler的构造方法中不传参时表示的是使用主线程的Looper创建实例
      • HandlerThread使用
        • 创建实例
        • HandlerThread ht = new HandlerThread("handler thread");
          ht.start();
        • 实例化后必须使用start启动
        • 通过HandlerThread实例的Looper创建Handler实例
        • Handler handler=new Handler(ht.getLooper());
        • 通过Handler实例进行post方法调用
        • handler.post(new Runnable(){//这里run()方法其实还是在等ht.start()调用
              public void run(){
                  Log.e("当前线程:",Thread.currentThread().getName());//这里打印的会是handler thread
                  setTitle("哈哈");//这样必定报错
              }
          });
        • 在run中如果操作UI会直接报错,因为这个县城是工作线程,不能执行UI操作,而如果想要执行UI操作,需要通过sendMessage来实现,在UI线程中再实例化一个Handler实例,重写handlerMessage方法,然后在run中向该实例发送消息
        • 这样实现会发现比较繁琐而且低效,不建议使用这种方法,即HandlerThread不建议使用
        • 并且一个HandlerThread中创建的多个Handler,在post的时候并不是并打的,而是顺序执行的
    • Java中创建线程方法
      • Java提供了通用的多线程类与接口,能够简单而直接创建工作线程,不需要使用HandlerThread创建一个handler
      • 通过new Thread(){run}.start();
      • new Thread(){
            @Override
            public void run() {
                super.run();
                //ToDo
            }
        }.start();
        • 该方法是通过匿名类来实例化Thread的子类实例的,在run中处理复杂操作,并发送消息到UI线程中,完成与UI线程通信
      • 通过new Thread(Runnable).start();
      • new Thread(new Runnable() {
            @Override
            public void run() {
                
            }
        }).start();
        • 通过Runnable接口实例化Thread实例,与匿名类一样,只是两种不同的实例化方法
    • AsyncTask异步任务
      • Android中提供一种异步任务类,能够实现简单的工作线程与主线程操作,是Handler、Message的结合,使用更加简单
      • 创建异步任务
        • 注意AsyncTask中的5个可重写方法
          • onPreExcute:是在异步任务执行前执行的操作,可以操作UI线程
          • doInBackground(params):在工作线程中执行的操作
          • onProgressUpdate(values):在工作线程执行过程中如果需要操作UI,就可以在doInBackground中使用publicProgress();来广播进度,在onProgressUpdate中就会收到进度值
          • onPostExcute(retult):任务执行结束后调用,即将doInBackground中返回的结果传到该方法中
          • 在实例化AsyncTask的时候可以直接指定不同方法中参数的类型,即AsyncTask是泛型类
          • 在整个过程中只有一个方法doInBackground是在工作线层中运行的,其他三个方法都是在主线程中运行的
        • 实例化
        • AsyncTask<String,String,String> asyncTask=new AsyncTask<String, String, String>() {
              @Override
              protected void onPreExecute() {
                  super.onPreExecute();
              }
              @Override
              protected String doInBackground(String... params) {
                  return null;
              }
              @Override
              protected void onProgressUpdate(String... values) {
                  super.onProgressUpdate(values);
              }
              @Override
              protected void onPostExecute(String s) {
                  super.onPostExecute(s);
              }
          };
        • 与Thread+Handler+Message实现多线程比较
          • AsyncTask本质上就是Thread+Handler+Message的封装
          • 在Activity被重新创建(设备状态改变,例如屏幕方向变化引起的Activity重启)时,任务会被取消
          • 在线程池中只能容纳5个后台运行程序,再多会造成阻塞,这里表示的是通过AsyncTask创建的线程,用Thread创建的不算
          • 执行方式不同,AsyncTask通过excute来执行,Thread通过start来执行
    • ExecutorService线程池
      • 线程池适合处理大量线程的操作,例如多线程加载1000张图片,多线程批量下载
      • 实例化线程池
        • 单线程
        • ExecutorService service=Executors.newSingleThreadExecutor();
        • 固定数量线程
        • ExecutorService service=Executors.newFixedThreadPool(10);
        • 动态线程
        • ExecutorService service=Executors.newCachedThreadPool();
      • 执行线程操作:
        • submit(Runnable):创建并执行一个工作线程
原文地址:https://www.cnblogs.com/xl-xlg/p/5036035.html