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");}


















    



0 0
原创粉丝点击