Handler简介
在Android开发中,我们常常使用单独的线程来完成某些操作,比如用一个线程来完成从网络上下载图片,然后显示在一个ImageView上,在多线程操作时,Android必须保证以下两点:
1、不要阻塞UI线程
2、不要再UI线程之外访问Android UI工具包
在两个线程中访问时使用handler
public class MainActivity extends AppCompatActivity {
private TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView) findViewById(R.id.textView);
}
private Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what){
case 100:
textView.setText("下载完成");
break;
}
}
};
public void downloadClick(View v){
//使用线程模拟下载操作
new Thread(new Runnable() {
@Override
public void run() {
while (true){
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
break;
}
// 下载完成后,更新UI状态
// 不可以在此访问textView,内部线程不可以访问UI线程
// textView.setText("下载完成");
//100存储到what中
handler.sendEmptyMessage(100);
// Message msg = handler.obtainMessage();//获取一个消息对象
// msg.what = 100;
// msg.obj = "要存储的信息";//任意类型都可以
// handler.sendMessage(msg);//发送消息
}
}).start();
}
}
Handler常用API
使用Handler可以完成以下两点工作:
1、消息调用和在将来的某个时间段执行一个Runnable
2、多个任务加入到一个队列中执行
//100存储到what中
handler.sendEmptyMessage(100);//发送一个空消息,标记为100
Message msg = handler.obtainMessage();//获取一个消息对象
msg.what = 100;
msg.obj = "要存储的信息";//任意类型都可以
handler.sendMessage(msg);//发送消息
handler.sendEmptyMessageAtTime(200,System.currentTimeMillis()+3000);//在指定时间后发送消息
handler.sendEmptyMessageDelayed(300,2000);//延迟多少时间后发送消息
Handler内部实现原理
handle机制
- 1、Message 消息对象,内部使用链表结果实现一个消息池,用于重复利用,避免大量创建消息对象,造成内存浪费
- 2、Handler 消息处理者,通过该对象把消息存入消息队列,并最好通过handlerManager方法处理消息
- 3、MessageQueue 消息队列,用于存储Message对象的数据结构,先进先出
- 4、Looper 消息队列的处理者,用于循环检测消息队列,从消息队列中一个一个的取出消息对象,传入HandlerMessage方法
Android启动程序时会在UI线程中创建一个MessageQueue
Handler内存泄漏分析
错误代码:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_handler_memorry);
//使用handler延迟执行一个runnable(10分钟)
handler.postDelayed(new Runnable() {
@Override
public void run() {
System.out.println("runnable");
}
},1000+60+10);
finish();//关闭当前Activity
}
private Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
}
};
正确代码:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_handler_memorry);
//使用handler延迟执行一个runnable(10分钟)
handler.postDelayed(new Runnable() {
@Override
public void run() {
System.out.println("runnable");
}
},1000+60+10);
finish();//关闭当前Activity
}
private MyHandler handler = new MyHandler(this);
//
private static class MyHandler extends Handler{
WeakReference<HandlerMemoryActivity> weakReference;
public MyHandler(HandlerMemoryActivity activity){
weakReference = new WeakReference<HandlerMemoryActivity>(activity);
}
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
HandlerMemoryActivity activity = weakReference.get();
if(activity!=null){
// tv.setText();
}
}
}
使用Handler实现APP的闪屏页
闪屏页的作用
- 1、提供欢迎界面
- 2、初始化工作
在清单文件中添加android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_splash);
handler.postDelayed(new Runnable() {
@Override
public void run() {
startMainActivity();
}
},3000);
}
private void startMainActivity(){
Intent intent = new Intent(this,MainActivity.class);
startActivity(intent);
}
private Handler handler = new Handler();
AsyncTask
适用于简单的异步处理,不需要借助线程和Handler即可使用,AsyncTask是抽象类,定义了三种泛型类型:
*Params启动任务执行的输入参数,比如HTTP请求的URL
*Progress后台任务执行的百分比
*Result后台执行任务最终返回的结果,比如String
public class MainActivity2 extends AppCompatActivity {
private TextView info;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
info = (TextView)findViewById(R.id.info);
}
public void asyncTaskClick(View v){
new MyAsyncTask(this).execute();
}
/***
* 通过一个AsyncTask实现一个异步任务
* 第三个值是doInBackground的返回值类型
*/
private static class MyAsyncTask extends AsyncTask<String,Integer,String>{
private MainActivity2 activity;
public MyAsyncTask(MainActivity2 activity){
this.activity = activity;
}
//执行任务之前触发的事件方法,可以在该方法中作一些初始化工作
@Override
protected void onPreExecute() {
super.onPreExecute();
System.out.println("onPreExecute");
activity.info.setText("开始执行任务。。。");
}
//执行后台任务的方法,类似于线程,所以不能在该方法中访问UI组件
@Override
protected String doInBackground(String... strings) {
for(int i=0;i<10;i++){
System.out.println(i);
publishProgress(i);//更新进度
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return "success";
}
//更新进度值
@Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
activity.info.setText("档期的值为"+values[0]);
}
//当doInBackground方法返回后被调用
@Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
activity.info.setText(s);
}
}
}
AsyncTask-下载文件示例
public void downloadClick(View v){
new DownloadAsyncTask(this).execute("");//图片下载地址
}
private static class DownloadAsyncTask extends AsyncTask<String,Integer,Integer>{
private MainActivity2 activity;
public DownloadAsyncTask(MainActivity2 activity){
this.activity = activity;
}
//初始
@Override
protected void onPreExecute() {
super.onPreExecute();
activity.pb.setProgress(0);
}
@Override
protected Integer doInBackground(String... strings) {
String s = strings[0];
try {
URL url = new URL(s);
//打开链接
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
int size = conn.getContentLength();//获取文件大小
//0表示需要更新的最大进度值,1表示更新档期下载的进度值
publishProgress(0,size);
byte[] bytes = new byte[20];
int len = -1;
InputStream in = conn.getInputStream();
FileOutputStream out = new FileOutputStream("/sdcard/"+System.currentTimeMillis()+".jpg");//图片存储地址
while ((len=in.read(bytes))!=-1){
out.write(bytes,0,len);
publishProgress(1,len);//更新进度
out.flush();
// Thread.sleep(500);
}
out.close();
in.close();
} catch (MalformedURLException e) {
e.printStackTrace();
}catch (IOException e){
e.printStackTrace();
}
return 200;
}
@Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
switch (values[0]){
case 0:
activity.pb.setMax(values[1]);
break;
case 1:
activity.pb.incrementProgressBy(values[1]);
break;
}
}
@Override
protected void onPostExecute(Integer integer) {
super.onPostExecute(integer);
if(integer == 200){
activity.info.setText("下载完成");
}
}
}