zoukankan      html  css  js  c++  java
  • AsyncTask和Handler的优缺点比较(更新线程的问题总结

    AsyncTask和Handler的优缺点比较:

    http://blog.csdn.net/onlyonecoder/article/details/8484200

    更深入的参考 

    http://www.cnblogs.com/net168/p/4082217.html

    Handler主要接受子线程发送的数据, 并用此数据配合主线程更新UI.
    当应用程序启动时,Android首先会开启一个主线程, 主线程为管理界面中的UI控件,进行事件分发,更新UI只能在主线程中更新,子线程中操作是危险的。这个时候,Handler就需要出来解决这个复杂的问题。由于Handler运行在主线程中(UI线程中),它与子线程可以通过Message对象来传递数据, 这个时候,Handler就承担着接受子线程传过来的(子线程用sedMessage()方法传递)Message对象(里面包含数据), 把这些消息放入主线程队列中,配合主线程进行更新UI。
    综上所述:数据简单使用AsyncTask:实现代码简单,数据量多且复杂使用handler+thread :相比较AsyncTask来说能更好的利用系统资源且高效
     

    下面的转自:

    http://www.cnblogs.com/net168/p/4075126.html

    不要在UI主线程中进行耗时操作

      如果你不信邪一定要在UI主线程进行下载文件、加载大文件之类的耗时操作。如下代码:

    private Button btn;
    //onCreate之类的生命周期的方法就是允许在UI主线程中
    @Override
    protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_main);
            
      btn = (Button) findViewById(R.id.btn);
            
      btn.setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(View v) {
          downLoad();//调用UI主线程的下载函数
        }
      });
    }
        
    private void downLoad(){
      try {
        Thread.sleep(10000);//休眠10秒,模拟网络文件下载耗时操作
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }
    

      你会发现界面卡主了10秒:(模拟下载操作的按钮为深色,说明按钮一直为按下状态)

    如果这时候你手比较管不住的话,虽然点几下界面,没事~Androi系统会马上送你一份ANR大礼哦

    小结一个:不要在UI主线程中进行耗时操作,你可能会疑问什么是UI主线程,UI主线程主要运行的就是Activity、Service等里面的生命周期方法,所以不要在生命周期方法如onCreate()中进行下载这些大事件。对于耗时操作,我们应该新建一个子线程并交给他处理,但是还需要注意一点。

    不要在子线程中更新UI界面

    既然我们说下载文件要在子线程中进行,那么我们就新建一个子线程把下载操作放到里面进行咯

    protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_main);
            
      btn = (Button) findViewById(R.id.btn);
      text = (TextView) findViewById(R.id.text);
            
      btn.setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(View v) {
          new Thread(){
            @Override
            public void run() {
              //在子线程中进行下载操作
              try {
                Thread.sleep(10000);//休眠10秒,模拟耗时操作
              } catch (InterruptedException e) {
                e.printStackTrace();
              }
              text.setText("下载完成");//设置TextView,通知UI界面下载完成
            }
          }.start();
        }
      });
    }
    

      小结一个:不要在子线程中更新UI界面,这样会导致android系统报错、应用崩溃退出。UI界面时单线程模式,我们只能通过UI主线程中对UI的界面进行相关的更新,千万不要越线办事,你要记住的是~UI界面是UI主线程的老婆,你们这些子线程谁都别想动!

    利用Thread+Handler进行异步处理

      那么问题来了,现在我们需要进行耗时操作(例如下载文件)时不能在主线程执行,我们又需要在UI界面通知用户我们活干完了不能再子线程中执行。这似乎是一个棘手的热山芋呀,幸好谷歌给我们提供了一个救我们于危难之中的Handler,一个能让主线程监听子线程发送来消息的东东,至于Handler的实现原理我会在后面的文章详细介绍,现在我们只需要先了解Handler的用法。

    private Button btn;
    private TextView text;
        
    private Handler handler = new Handler(){
      private int process = 0;
      @Override
      public void handleMessage(Message msg) {
        switch(msg.what){
        case 0://更细下载进度
          process += 1;
          text.setText("下载" + process + "%");//在主线程中更新UI界面
          break;
        case 1://提示下载完成
          text.setText("下载完成");//在主线程中更新UI界面
          break;
        default:
          break;
        }
      }
    };
    //onCreate之类的生命周期的方法就是允许在UI主线程中
    @Override
    protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_main);
            
      btn = (Button) findViewById(R.id.btn);
      text = (TextView) findViewById(R.id.text);
            
      btn.setOnClickListener(new OnClickListener() {
      @Override
      public void onClick(View v) {
        new Thread(){
          @Override
          public void run() {
            //在子线程中进行下载操作
            for(int i = 0; i < 100; i++){
              try {
                Thread.sleep(200);//休眠0.2秒,模拟耗时操作
              } catch (InterruptedException e) {
                e.printStackTrace();
              }
              handler.sendEmptyMessage(0);//发送消息到handler,通知下载进度
            }
            handler.sendEmptyMessage(1);//发送消失到handler,通知主线程下载完成
            }
          }.start();
        }
      });
    }
    

      小结一个:对于比较耗时间的任务,我们一般需要放在子线程中执行;当子线程更新UI界面时,子线程可以通过Handler来通知主线程更新,一般通过发送消息来触发handlerMessage()这个回调方法来执行UI界面的更新。

    进一步简略de操作:handler.post方法和view.post方法

      但是如果你觉得每次都要重写handlerMessage()比较麻烦,我们完全可以用更加简略的方法来解决我们的需求,就是用handler中的post方法。代码如下

    new Thread(){
      @Override
      public void run() {
        //在子线程中进行下载操作
        try {
          Thread.sleep(1000);
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
        handler.post(new Runnable() {
          @Override
          public void run() {
            text.setText("下载完成");
          }
        });//发送消失到handler,通知主线程下载完成
      }
    }.start();
    

      这样处理的话我们就可以不用重写handlerMessage()方法了,适合子线程与主线程进行较为单一的交流。但在这里我们要强调的一点的是,post里面的Runnable还是在UI主线程中运行的,而不会另外开启线程运行,千万不要在Runnable的run()里面进行耗时任务,不然到时又ANR了可别找我哦。。

    如果你有时候连handler都不想搞,还可以这样写代码滴。

    我们只需要把handler换成View组件进行post,更新任务自然会加载到UI主线程中进行处理。

    text.post(new Runnable() {
      @Override
      public void run() {
        text.setText("下载完成");
      }
    });//发送消失到handler,通知主线程下载完成
    

    View.post学习

    Runnable 并不一定是新开一个线程,比如下面的调用方法就是运行在UI主线程中的:

        Handler mHandler=new Handler(); 
         mHandler.post(new Runnable(){ 
            @Override public void run() 
            { // TODO Auto-generated method stub 
             } 
         });

    官方对这个方法的解释如下,注意其中的:“The runnable will be run on the user interface thread. ”

    boolean android.view.View .post(Runnable action)

    Causes the Runnable to be added to the message queue. The runnable will be run on the user interface thread.

    Parameters:

    action The Runnable that will be executed.

    Returns:

    Returns true if the Runnable was successfully placed in to the message queue. Returns false on failure, usually because the looper processing the message queue is exiting.

    我们可以通过调用handler的post方法,把Runnable对象(一般是Runnable的子类)传过去;handler会在looper中调用这个Runnable的Run方法执行。

    Runnable是一个接口,不是一个线程,一般线程会实现Runnable。所以如果我们使用匿名内部类是运行在UI主线程的,如果我们使用实现这个Runnable接口的线程类,则是运行在对应线程的。

    具体来说,这个函数的工作原理如下:

    View.post(Runnable)方法。在post(Runnable action)方法里,View获得当前线程(即UI线程)的Handler,然后将action对象post到Handler里。在Handler里,它将传递过来的action对象包装成一个Message(Message的callback为action),然后将其投入UI线程的消息循环中。在Handler再次处理该Message时,有一条分支(未解释的那条)就是为它所设,直接调用runnable的run方法。而此时,已经路由到UI线程里,因此,我们可以毫无顾虑的来更新UI。

    如下图,前面看到的代码,我们这里Message的callback为一个Runnable的匿名内部类

    这种情况下,由于不是在新的线程中使用,所以千万别做复杂的计算逻辑。

  • 相关阅读:
    ios本地推送
    ios BUG
    性能优化
    数据结构设计
    代码的可维护性
    NSMutalbleDictionary
    NSDictionary
    NSMutableArray
    java 容器
    Java bug
  • 原文地址:https://www.cnblogs.com/chuiyuan/p/4085926.html
Copyright © 2011-2022 走看看