Handler 闪屏页小应用
来源:互联网 发布:淘宝月老祠堂怎么样 编辑:程序博客网 时间:2024/04/30 07:16
Handler
理解Handler的实现原理
在处理耗时操作时,需要使用单独的线程去处理(下载、上传、读大文件等),来防止这个操作阻塞UI线程(主线程)。
那我们在使用子线程的时候要注意的问题是:
不能在子线程中访问UI工具包(UI组件)API 15 android4.0后强制限制
目的是保正UI组件的线程安全。
那在Android中多个线程相互通讯的解决方法,可以使用Handler来完成。
1、通常我们会创建一个Handler的实现类,并重写handleMessage方法来处理消息
如:
Handler handler = new Handler(){ @Override public void handleMessage(Message msg) { super.handleMessage(msg); switch (msg.what){ case UPDATE_NUMBER: button_validNumber.setText(msg.arg1+"s"); break; case SUCCESS_NUMBER: button_validNumber.setText("获取验证码"); button_validNumber.setEnabled(true); break; } }}在子线程需要更新UI组件的地方,通过Handler来给UI线程发送一个消息: class MyThread implements Runnable{ @Override public void run() { for (int i=60;i>=0;i--){ //获取一个消息对象 Message m = handler.obtainMessage(); m.what = UPDATE_NUMBER; m.arg1 = i; handler.sendMessage(m);//发送消息 try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } //发送倒计时完成的消息 handler.sendEmptyMessage(SUCCESS_NUMBER); } }
2、Handler API使用:
<1>Message 对象:表示要传输的消息对象
what: 什么(用于要发送的消息对象的一个标记,处理时判断用)
arg1/arg2: 两个用于存放整数数据的变量(要发送的数据是整数时可以使用这两个变量存值)
obj:用于存放任何数据对象,本身是一个Object类型
handler.obtainMessage(); 获取一个消息对象(*****)
handler.sendEmptyMessage(); 发送一个不带数据的消息对象(*****)
handler.sendMessage(); 发送一个消息对象(*****)
handler.sendMessageAtTime(); 在指定时间发送一个消息对象
handler.sendMessageDelayed(); 延迟指定时间发送一个消息对象
handler.sendEmptyMessageAtTime(); 在指定时间发送一个不带数据的消息对象
handler.sendEmptyMessageDelayed(); 延迟指定时间发送一个不带数据的消息对象
发送一个消息,并把该消息对象添加到队列的最前面(插队),不建议使用
handler.sendMessageAtFrontOfQueue();
handler.post(); 把一个Runnable对象加入到对队中,依次执行,会主线程中。
3、Handler的实现原理:
面试题:阐述Handler的实现原理。
处理过程:
从handler中获取一个消息对象,把数据封装到消息对象中,通过handler的send...方法把消息
push到MessageQueue队列中,Looper对象会轮询MessageQueue队列,把消息对象取出,
通过dispatchMessage分发给Handler,再回调用Handler实现的handleMessage方法处理消息。
Handler的实现中适及以下对象:
1、Handler本身:负责消息的发送和处理
2、Message:消息对象
3、MessageQueue:消息队列(用于存放消息对象的数据结构)
4、Looper:消息队列的处理者(用于轮询消息队列的消息对象,
取出后回调handler的dispatchMessage进行消息的分发,dispatchMessage方法会回调
handleMessage方法把消息传入,由Handler的实现类来处理)
Message对象的内部实现是链表,最大长度是50,用于缓存消息对象,达到重复利用消息对象的目的,
以减少消息对象的创建,所以通常我们要使用obtainMessage方法来获取消息对象
Handler的消息处理机制是线程安全的
创建Handler时会创建Looper,Looper对象的创建又创建了MessageQueue
4、Handler导致的内存泄露问题分析
什么是内存泄露:
当一个对象A被其它对象B所引用,那么当B对象没有释放时,A对象不能被回收,那么A对象可能造成
内存泄露。
什么是内存溢出:
当一个应用程序内存泄露过多,或者内存不足时,程序会发生内存溢出,导致程序异常中断(崩了)
解决内存泄露来防止内存溢出的方法:
(1)在编写代码一定要注意是否存在内存泄露问题
(2)项目测试可以使用内存泄露的检查工具
在处理Handler的内存泄露方法:
(1)在结束Activity时,删除所有回调和消息处理
handler.removeCallbacksAndMessages(null);
(2)使用弱引用+静态
private static class MyHandler extends Handler{
//把所依赖的引用对象,使用弱引用,那么系统在内存不足时会优先回收该对象
private WeakReference<MainActivity> weakReference;
public MyHandler(MainActivity activity){
weakReference = new WeakReference<MainActivity>(activity);
}
@Override
public void handleMessage(Message msg) {
MainActivity activity = weakReference.get();
if (activity!=null){
activity.button_validNumber.setText("xxxx");
}
}
}
5、应用程序闪屏页
public class SplashActivity extends Activity { private Handler handler = new Handler(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_splash); handler.postDelayed(new Runnable() { @Override public void run() { start(); } },3000); } private void start() { startActivity(new Intent(this,MainActivity.class)); finish(); } @Override protected void onDestroy() { super.onDestroy(); handler = null; Log.i("handler","onDestroy"); }}
6、AsyncTask工具类的使用
实现一个异步任务可以使用Handler+线程,Android给我们提供了另一种更轻量级的实现方法
就是使用AsyncTask来完成。
AsyncTask是一个抽象类,通常我们需要去创建一个类继承AsyncTask来实现一个异步任务,
AsyncTask定义三个泛型参数类型:Params,Progress,Result
Params表示执行任务时需要参数类型
Progress表示执行任务时进度值的类型
Result表示任务完成后返回值的类型
这个三个参数分别在创建AsyncTask子类时通过泛型指定类型
//一个异步任务class MyAsyncTask extends AsyncTask<String,Integer,String>{ //此方法在UI线程中调用,实例化MyAsyncTask执行任务时开始调用,在方法中进行一些准备工作 @Override protected void onPreExecute() { super.onPreExecute(); textView_update.setText("开始更新..."); } //此方法在后台线程中执行,用来执行一个异步任务 @Override protected String doInBackground(String... params) { for (int i=0;i<=100;i++){ try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } publishProgress(i); //发布当前进度值,该方法会触发UI线程回调onProgressUpdate方法 } return "success"; } @Override protected void onProgressUpdate(Integer... values) { textView_update.setText("当前进度为:"+values[0]+"%"); } @Override protected void onPostExecute(String s) { textView_update.setText(s); } }
下载图片示例:
<1>布局文件中定义一个下载按钮和一个进度条组件:
<Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="下载" android:onClick="downloadClick" android:id="@+id/button2_download" android:layout_alignParentBottom="true" android:layout_alignParentEnd="true" android:layout_toEndOf="@+id/textView_update" /> <ProgressBar style="?android:attr/progressBarStyleHorizontal" android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/progressBar" android:visibility="gone" android:layout_above="@+id/button2_download" android:layout_centerHorizontal="true" android:layout_marginBottom="38dp" />
<2>定义一个下载的AsyncTask任务类:DownloadTask
//下载任务 class DownloadTask extends AsyncTask<String,Integer,String>{ @Override protected void onPreExecute() { super.onPreExecute(); progressBar.setProgress(0); progressBar.setVisibility(View.VISIBLE); } @Override protected String doInBackground(String... params) { try { URL url = new URL(params[0]); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); int contentLen = conn.getContentLength();//资源的总大小 publishProgress(FLAG_CONTENT_LEN,contentLen);//把资源的总大小更新到进度条上 BufferedInputStream in = new BufferedInputStream(conn.getInputStream()); BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(new File("/sdcard/Download/mm.jpg"))); int len = -1; byte[] bytes = new byte[1024]; while((len=in.read(bytes))!=-1){ out.write(bytes,0,len); publishProgress(FLAG_UPDATE_PROGRESS,len); } out.close(); in.close(); } catch (IOException e) { e.printStackTrace(); return "error"; } return "success"; } @Override protected void onPostExecute(String s) { if("success".equals(s)){ Toast.makeText(Main2Activity.this, "下载完成", Toast.LENGTH_SHORT).show(); }else if("error".equals(s)){ Toast.makeText(Main2Activity.this, "下载失败", Toast.LENGTH_SHORT).show(); } progressBar.setVisibility(View.GONE); } @Override protected void onProgressUpdate(Integer... values) { switch (values[0]){ case FLAG_UPDATE_PROGRESS: progressBar.incrementProgressBy(values[1]); break; case FLAG_CONTENT_LEN: progressBar.setMax(values[1]); break; } } }
<3>在Activity 中按钮单击事件中实现下载:
添加两个权限
<uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
两个标记常量
private static final int FLAG_CONTENT_LEN = 0x1; //用来设置进度条的总大小private static final int FLAG_UPDATE_PROGRESS = 0x2; //用来更新进度
private ProgressBar progressBar;progressBar = (ProgressBar) findViewById(R.id.progressBar);
//下载按钮事件public void downloadClick(View view){ //不能创建一个对象后反复执行execute,只能用一次 new DownloadTask().execute("http://f.hiphotos.baidu.com/image/h%3D200/sign=a2c37cfc0846f21fd6345953c6246b31/00e93901213fb80e0ee553d034d12f2eb9389484.jpg");}
- Handler 闪屏页小应用
- Handler消息应用相关
- Android Handler应用
- Handler 应用解析
- handler机制基础应用
- Handler的基本应用
- handler应用(1)
- handler的应用
- Handler应用: Activity 之间通过 Handler 通信
- Android 中handler 的应用
- Handler对象的Message应用
- 【android】android Handler应用详解
- Android中的Handler的应用
- Handler Looper MessageQueue的应用
- Handler机制的初级应用
- Android 中级应用 handler 之一 "那个年代还不知handler"
- Android 中级应用 handler 之二 初试handler
- Android 中级应用 handler 之二 深入handler
- ExecutorService线程池
- 多态
- ListView分页功能(2) 自定义View实现分页功能
- 数据结构之-栈(Java实现)
- session 如 mysql
- Handler 闪屏页小应用
- 当file_get_contents 或者 simplexml_load_file的时候乱码
- Android自定义Viewpager指示器PagerIndicator-仿微博头条效果
- USACO 4.2.1 iSap + gap优化
- JAVA实现快速排序
- 从头到尾彻底理解KMP
- NYOJ矩形的个数
- http请求状态码
- 190. Reverse Bits