Android 之路37---Handler

导读

1.一些重要的Studio技巧
2.Android 6.0动态权限申请
3.对Handler的说明
4.使用Handler的实现和优化
5.打地鼠案例

一些重要的Studio技巧

⚠️查看一个类的快捷键 command+单击
⚠️快速将局部变量变成全局变量 command+alt+t

⚠️更多技巧见 Android 之路31—关于AndroidStudio的1,2,3

Android 6.0动态权限申请


这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述

对Handler的说明

这里写图片描述

MessageQueue是一个线程队列,里边是要执行的线程,而Looper相当于一个抽水机,把线程从队列里抽出来,抽出的线程交给handlerMessage处理,或者交给run去执行,所以handler就是处理不同线程的一种机制

子线程使用Handler要如下编写

Looper.prepare();
Handler handler=new Handler();
Looper.loop();

使用Handler的实现和优化

Handler常用方法

activity_main.xml

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

    <TextView
        android:id="@+id/header"
        android:layout_width="match_parent"
        android:layout_height="48dp"
        android:text="Emilia Clarke"
        android:textSize="28sp"
        android:gravity="center"
        android:textColor="#ffffff"
        android:background="#3f51b5"
        android:paddingRight="15dp"/>

    <Button
        android:id="@+id/bt"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:text="点击"/>


</LinearLayout>

MainActivity.java

package com.hala.view01;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.TextView;

import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;

import org.json.JSONException;
import org.json.JSONObject;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;


/*
线程间通信
1。主线程(UI线程)执行轻量级任务
2。new 的新线程 执行下载等耗时任务
3。下载完成后通知主线程进行后续操作
 */


public class MainActivity extends Activity {


    public static final String TAG = "MainActivity";

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        final TextView tx=(TextView)findViewById(R.id.header);

        //创建Handler
        final Handler handler=new Handler(){
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                //处理消息
                Log.d(TAG,"handleMessage:"+msg.what);

                if(msg.what==1002){
                    tx.setText(""+msg.obj);
                }
            }
        };

        findViewById(R.id.bt).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //有可能消耗大量时间,比如下载
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                   /*     try {
                            //这里用休眠来表示耗时操作
                            Thread.sleep(4000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }*/
                        //发送空消息,只有一个代号但没有实质内容
                        handler.sendEmptyMessage(1001);

                        //以下都是android系统写好的参数
                        Message message=Message.obtain();
                        message.what=1002;
                        message.arg1=1;
                        message.arg2=2;
                        message.obj="Neymar";
                        handler.sendMessage(message);

                    //两个方法实现效果相同,但方法不同    handler.sendMessageAtTime(message,SystemClock.uptimeMillis()+3000);
                        handler.sendMessageDelayed(message,3000);
                    }
                }).start();
            }
        });

    }

}

java强引用与弱引用的说明

这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述

Handler防止内存泄漏的优化以及倒计时实现

Manifest文件

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.hala.view01">

    <!-- 网络链接,写文件和读文件的权限 -->
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity"></activity>
        <activity android:name=".Main2Activity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

布局文件 activity_main2

<?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.hala.view01.Main2Activity">


    <TextView
        android:id="@+id/textView"
        android:layout_width="111dp"
        android:layout_height="71dp"
        android:text="TextView"
        app:layout_constraintTop_toTopOf="parent"
        android:layout_marginTop="8dp"
        app:layout_constraintBottom_toBottomOf="parent"
        android:layout_marginBottom="8dp"
        android:layout_marginLeft="8dp"
        app:layout_constraintLeft_toLeftOf="parent"
        android:layout_marginRight="8dp"
        app:layout_constraintRight_toRightOf="parent"
        tools:layout_editor_absoluteY="194dp"
        android:gravity="center"
        android:textSize="20sp"/>


</android.support.constraint.ConstraintLayout>

Main2Activity

