1.Handler简介
handler是Android系统封装的用于线程更新UI,消息处理的机制。
[说明]
查看Android Framework源码可以看到,常见的Activity的生命周期onCreate(), onStart(), onResume(), onPause(), onStop(), onDestroy()都是通过handler发送不同Message,AMS(Activity Manager Service)通过Handler向ActivityThread发送消息,在ActivityThread中执行不同的Activity的周期。
2.Handler的用法
// Google文档的地址
http://developer.android.com/reference/android/os/Handler.html
// Google对Handler的介绍
A Handler allows you to send and process Message and Runnable objects associated with a thread's MessageQueue.
Each Handler instance is associated with a single thread and that thread's message queue. When you create a new Handler,
it is bound to the thread / message queue of the thread that is creating it -- from that point on, it will deliver
messages and runnables to that message queue and execute them as they come out of the message queue.
[说明]
查看Google文档可以看出,Handler允许我们绑定(associate with)一个线程的MessageQueue,并通过该handler向该线程发送Message或者Runnable对象,一个Handler绑定了一个线程以及这个线程的MessageQueue,当你创建一个Handler的时候,该Handler就会和Thread以及该Thread的MessageQueue绑定。
首先,下面的程序,在子线程中更新UI:
public class MainActivity extends Activity
{
TextView tv;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv = (TextView) findViewById(R.id.tv);
new Thread()
{
public void run()
{
try
{
Thread.sleep(1000);
} catch (InterruptedException e)
{
e.printStackTrace();
}
tv.setText("update UI");
};
}.start();
}
}
运行之后,程序奔溃,logcat中打印信息:
[说明]
上面信息的主要内容是,不允许在子线程中更新UI线程,Android自身设定的机制则是只能在子线程中处理耗时的操作,处理完毕之后,在UIThread中更新UI,而子线程是不能更新UI的。
Handler主要提供了下面API来实现子线程与UIThread之间的通信问题:
- sendMessage
- sendMessageDelayed
- post(Runnable)
- postDelayed(Runnable, long)
public class MainActivity extends Activity
{
@SuppressLint("HandlerLeak")
Handler handler = new Handler()
{
public void handleMessage(android.os.Message msg)
{
if (msg.what == 0x1)
{
tv.setText("update UI");
}
};
};
TextView tv;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv = (TextView) findViewById(R.id.tv);
new Thread()
{
public void run()
{
try
{
Thread.sleep(1000);
} catch (InterruptedException e)
{
e.printStackTrace();
}
handler.sendEmptyMessage(0x1);
};
}.start();
}
}
sendMessageDelayed(Message, long)是延迟long毫秒之后,再发送Message。
public class MainActivity extends Activity
{
@SuppressLint("HandlerLeak")
Handler handler = new Handler()
{
public void handleMessage(android.os.Message msg)
{
};
};
TextView tv;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv = (TextView) findViewById(R.id.tv);
new Thread()
{
public void run()
{
try
{
Thread.sleep(1000);
} catch (InterruptedException e)
{
e.printStackTrace();
}
handler.post(new Runnable()
{
@Override
public void run()
{
tv.setText("update UI");
}
});
};
}.start();
}
}
下面利用Handler实现一个简单的图片轮换的功能,每隔1s循环替换ImageView显示的图片:
public class MainActivity extends Activity
{
Handler handler = new Handler();
ImageView img;
int[] images = // 存放循环播放的图片
{ R.drawable.weather_0, R.drawable.weather_1, R.drawable.weather_2, R.drawable.weather_3, R.drawable.weather_4 };
private int imgCount = images.length;
private int index = 0;
private long delayMillis = 1000L; // 每隔1s循环一次
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
img = (ImageView) findViewById(R.id.img);
handler.post(imgRunnable);
}
private Runnable imgRunnable = new Runnable()
{
public void run()
{
img.setBackgroundResource(images[index % imgCount]);
index++;
handler.postDelayed(imgRunnable, delayMillis);
}
};
}
对应的xml文件中只有一个<ImageView />:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<ImageView
android:id="@+id/img"
android:layout_width="200.0dip"
android:layout_height="200.0dip"
android:layout_centerInParent="true"
android:contentDescription="@string/app_name" />
</RelativeLayout>
handler.removeCallbacks(imgRunnable);
public class SecondActivity extends Activity
{
@SuppressLint("HandlerLeak")
Handler handler = new Handler(new Handler.Callback()
{
@Override
public boolean handleMessage(Message msg)
{
if (msg.what == 0x1)
{
Log.v(LOG, "返回true,消息被截获");
return true;
} else if (msg.what == 0x2)
{
Log.v(LOG, "返回false,不截获");
return false;
}
return false;
}
})
{
@Override
public void handleMessage(Message msg)
{
Log.v(LOG, "收到消息....");
}
};
Button btn1, btn2;
private final String LOG = "SecondActivity";
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
btn1 = (Button) findViewById(R.id.btn1);
btn1.setOnClickListener(new OnClickListener()
{
@Override
public void onClick(View v)
{
handler.sendEmptyMessage(0x1);
}
});
btn2 = (Button) findViewById(R.id.btn2);
btn2.setOnClickListener(new OnClickListener()
{
@Override
public void onClick(View v)
{
handler.sendEmptyMessage(0x2);
}
});
}
}
界面效果如下: