編輯:關於Android編程
handler是android中專門用來在線程之間傳遞信息類的工具。
當應用程序啟動時,會開啟一個主線程(也就是UI線程),由它來管理UI,監聽用戶點擊,來響應用戶並分發事件等。所以一般在主線程中不要執行比較耗時的操作,如聯網下載數據等,否則出現ANR錯誤。所以就將這些操作放在子線程中,但是由於AndroidUI線程是不安全的,所以只能在主線程中更新UI。Handler就是用來 子線程和創建Handler的線程進行通信的。
消息的處理者,handler負責將需要傳遞的信息封裝成Message,通過調用handler對象的obtainMessage()來實現;將消息傳遞給Looper,這是通過handler對象的sendMessage()來實現的。繼而由Looper將Message放入MessageQueue中。當Looper對象看到MessageQueue中含有Message,就將其廣播出去。該handler對象收到該消息後,調用相應的handler對象的handleMessage()方法
主要功能是為特定單一線程運行一個消息環。一個線程對應一個looper。同樣一個looper對應一個線程。這就是所謂的特定單一。一般情況下,在一個線程創建時他本身是不會生產他特定單一的looper的(主線程是個特例)。因此我們需要手動的把一個looper與線程相關聯。其方法只需在需要關聯的looper的線程中調用Looper.prepare。之後我們再調用Looper.loop啟動looper。
從代碼層面來講Looper是MessageQueue的管理者。每一個MessageQueue都不能脫離Looper而存在,Looper對象的創建是通過prepare函數來實現的。同時每一個Looper對象
和一個線程關聯。通過調用Looper.myLooper()可以獲得當前線程的Looper對象
創建一個Looper對象時,會同時創建一個MessageQueue對象。除了主線程有默認的Looper,其他線程默認是沒有MessageQueue對象的,所以,不能
接受Message。如需要接受,自己定義一個Looper對象(通過prepare函數),這樣該線程就有了自己的Looper對象和MessageQueue數據結構了。
Looper從MessageQueue中取出Message然後,交由Handler的handleMessage進行處理。處理完成後,調用Message.recycle()將其放入Message Pool中。
class MyThread extends Thread{
public void run(){
Looper.prepare(); //創建該線程的Looper對象,用於接收消息
//這裡Looper.myLooper()獲得的就是該線程的Looper對象了
handler = new ThreadHandler(Looper.myLooper());
//不經常去看看,你怎麼知道你有新消息呢?
Looper.loop();
}
MessageQueue:是一種數據結構,見名知義,就是一個消息隊列,存放消息的地方。每一個線程最多只可以擁有一個MessageQueue數據結構。創建一個線程的時候,並不會自動創建其MessageQueue。通常使用一個Looper對象對該線程的MessageQueue進行管理。主線程創建時,會創建一個默認的Looper對象,而Looper對象的創建,將自動創建一個Message Queue。其他非主線程,不會自動創建Looper,要需要的時候,通過調用prepare函數來實現。
Message:消息對象,Message Queue中的存放的對象。一個Message Queue中包含多個Message。Message實例對象的取得,通常使用Message類裡的靜態方法obtain(),該方法有多個重載版本可供選擇;它的創建並不一定是直接創建一個新的實例,而是先從Message Pool(消息池)中看有沒有可用的Message實例,存在則直接取出返回這個實例。如果Message Pool中沒有可用的Message實例,則才用給定的參數創建一個Message對象。調用removeMessages()時,將Message從Message Queue中刪除,同時放入到Message Pool中。除了上面這種方式,也可以通過Handler對象的obtainMessage()獲取一個Message實例。
代碼示例:
主線程給自己發送Message
public class MainActivity extends Activity {
private Button btnTest;
private TextView textView;
private Handler handler;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
btnTest =(Button)this.findViewById(R.id.btn_01);
textView = (TextView)this.findViewById(R.id.view_01);
btnTest.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View arg0) {
Looper looper = Looper.getMainLooper(); //主線程的Looper對象
//這裡以主線程的Looper對象創建了handler,
//所以,這個handler發送的Message會被傳遞給主線程的MessageQueue。
handler = new MyHandler(looper);
handler.removeMessages(0);
//構建Message對象
//第一個參數:是自己指定的message代號,方便在handler選擇性地接收
//第二三個參數沒有什麼意義
//第四個參數需要封裝的對象
Message msg = handler.obtainMessage(1,1,1,"主線程發消息了");
handler.sendMessage(msg); //發送消息
}
});
}
class MyHandler extends Handler{
public MyHandler(Looper looper){
super(looper);
}
public void handleMessage(Message msg){
super.handleMessage(msg);
textView.setText("我是主線程的Handler,收到了消息:"+(String)msg.obj);
}
}
}
其他線程給主線程發送Message
public class MainActivity extends Activity {
private Button btnTest;
private TextView textView;
private Handler handler;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
btnTest = (Button)this.findViewById(R.id.btn_01);
textView = (TextView)this.findViewById(R.id.view_01);
btnTest.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View arg0) {
//可以看出這裡啟動了一個線程來操作消息的封裝和發送的工作
//這樣原來主線程的發送就變成了其他線程的發送,簡單吧?呵呵
new MyThread().start();
}
});
}
class MyHandler extends Handler{
public MyHandler(Looper looper){
super(looper);
}
public void handleMessage(Message msg){
super.handleMessage(msg);
textView.setText("我是主線程的Handler,收到了消息:"+(String)msg.obj);
}
}
//加了一個線程類
class MyThread extends Thread{
public void run(){
Looper looper = Looper.getMainLooper(); //主線程的Looper對象
//這裡以主線程的Looper對象創建了handler,
//所以,這個handler發送的Message會被傳遞給主線程的MessageQueue。
handler = new MyHandler(looper);
//構建Message對象
//第一個參數:是自己指定的message代號,方便在handler選擇性地接收
//第二三個參數沒有什麼意義
//第四個參數需要封裝的對象
Message msg = handler.obtainMessage(1,1,1,"其他線程發消息了");
handler.sendMessage(msg); //發送消息
}
}
}
主線程給其他線程發送Message
public class MainActivity extends Activity {
private Button btnTest;
private TextView textView;
private Handler handler;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
btnTest = (Button)this.findViewById(R.id.btn_01);
textView = (TextView)this.findViewById(R.id.view_01);
//啟動線程
new MyThread().start();
btnTest.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View arg0) {
//這裡handler的實例化在線程中
//線程啟動的時候就已經實例化了
Message msg = handler.obtainMessage(1,1,1,"主線程發送的消息");
handler.sendMessage(msg);
}
});
}
class MyHandler extends Handler{
public MyHandler(Looper looper){
super(looper);
}
public void handleMessage(Message msg){
super.handleMessage(msg);
textView.setText("我是主線程的Handler,收到了消息:"+(String)msg.obj);
}
}
class MyThread extends Thread{
public void run(){
Looper.prepare(); //創建該線程的Looper對象,用於接收消息
//注意了:這裡的handler是定義在主線程中的哦,呵呵,
//前面看到直接使用了handler對象,是不是在找,在什麼地方實例化的呢?
//現在看到了吧???呵呵,開始的時候實例化不了,因為該線程的Looper對象
//還不存在呢。現在可以實例化了
//這裡Looper.myLooper()獲得的就是該線程的Looper對象了
handler = new ThreadHandler(Looper.myLooper());
//這個方法,有疑惑嗎?
//其實就是一個循環,循環從MessageQueue中取消息。
//不經常去看看,你怎麼知道你有新消息呢???
Looper.loop();
}
//定義線程類中的消息處理類
class ThreadHandler extends Handler{
public ThreadHandler(Looper looper){
super(looper);
}
public void handleMessage(Message msg){
//這裡對該線程中的MessageQueue中的Message進行處理
//這裡我們再返回給主線程一個消息
handler = new MyHandler(Looper.getMainLooper());
Message msg2 = handler.obtainMessage(1,1,1,"子線程收到:"+(String)msg.obj);
handler.sendMessage(msg2);
}
}
}
}
Android WebView 的簡單使用
Android WebView 1.首先修改activity.xml中的代碼:2.然後MainActivity中的代碼:3.最後設置權限:<uses-permiss
Android 開發仿簡書登錄框可刪除內容或顯示密碼框的內容
簡書App 是我很喜歡的一款軟件。今天就模仿了一下他的登錄框。先上圖:好了下面上代碼,自定義ImgEditText 繼承與EditText。重寫一些方法。package
Android事件傳遞(二)ViewGroup事件的傳遞
經過上一篇的實驗,我門只是僅僅對View的事件的傳遞進行了分析,但是還有一個比較厲害的ViewGroup我們肯定是要說一下的,ViewGroup的二叉視圖分析 我們能看到
Android Material Design(一)材料設計控件大全
主要內容:本文將要介紹Material design和Support library控件,主要包括TextInputLayout、SwitchCompat、SnackBa