Android Handler使用

1. 介绍

Handler允许向关联线程的消息队列(MessageQueue)发送消息(Message)和可执行对象(Runnable).
每个Handler实例都与某个线程(即创建该Handler的线程)及该线程的消息队列所关联

Handler主要有两种用途

- 调度消息和可执行对象在未来某个时间点的处理
- 在其他线程中执行动作

2. 实例

2.1 基本实例

注意: 实例中myRunnable方法是被UI线程执行

File: activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.lineto.testhandler.MainActivity">

    <Button
        android:id="@+id/start"
        android:text="start"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        />
    <Button
        android:id="@+id/stop"
        android:text="stop"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        />
</LinearLayout>

File: MainActivity.java

public class MainActivity extends AppCompatActivity {
    private Button start;
    private Button stop;
    private Handler handler;
    private Runnable myRunnable;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        start = (Button)findViewById(R.id.start);
        stop  = (Button)findViewById(R.id.stop);

        View.OnClickListener listener = new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Button button = (Button)v;
                if (button == start) {
                    handler.post(myRunnable);
                } else if (v == stop) {
                    handler.removeCallbacks(myRunnable);
                }
            }
        };
        start.setOnClickListener(listener);
        stop.setOnClickListener(listener);

        handler = new Handler();
        myRunnable = new Runnable() {
            @Override
            public void run() {
                System.out.println("Run method");
                handler.postDelayed(myRunnable, 3000);
            }
        };
    }
}

2.2 进度条实例

在该实例中, 分别采用两种方式来实现
一种是runnable方法由UI线程来执行, 另一种是runnable方法由新线程来执行
可以发现第一种会导致界面卡顿, 后面一种才是Handler的正确使用方法

File: activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.lineto.handlerprogressbar.MainActivity">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="ProgressBar With Handler"
        />
    <ProgressBar
        android:id="@+id/progressbar"
        style="@android:style/Widget.ProgressBar.Horizontal"
        android:layout_width="300dp"
        android:layout_height="wrap_content"
        android:visibility="gone"
        />
    <Button
        android:id="@+id/start"
        android:text="Start"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
    <Button
        android:id="@+id/stop"
        android:text="Stop"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</LinearLayout>

File: MainActivity.java

public class MainActivity extends AppCompatActivity {
    private ProgressBar progressBar;
    private Button start;
    private Button stop;
    private Handler handler;
    private boolean use_new_thread = true;
    private boolean thread_running = false;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        progressBar = (ProgressBar)findViewById(R.id.progressbar);
        start       = (Button)findViewById(R.id.start);
        stop        = (Button)findViewById(R.id.stop);

        final Runnable myRunnable = new Runnable() {
            int i = 0;
            @Override
            public void run() {
                do {
                    try {
                        Thread.sleep(1000);
                    } catch (Exception e) {
                        System.out.println(e);
                    }
                    if (i < 100) {
                        i += 10;
                    } else {
                        i = 0;
                    }
                    Message msg = handler.obtainMessage();
                    msg.arg1 = i;
                    handler.sendMessage(msg);
                } while(thread_running);
            }
        };

        View.OnClickListener listener = new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (v == start) {
                    Toast toast = Toast.makeText(MainActivity.this, "Start", Toast.LENGTH_SHORT);
                    toast.show();
                    progressBar.setVisibility(View.VISIBLE);
                    if (use_new_thread) {
                        thread_running = true;
                        Thread thread = new Thread(myRunnable);
                        thread.start();
                    } else {
                        thread_running = false;
                        handler.post(myRunnable);
                    }
                }
                else if(v == stop) {
                    Toast toast = Toast.makeText(MainActivity.this, "Stop", Toast.LENGTH_SHORT);
                    toast.show();
                    progressBar.setVisibility(View.GONE);
                    if (use_new_thread) {
                        thread_running = false;
                    } else {
                        handler.removeCallbacks(myRunnable);
                    }
                }
            }
        };

        start.setOnClickListener(listener);
        stop.setOnClickListener(listener);

        handler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                progressBar.setProgress(msg.arg1);
                if (!use_new_thread) {
                    handler.post(myRunnable);
                }
            }
        };

    }
}

3. Looper

Looper是用于给线程添加一个消息队列(MessageQueue), 并且循环等待; 当有消息时会唤起线程来处理消息的类.
UI线程默认包含一个Looper, 所以通常不需要为新线程创建Looper;当为新线程创建Looper后, 通常使用Handler来进行消息交互

下面是一个典型的Looper使用方法

class LooperThread extends Thread {
      public Handler mHandler;

      public void run() {
          Looper.prepare();

          mHandler = new Handler() {
              public void handleMessage(Message msg) {
                  // process incoming messages here
              }
          };

          Looper.loop();
      }
  }

详细的实例参考<Android实战技巧:消息循环与Looper>

4. HandlerThread

HandlerThread是一个拥有Looper的Thread, 然后可以使用该Looper得到一个Handler(一定要在start()方法之后)
需要注意的是程序结束的时候需要退出Looper(quit()/quitSafely())

相关实例参考<Android HandlerThread 完全解析>

5. Message

Message用于在消息循环中通信, 用来发消息给某个Handler, 可以通过Handler的obtainMessage()从消息池中获取一个Message引用;Message常用的方法是赋值, 相关操作查询API即可

参考:
<Android 异步消息处理机制>
<Android中的Handler的机制与用法详解>

posted @ 2017-04-13 17:34  北落不吉  阅读(495)  评论(0编辑  收藏  举报