背景:
1.主线程(UI线程):主要负责UI更新,为了提高性能,Android的UI线程是不安全的,子线程无法直接更新UI
2.消息循环机制:UI线程是个死循环
应用:1.定时任务
2.线程与线程交互
handler方法使用:
简单使用:子线程通知UI更新
public class MainActivity extends AppCompatActivity { protected Handler handler; protected TextView textView; @SuppressLint("HandlerLeak") @Override protected void onCreate(Bundle savedInstanceState) { /* UI线程 */ super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); textView = findViewById(R.id.textView); handler = new Handler(){ @Override public void handleMessage(Message msg) { super.handleMessage(msg); //主线程接受到子线程发送的消息,更新数据 if(msg.what == 1001011){ textView.setText("消息"); } } }; findViewById(R.id.button).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { //又可能做大量耗时操作如下载文件 new Thread(){ @Override public void run() { //子线程发送消息 handler.sendEmptyMessage(1001011); } }.start(); } }); } }
如果在子线程中直接更新UI:
则会提示异常信息:只有在主线程中才能更新view
常用方法:
//使用obtain实例化Message(建议),会做一个缓存 Message message = Message.obtain(); //标识,相当于密码箱的密码,int类型 message.what = 10010; message.arg1 = 10011; message.arg2 = 10012; //对象,可以是上下文 message.obj = MainActivity.this; //空消息 handler.sendEmptyMessage(1001013); //约定一个时间发送,绝对时间 准时发送 handler.sendMessageAtTime(message,6000); //相对时间 XX秒后发送 handler.sendMessageDelayed(message,2000); //发送一个可执行程序,立即发出 Runnable runnable = new Runnable() { @Override public void run() { int a = 1 + 3; } }; handler.post(runnable); //执行程序时使用run方法 runnable.run(); //定时任务 handler.postAtTime(runnable,2000);
Demo:
1.下载文件并更新进度条
public class DownActivity extends AppCompatActivity { public static final int INT = 1001011; protected ProgressBar progressBar; protected Handler handler; private static final String TAG = "DownActivity"; protected int progress; @SuppressLint("HandlerLeak") @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_down); findViewById(R.id.button2).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { downData(); } }); progressBar = findViewById(R.id.progressBar); /** * UI线程接收消息 */ handler = new Handler(){ @Override public void handleMessage(Message msg) { super.handleMessage(msg); if (msg.what == INT){ Log.e(TAG, "handleMessage: "+ "判断成功" ); progress = (Integer) msg.obj; //设置进度条进度 progressBar.setProgress(progress); } } }; } private void downData() { /** * 子线程,下载文件 */ new Thread(new Runnable() { @Override public void run() { try { URL url = new URL("https://clfile.imooc.com/class/assist/119/4289211/Handler%E6%BA%90%E7%A0%81(%E4%BB%A3%E7%A0%81%E7%BB%8F%E8%BF%87%E5%B0%81%E8%A3%85).rar"); HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection(); InputStream inputStream = httpURLConnection.getInputStream(); //获取文件总长度 int filesize = httpURLConnection.getContentLength(); //下载文件夹名称 String downloadFolderName = Environment.getExternalStorageDirectory() + File.separator + "我的下载文件" + File.separator; File file = new File(downloadFolderName); //如果文件夹不存在,则创建 if(!file.exists()){ file.mkdir(); } //下载文件名 String filename = downloadFolderName + "源代码"; File file1 = new File(filename); if(file1.exists()){ file1.delete(); } //已下载文件长度 int downsize = 0; int len = 0; byte[] b = new byte[1024*10]; OutputStream outputStream= new FileOutputStream(filename); while ((len = inputStream.read(b)) != -1){ outputStream.write(b,0,len); downsize += len; Message message = Message.obtain(); message.obj = downsize*100/filesize; message.what = INT; handler.sendMessage(message); } } catch (MalformedURLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }).start(); } }
下载网络图片,通过handle更新ImageView控件显示图片
public class PicActivity extends AppCompatActivity { MyHandler2 myHandler2 = new MyHandler2(this); protected ImageView imageView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_pic); imageView = findViewById(R.id.imageView); findViewById(R.id.button3).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { getPicture(); } }); } void getPicture(){ new Thread(new Runnable() { @Override public void run() { try { URL url = new URL("https://img2.mukewang.com/5adfee7f0001cbb906000338-240-135.jpg"); HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection(); httpURLConnection.setRequestMethod("GET"); httpURLConnection.setConnectTimeout(5000); if (httpURLConnection.getResponseCode() ==200){ InputStream inputStream = httpURLConnection.getInputStream(); //获取流 Bitmap bitmap = BitmapFactory.decodeStream(inputStream); Message message = Message.obtain(); message.what = 10010; message.obj = bitmap; //发送消息 myHandler2.sendMessage(message); } } catch (MalformedURLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }).start(); } /** * 静态 弱引用 handle 避免发生内存泄漏 * 当handle持有PicActivity的引用也能被回收 */ static class MyHandler2 extends Handler{ WeakReference<PicActivity> weakReference; private MyHandler2(PicActivity activity) { this.weakReference =new WeakReference<>(activity); } @Override public void handleMessage(Message msg) { super.handleMessage(msg); //获取当前activity PicActivity picActivity = weakReference.get(); switch (msg.what){ case 10010: Bitmap bitmap = (Bitmap) msg.obj; picActivity.imageView.setImageBitmap(bitmap); } } } }
通过handle更新显示内容,通过延迟发送sendMessageDelayed,实现倒计时功能
public class TimeActivity extends AppCompatActivity { public static final int MAX = 10; public static final int CODE = 10010; protected TextView textView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_time); textView = findViewById(R.id.textView2); MyHandler myHandler = new MyHandler(this); Message message = Message.obtain(); message.what = 10010; message.arg1 = MAX; myHandler.sendMessageDelayed(message, 1000); } public static class MyHandler extends Handler { WeakReference<TimeActivity> weakReference; private MyHandler(TimeActivity activity) { this.weakReference = new WeakReference<>(activity); } @Override public void handleMessage(Message msg) { super.handleMessage(msg); int value = 0; TimeActivity timeActivity = weakReference.get(); if (msg.what == 10010) { value = msg.arg1; timeActivity.textView.setText(String.valueOf(value--)); } //实现消息循环发送,直至不满足条件 if (value > 0) { Message message = Message.obtain(); message.what = 10010; message.arg1 = value; sendMessageDelayed(message, 1000); } } } }