原CSDN博客已弃用,文章会逐渐迁移过来。

一、异步下载更新进度条

activity_down_load.xml

<?xml version="1.0" encoding="utf-8"?>  
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
    android:orientation="vertical"  
    android:layout_width="match_parent"  
    android:layout_height="match_parent">  

    <Button  
        android:layout_width="wrap_content"  
        android:layout_height="wrap_content"  
        android:text="New Button"  
        android:id="@+id/button"/>  

    <ProgressBar  
        style="?android:attr/progressBarStyleHorizontal"  
        android:layout_width="match_parent"  
        android:layout_height="wrap_content"  
        android:id="@+id/progressBar"  
        android:max="100"  
        android:layout_gravity="center_horizontal"/>  
</LinearLayout>  

DownloadActivity.java

package com.administrator.handlerproject;  
import android.app.Activity;  
import android.os.Bundle;  
import android.os.Environment;  
import android.os.Handler;  
import android.os.Message;  
import android.view.View;  
import android.widget.ProgressBar;  

import java.io.File;  
import java.io.FileOutputStream;  
import java.io.IOException;  
import java.io.InputStream;  
import java.io.OutputStream;  
import java.net.MalformedURLException;  
import java.net.URL;  
import java.net.URLConnection;  

public class DownloadActivity extends Activity {  

    private Handler mHandler;  
    public static final int DOWNLOAD_MESSAGE_CODE = 100001;  
    public static final int DOWNLOAD_MESSAGE_FAIL_CODE = 100002;  

    @Override  
    public void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.activity_down_load);  

        final ProgressBar progressBar = (ProgressBar)findViewById(R.id.progressBar);  

        /** 
         * 主线程 -->start 
         * 点击按钮 | 
         * 发起下载 | 
         * 开启子线程做下载 | 
         * 下载完成后通知主线程 | -->主线程更新进度条 
         */  

        findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {  
            @Override  
            public void onClick(View v) {  
                new Thread(new Runnable() {  
                    @Override  
                    public void run() {  
                        download("http://download.sj.qq.com/upload/connAssitantDownload/upload/MobileAssistant_1.apk");  
                    }  
                }).start();  

            }  
        });  

        mHandler =  new Handler(){  
            @Override  
            public void handleMessage(Message msg) {  
                super.handleMessage(msg);  

                switch (msg.what){  
                    case DOWNLOAD_MESSAGE_CODE:  
                        progressBar.setProgress((Integer) msg.obj);  
                    case DOWNLOAD_MESSAGE_FAIL_CODE:  
                }  
            }  
        };  
    }  
    private void download(String appUrl){  
        try {  
            URL url = new URL(appUrl);  
            URLConnection urlConnection = url.openConnection();  

            InputStream inputStream = urlConnection.getInputStream();  

            /** 
             * 获取文件的总长度 
             */  
            int contentLength = urlConnection.getContentLength();  

            String downloadFolderName = Environment.getExternalStorageDirectory()  
                    + File.separator+"imooc"+File.separator;  

            File file = new File(downloadFolderName);  
            if (!file.exists()){  
                file.mkdir();  
            }  

            String fileName = downloadFolderName + "imooc.apk";  

            File apkFile = new File(fileName);  

            if (apkFile.exists()){  
                apkFile.delete();  
            }  

            int downloadSize = 0;  
            byte[] bytes = new  byte[1024];  

            int length = 0;  

            OutputStream outputStream = new FileOutputStream(fileName);  
            while ((length = inputStream.read(bytes)) != -1){  
                outputStream.write(bytes,0,length);  
                downloadSize += length;  
                /** 
                 * update UI 
                 */  

                Message message = Message.obtain();  
                message.obj = downloadSize * 100 / contentLength;  
                message.what = DOWNLOAD_MESSAGE_CODE;  
                mHandler .sendMessage(message);  
            }  
            inputStream.close();  
            outputStream.close();  





        }catch (MalformedURLException e){  
            notifyDownloadFaild();  
            e.printStackTrace();  
        }catch (IOException e){  
            notifyDownloadFaild();  
            e.printStackTrace();  
        }  
    }  

    private  void  notifyDownloadFaild(){  
        Message message = Message.obtain();  
        message.what = DOWNLOAD_MESSAGE_FAIL_CODE;  
        mHandler .sendMessage(message);  
    }  
}  

二、倒计时效果(内存泄漏处理)

