3-15笔记 待整理 Handler AsyncTask

来源:互联网 发布:加工中心宏程序编程 编辑:程序博客网 时间:2024/05/16 23:52
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");
}









0 0
原创粉丝点击