2017-08-27
原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);
}
}