当Activity被销毁的时候,被延时的消息会在被处理之前存在于主线程的消息队列中,而这个消息中又包含了Handler的引用,而Handler是一个匿名内部类的实例,其持有外面的MainActivity的引用。这些引用会一直保持到该消息被处理,从而阻止了MainActivity被垃圾回收器回收。因此这就导致了MainActivity无法被回收,进而导致MainActivity持有的很多资源都无法回收,这就是我们常说的内存泄漏。

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>  
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"  
    xmlns:app="http://schemas.android.com/apk/res-auto"  
    xmlns:tools="http://schemas.android.com/tools"  
    android:layout_width="match_parent"  
    android:layout_height="match_parent"  
    tools:context="com.administrator.handlerxuexi.MainActivity">  

    <TextView  
        android:id="@+id/countdownTimeTextView"  
        android:layout_width="wrap_content"  
        android:layout_height="wrap_content"  
        android:text="@null"  
        app:layout_constraintBottom_toBottomOf="parent"  
        app:layout_constraintLeft_toLeftOf="parent"  
        app:layout_constraintRight_toRightOf="parent"  
        app:layout_constraintTop_toTopOf="parent" />  

</android.support.constraint.ConstraintLayout>  

MainActivity.java

package com.administrator.handlerxuexi;  

import android.os.Handler;  
import android.os.Message;  
import android.support.v7.app.AppCompatActivity;  
import android.os.Bundle;  
import android.widget.TextView;  

import java.lang.ref.WeakReference;  

public class MainActivity extends AppCompatActivity {  

    /** 
     * 倒计时标记handle code 
     */  
    public  static  final  int COUNTDOWN_TIME_CODE = 100001;  
    /** 
     * 倒计时间隔 
     */  
    public  static  final  int  DELAY_MILLIS = 1000;  
    /** 
     * 倒计时最大值 
     */  
    public  static  final  int  MAX_COUNT = 10;  


    private TextView mCountdownTimeTextView;  


    @Override  
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.activity_main);  

        //得到控件  
        mCountdownTimeTextView= (TextView)findViewById(R.id.countdownTimeTextView);  

        //创建了一个handler  
        CountdownTimeHandler handler = new CountdownTimeHandler(this);  

//        Handler handler = new Handler(){}强引用会出现内存泄漏,  
        //新建了一个message  
        Message message = Message.obtain();  
        message.what = COUNTDOWN_TIME_CODE;  
        message.arg1 = MAX_COUNT;  

        //第一次发送这个message  
        handler.sendMessageDelayed(message,DELAY_MILLIS);  

    }  

    /** 
     * 创建弱引用的CountdownTimeHandler类继承Handler 
     *  
     */  
    public  static  class  CountdownTimeHandler extends Handler{  
        static  final  int  MIN_COUNT = 0;  
        final WeakReference<MainActivity> mWeakReference;//括号内参数是当前Activity对象  

        CountdownTimeHandler(MainActivity activity){//括号内参数是当前Activity对象  
            mWeakReference = new WeakReference<> (activity );  
        }  

        @Override  
        public void handleMessage(Message msg) {  
            super.handleMessage(msg);  
            //创建一个当前的Activity接收  
            MainActivity activity =mWeakReference.get();//获得上面CountdownTimeHandler内定义的mWeakReference对象  

            switch (msg.what){  
                case COUNTDOWN_TIME_CODE:  
                    int value = msg.arg1;  
                    activity.mCountdownTimeTextView.setText(String.valueOf(value --));  

                    //循环发的消息控制  
                    if (value >= MIN_COUNT) {  
                        Message message = Message.obtain();  
                        message.what = COUNTDOWN_TIME_CODE;  
                        message.arg1 = value;  
                        sendMessageDelayed(message, DELAY_MILLIS);  
                    }  

                    break;  
            }  
        }  
    }  
}  

三、用Handler实现打地鼠游戏

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>  
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
    android:layout_width="match_parent"  
    android:layout_height="match_parent"  
    android:background="#FFFFFF">  

    <ImageView  
        android:id="@+id/image_view"  
        android:layout_width="80dp"  
        android:layout_height="80dp"  
        android:src="@mipmap/ic_launcher"  
        android:visibility="gone"/>  

    <Button  
        android:id="@+id/start_button"  
        android:layout_width="wrap_content"  
        android:layout_height="wrap_content"  
        android:layout_alignParentBottom="true"  
        android:layout_centerHorizontal="true"  
        android:text="点击开始"/>  

    <TextView  
        android:id="@+id/text_view"  
        android:layout_width="wrap_content"  
        android:layout_height="wrap_content"  
        android:layout_centerHorizontal="true"  
        android:layout_centerVertical="true"  
        android:textAppearance="?android:attr/textAppearanceLarge"/>  

