android——handler机制原理

  在android版本4.0及之后的版本中多线程有明确的分工,子线程可以写所有耗时的代码(数据库、蓝牙、网络服务),但是绝对不能碰UI,想碰UI跟着主线程走,那么我们如何才能让主线程知道我们要对 UI进行操作呢?这时我们就可以利用用消息机制——handler去通知主线程(因为子线程本身不可以发消息)

  下面是handler简单的工作原理图(此图为转载)

   handler用来发消息和处理消息

下面用个案例来说明:

  activity_main.xml:

      

 1 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
 2     xmlns:tools="http://schemas.android.com/tools"
 3     android:layout_width="match_parent"
 4     android:layout_height="match_parent"
 5     >
10  
11     <TextView
12         android:id="@+id/textView1"
13         android:layout_width="wrap_content"
14         android:layout_height="wrap_content"
15         android:text="@string/hello_world" />
16 
17     <Button
18         android:id="@+id/button1"
19         android:layout_width="wrap_content"
20         android:layout_height="wrap_content"
21         android:layout_alignParentRight="true"
22         android:layout_alignTop="@+id/textView1"
23         android:layout_marginRight="53dp"
24         android:text="Button" />
25 
26     <ListView
27         android:id="@+id/listView1"
28         android:layout_width="match_parent"
29         android:layout_height="wrap_content"
30         android:layout_below="@+id/button1"
31         android:layout_marginTop="84dp" >
32     </ListView>
33 
34    <!--  <ProgressBar
35         android:id="@+id/progressBar1"
36         style="?android:attr/progressBarStyleHorizontal"
37         android:layout_width="wrap_content"
38         android:layout_height="wrap_content"
39         android:layout_alignLeft="@+id/listView1"
40         android:layout_alignRight="@+id/button1"
41         android:layout_below="@+id/button1"
42         android:layout_marginTop="28dp" /> -->
43 
44 </RelativeLayout>

listview中的布局item.xml

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 3     android:layout_width="match_parent"
 4     android:layout_height="match_parent"
 5     android:orientation="horizontal" >
 6     <TextView 
 7         android:id="@+id/username"
 8         android:layout_weight="1"
 9         android:layout_width="match_parent"
10         android:layout_height="60dp"
11         android:textSize="45dp"
12         />
13 
14     <TextView
15         android:id="@+id/sex"
16         android:layout_width="match_parent"
17         android:layout_height="60dp"
18         android:layout_weight="1"
19         android:textSize="45dp" />
20 
21 </LinearLayout>

User.java(用于模拟数据)

 1 public class User {
 2     private String username;
 3     private String sex;
 4     public String getUsername() {
 5         return username;
 6     }
 7     public void setUsername(String username) {
 8         this.username = username;
 9     }
10     public String getSex() {
11         return sex;
12     }
13     public void setSex(String sex) {
14         this.sex = sex;
15     }
16 
17 }