package com.hala.view01;

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 Main2Activity extends AppCompatActivity {


    private TextView tv;

    public static final int MIN = 0;
    public static final int MAX = 10;
    public static final int Code = 10001;
    public static final int sendTime = 1000;

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


         tv=(TextView)findViewById(R.id.textView);

        //这里参数要传上下文
        wHandler handler=new wHandler(this);

        Message message=Message.obtain();
        message.what=Code;
        message.arg1=MAX;
        handler.sendMessageDelayed(message,sendTime);
    }

    /**
     * 这里是自己创建的静态Handler的弱引用,目的是防止内存泄露
     */

    public static class wHandler extends Handler{
        final WeakReference<Main2Activity> mWeaker;

        public wHandler(Main2Activity activity) {
            mWeaker=new WeakReference<>(activity);
        }

        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            //此句获取了当前Activity的弱引用
            Main2Activity activity=mWeaker.get();

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

                    //这里是一个循环发送直到达到条件
                    if (value>= MIN) {
                        //这里Message必须要从消息池里再取一个,目的是将value发回arg1去
                        Message message=Message.obtain();
                        message.what=Code;
                        message.arg1=value;
                        sendMessageDelayed(message,sendTime);
                    }
                    break;

            }
        }
    }
}

显示结果

这里写图片描述

下载文件时Handler的运用

配置文件

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.hala.view01">

    <!-- 网络链接,写文件和读文件的权限 -->
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity android:name=".Main2Activity">
        </activity>
    </application>

</manifest>

布局文件

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

    <ProgressBar
        android:id="@+id/progressBar"
        style="?android:attr/progressBarStyleHorizontal"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:max="100"/>

    <Button
        android:id="@+id/bt"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:text="点击"/>

    <TextView
        android:id="@+id/tv"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="30sp"/>


</LinearLayout>

java文件

package com.hala.view01;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.ProgressBar;
import android.widget.TextView;

import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;

import org.json.JSONException;
import org.json.JSONObject;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;


public class MainActivity extends Activity {

    public static final String APP_URL = "http://download.sj.qq.com/upload/connAssitantDownload/upload/MobileAssistant_1.apk";
    public static final int INT1 = 1002;
    ProgressBar pb=(ProgressBar)findViewById(R.id.progressBar);
    TextView tv=(TextView)findViewById(R.id.tv);
    Handler M_HANDLER;
    public static final int INT = 1001;

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

        /*
        1.主线程->start
        2.点击按键发起下载
        3.开启子线程做下载
        4.下载过程中通知主线程更新进度条
         */

        findViewById(R.id.bt).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                new Thread(new Runnable() {
                    @Override
                    public void run() {

                        download(APP_URL);

                    }
                }).start();
            }
        });

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

                switch (msg.what){
                    case INT:
                        pb.setProgress((Integer)msg.obj);
                        break;
                    case  INT1:
                        tv.setText("下载失败");
                        break;
                }

            }
        };

    }

    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+"Emilia Clarke"+File.separator;
            File file=new File(downloadFolderName);
            if(!file.exists()){
                file.mkdir();
            }

            String fileName=downloadFolderName+"emilia.apk";
            File apkfile=new File(fileName);
            if(apkfile.exists()){
                apkfile.delete();
            }


            int downloadSize=0;
            byte[] b=new byte[1024];
            int length;

            OutputStream outputStream=new FileOutputStream(fileName);
            while((length=inputStream.read(b))!=-1){
                outputStream.write(b,0,length);
                downloadSize+=length;



                Message message=Message.obtain();
                message.obj=downloadSize*100/contentLength;
                message.what= INT;
                M_HANDLER.sendMessage(message);

            }

            inputStream.close();
            outputStream.close();

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

    private void notifyDownloadFile() {
        Message message=Message.obtain();
        message.what= INT1;
        M_HANDLER.sendMessage(message);
    }


}

打地鼠案例

布局文件

?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.hala.view01.Main2Activity">

<RelativeLayout
    android:id="@+id/rl"
    android:layout_width="368dp"
    android:layout_height="439dp"
    android:layout_marginLeft="8dp"
    app:layout_constraintLeft_toLeftOf="parent"
    android:layout_marginRight="8dp"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintTop_toTopOf="parent"
    android:layout_marginTop="8dp"
    android:layout_marginBottom="8dp"
    app:layout_constraintBottom_toTopOf="@+id/button">

    <ImageView
        android:id="@+id/iv"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:src="@drawable/timg"
        android:visibility="gone"/>