</RelativeLayout>  

MainActivity.java

package com.administrator.diglett;  

import android.app.Activity;  
import android.content.DialogInterface;  
import android.os.Handler;  
import android.os.Message;  
import android.support.v7.app.AppCompatActivity;  
import android.os.Bundle;  
import android.view.MotionEvent;  
import android.view.View;  
import android.widget.Button;  
import android.widget.ImageView;  
import android.widget.TextView;  
import android.widget.Toast;  

import java.lang.ref.WeakReference;  
import java.util.Random;  

public class MainActivity extends AppCompatActivity implements View.OnClickListener,View.OnTouchListener{  


    public static final int CODE = 123;  
    private TextView mResultTextView;  
    private ImageView mDiglettImageView;  
    private Button mStarrButton;  

    public int[][] mPosition = new  int[][]{  
            {342,180},{432,880},  
            {521,256},{429,780},  
            {456,976},{145,665},  
            {123,678},{564,567},  
    };  

    private  int mTotalCount;  
    private  int mSuccessCount;  

    public static final int MAX_COUNT = 10;  

    private DialettHandler mHandler = new DialettHandler(this);  
    @Override  
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.activity_main);  
        initView();  

        setTitle("打地鼠");  
    }  

    private void initView(){  
        mResultTextView = (TextView)findViewById(R.id.text_view);  
        mDiglettImageView = (ImageView)findViewById(R.id.image_view);  
        mStarrButton = (Button)findViewById(R.id.start_button);  

        mStarrButton.setOnClickListener(this);  
        mDiglettImageView.setOnTouchListener(this);  
    }  

    @Override  
    public void onClick(View v) {  
        switch (v.getId()){  
            case R.id.start_button:  
            start();  
            break;  
        }  
    }  

    private void start() {  
        //发送消息 handler.sendmessagedelayer  
        mResultTextView.setText("开始啦");  
        mStarrButton.setText("游戏中.....");  
        mStarrButton.setEnabled(false);  
        next(0);  
    }  
    private void next(int delayTime){  
        //让地鼠每次都会有下一个  
        int position = new Random().nextInt(mPosition.length);  

        Message message = Message.obtain();  

        message.what = CODE;  
        message.arg1 = position;  

        mHandler.sendMessageDelayed(message,delayTime);  
        mTotalCount ++;  
    }  

    @Override  
    public boolean onTouch(View v, MotionEvent event) {  
        v.setVisibility(View.GONE);  
        mSuccessCount ++;  
        mResultTextView.setText("打到了"+mSuccessCount + "只,共" +(MAX_COUNT-1) + "只");  
        return false;  
    }  

    /** 
     * 创建弱引用的CountdownTimeHandler类继承Handler来处理Handler的内存泄漏问题 
     */  
    public static class DialettHandler extends Handler{  
        public static final int RANDOM_NUBER = 500;  
        public final WeakReference<MainActivity> mWeakReference;//括号内参数是当前Activity对象  

        public DialettHandler(MainActivity activity) {//括号内参数是当前Activity对象  
            mWeakReference = new WeakReference<>(activity);  
        }  

        @Override  
        public void handleMessage(Message msg) {  
            super.handleMessage(msg);  
            //创建一个当前的Activity接收  
            MainActivity activity = mWeakReference.get();//拿到上面的Activity  
            switch (msg.what){  
                case CODE:  
                    if(activity.mTotalCount>MAX_COUNT){  
                        activity.clear();  
                        Toast.makeText(activity,"地鼠打完了!",Toast.LENGTH_LONG).show();  
                        return;  
                    }  
                    int position =msg.arg1;  
                    activity.mDiglettImageView.setX(activity.mPosition[position][0]);  
                    activity.mDiglettImageView.setY(activity.mPosition[position][1]);  
                    activity.mDiglettImageView.setVisibility(View.VISIBLE);  

                    int randomTime = new Random().nextInt(RANDOM_NUBER) + RANDOM_NUBER;  
                    activity.next(randomTime);  

                    break;  
            }  
        }  
    }  

    private void clear() {  
        mTotalCount = 0;  
        mSuccessCount = 0;  
        mDiglettImageView.setVisibility(View.GONE);  
        mStarrButton.setText("点击开始");  
        mStarrButton.setEnabled(true);  
    }  
}