mainActivity.java

 

  1  2 
  3 import java.util.ArrayList;
  4 import java.util.List;
  5 
  6 import android.app.Activity;
  7 import android.os.Bundle;
  8 import android.os.Handler;
  9 import android.os.Message;
 10 import android.util.Log;
 11 import android.view.LayoutInflater;
 12 import android.view.Menu;
 13 import android.view.MenuItem;
 14 import android.view.View;
 15 import android.view.View.OnClickListener;
 16 import android.view.ViewGroup;
 17 import android.widget.BaseAdapter;
 18 import android.widget.Button;
 19 import android.widget.ListView;
 20 import android.widget.TextView;
 21 import android.widget.Toast;
 22 
 23 
 24 public class MainActivity extends Activity {
 25 
 26     private String fromDb_str1 = "";
 27     private Button btn;
 28     private TextView tv;
 29     private ListView lv;
 30     private BaseAdapter adapter;
 31     private List<User> userList = new ArrayList<User>();
 32     private Runnable doInBackground1;
 33     private Runnable doInBackground2;
 34     
 35     //1.跟着主线程走,可以碰UI
 36     //2.能够接受子线程发送的消息(Message)
 37     //        子线程类本身不可以发信息
 38     private Handler handler;
 39     
 40     @Override
 41     protected void onCreate(Bundle savedInstanceState) {
 42         super.onCreate(savedInstanceState);
 43         setContentView(R.layout.activity_main);
 44         
 45         Log.i("UI_MainThread","id:"+Thread.currentThread().getId());
 46         
 47         
 48         //模拟数据访问产生数据
 49         for (int i = 0; i < 5; i++) {
 50             User u = new User();
 51             u.setUsername("小明"+i);
 52             u.setSex("女"+i);
 53             userList.add(u);
 54         }
 55         
 56         tv =(TextView)findViewById(R.id.textView1);
 57         btn =(Button)findViewById(R.id.button1);
 58         btn.setOnClickListener(new OnClickListener() {
 59             
 60             @Override
 61             public void onClick(View v) {
 62                 //1.访问数据库或者互联网(但会卡的)
 63                 //2.更新界面
 64                 Thread t1 = new Thread(doInBackground1);
 65                 t1.start();
 66                 
 67                 Thread t2 = new Thread(doInBackground2);
 68                 t2.start();
 69                 
 70             }
 71         });
 72         adapter = new BaseAdapter(){
 73 
 74             @Override
 75             public int getCount() {
 76                 // TODO Auto-generated method stub
 77                 return userList.size();
 78             }
 79 
 80             @Override
 81             public View getView(int position, View convertView, ViewGroup parent) {
 82                 LayoutInflater inflater = MainActivity.this.getLayoutInflater();
 83                 View view;
 84                 if (convertView==null){
 85                     view = inflater.inflate(R.layout.item, null);
 86                 }
 87                 else{
 88                     view = convertView;
 89                 }
 90                 
 91                 TextView tv_username = (TextView)view.findViewById(R.id.username);
 92                 TextView tv_sex = (TextView)view.findViewById(R.id.sex);
 93                 tv_username.setText(userList.get(position).getUsername());
 94                 tv_sex.setText(userList.get(position).getSex());
 95                 return view;
 96             }
 97             
 98             @Override
 99             public Object getItem(int position) {
100                 // TODO Auto-generated method stub
101                 return null;
102             }
103 
104             @Override
105             public long getItemId(int position) {
106                 // TODO Auto-generated method stub
107                 return 0;
108             }
109         };
110         lv = (ListView)findViewById(R.id.listView1);
111         lv.setAdapter(adapter);
112         
113         handler = new Handler(){
114             
115             //1.消息msg来自于子线程
116             //2.消息可以多个,采用msg.what识别
117             //3.处理消息,一般就会更新UI
118             //4.此方法可以参考onPostExecute
119             @Override
120             public void handleMessage(Message msg) {
121                 
122                 super.handleMessage(msg);
123                 int msgwhat = msg.what;
124                 Log.i("handler","已经收到消息,消息what:"+msgwhat+",id:"+Thread.currentThread().getId());
125                 
126                 if (msgwhat==1){
127                     //更新helloworld
128                     tv.setText("子线程让我更新"+msgwhat);
129                 }
130                 if (msgwhat==2){
131                     //更新ListView
132                     adapter.notifyDataSetChanged();
133                 }
134 
135             }
136             
137         };
138         
139         //子线程代码1
140         doInBackground1 = new Runnable() {
141             
142             @Override
143             public void run() {
144                 Log.i("sub_Thread","子线程1启动,id:"+Thread.currentThread().getId());
145                 
146                 try {
147                     Thread.sleep(3000);
148                 } catch (InterruptedException e) {
149                     // TODO Auto-generated catch block
150                     e.printStackTrace();
151                 }
152                 
153                 //1.访问数据库或者互联网,不在UI进程,所以不卡
154                 Message msg = new Message();
155                 //对消息一个识别号,便于handler能够识别
156                 msg.what = 1;
157                 handler.sendMessage(msg);
158                 Log.i("sub_Thread","子线程1已经发送消息给handler");
159             }
160         };
161         
162         
163         
164         //子线程代码1
165         doInBackground2 = new Runnable() {
166             
167             @Override
168             public void run() {
169                 Log.i("sub_Thread","子线程2启动,id:"+Thread.currentThread().getId());
170                 
171                 try {
172                     Thread.sleep(6000);
173                 } catch (InterruptedException e) {
174                     // TODO Auto-generated catch block
175                     e.printStackTrace();
176                 }
177                 
178                 Message msg = new Message();
179                 //对消息一个识别号,便于handler能够识别
180                 msg.what = 2;
181                 //handler.sendMessage(msg);
182                 handler.sendMessageDelayed(msg, 500);
183 
184                 
185                 //访问互联网,下载最新的,更新data,但不碰界面
186                 for (User user : userList) {
187                     user.setSex("不男不女");
188                 }
189                 
190                 Log.i("sub_Thread","子线程2已经发送消息给handler");
191             }
192         };
193         
194     }
195 }
196 
197     

效果图:

  点击button的时候如下图

上面就是一个小例子;但是上面的代码写的还有很多需要改进的地方,详情请参考(此链接为转载):

Android中使用Handler造成内存泄露的分析和解决http://www.linuxidc.com/Linux/2013-12/94065.htm

    

  

原文地址:https://www.cnblogs.com/mark0812/p/6136858.html