</RelativeLayout>

    <Button
        android:onClick="onClick"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginLeft="8dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        android:layout_marginBottom="0dp"
        android:text="开始"
        android:id="@+id/button"
        app:layout_constraintHorizontal_weight="1"
        android:layout_marginStart="8dp" />

    <TextView
        android:id="@+id/tv"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="分数"
        android:textSize="25sp"
        android:gravity="center"

        app:layout_constraintBottom_toBottomOf="parent"
        android:layout_marginBottom="8dp"
        app:layout_constraintTop_toTopOf="@+id/button"
        android:layout_marginTop="8dp"
        android:layout_marginRight="8dp"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintHorizontal_weight="1"
        android:layout_marginEnd="8dp"
        app:layout_constraintLeft_toRightOf="@+id/button"
        android:layout_marginLeft="8dp" />


</android.support.constraint.ConstraintLayout>

java文件

package com.hala.view01;

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.RelativeLayout;
import android.widget.TextView;

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

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


    public static final int Code = 123;
    public static final int Rand = 500;
    public static final int MAX = 10;
    private TextView tv;
    private Button bt;
    private ImageView iv;
    private RelativeLayout rl;


    private int total;
    private int success;

    private DiglettHandler diglettHandler=new DiglettHandler(this);


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main2);
        setTitle("打我呀");
        initView();
    }

    private void initView() {
        tv = (TextView)findViewById(R.id.tv);
        bt = (Button)findViewById(R.id.button);
        iv = (ImageView)findViewById(R.id.iv);
        rl = (RelativeLayout)findViewById(R.id.rl);
        bt.setOnClickListener(this);
        iv.setOnTouchListener(this);

        //此句容易漏掉
        DiglettHandler diglettHandler=new DiglettHandler(this);

    }


    /**
     * 点击按钮开始游戏
     * @param v
     */
    @Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.button:
                start();
                break;
        }
    }

    /**
     * 开始打第一个地鼠
     * 发送消息
     */
    private void start() {

        total=0;
        success=0;
        bt.setText("游戏中。。。");
        bt.setEnabled(false);

        next(0);
    }

    /**
     * 打第一个以后的地鼠
     * @param delayTime
     */
    private void next(int delayTime){
        //Random().nextInt(368)表示生成0~368的随机数,包括0,不包括368
        int x=new Random().nextInt(368);
        int y=new Random().nextInt(439);

        Message message=Message.obtain();
        message.what= Code;
        message.arg1=x;
        message.arg2=y;

        diglettHandler.sendMessageDelayed(message,delayTime);
        total++;
    }

    /**
     * 游戏结束的反应
     */
    private void clear(){
        iv.setVisibility(View.GONE);
        bt.setText("开始");
        bt.setEnabled(true);

    }

    /**
     * 打中地鼠后的反应
     * @param v
     * @param event
     * @return
     */
    @Override
    public boolean onTouch(View v, MotionEvent event) {

        //地鼠为不可见
        v.setVisibility(View.GONE);
        success++;
        return true;
    }

    public static class DiglettHandler extends Handler{

        public final WeakReference<Main2Activity> mWeaker;

        public DiglettHandler(Main2Activity activity) {
            mWeaker=new WeakReference<Main2Activity>(activity);

        }


        /**
         * 点击屏幕后的处理机制
         * @param msg
         */
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            Main2Activity activity=mWeaker.get();

            switch (msg.what){
                case Code:
                    if(activity.total> MAX){
                        activity.clear();
                        return;
                    }
                    int x=msg.arg1;
                    int y=msg.arg2;
                    activity.iv.setX(x);
                    activity.iv.setY(y);
                    //默认为不显示,这里要显示出来
                    activity.iv.setVisibility(View.VISIBLE);
                    activity.tv.setText("打到"+activity.success+"只,漏掉"+(activity.total-activity.success)+"只哦");
                    //传回随机时间,执行next方法
                    int randomTime=new Random().nextInt(Rand)+ Rand;
                    activity.next(randomTime);
                    break;
            }
        }
    }
}

显示结果

这里写图片描述

这里写图片描述

这里写图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值