>

从 "5s澳门博发娱乐官网:" 开始显示,这俩种方

- 编辑:澳门博发娱乐官网 -

从 "5s澳门博发娱乐官网:" 开始显示,这俩种方

澳门博发娱乐官网 1

概述

在Android应用中大约都能收看,闪屏页也许招待页右上角有一个 “倒计时 + 跳过” 的效果与利益,还会有正是赢得验证码的倒计时功效,某人会想到延迟的贯彻格局,在此间经超过实际用Android封装好的类 CountDownTimer 就会轻轻巧松达成,在那之中间原理便是通过Handler机制完结的。

前言

LZ-Says:前几天吸取转正通告了,内心也就12s开心,随之而来的就是不平不淡。16年10月18号入职,感觉一切都好像眨眼之间,过得好快,各种忙
承诺了和谐,要完美努力。答应了亲属,要优质努力。答应了心,要能够坚贞不屈。有何理由不去努力

概述

对此刚入门的同班来讲,往往都会对Handler比较模糊,到底Handler是个什么样的东西。当然,大概对此一些有职业经历的程序员来说,他们也不必然能很标准地陈述,大家来看下API的介绍。

Handler是用来构成线程的新闻队列来发送、管理“Message对象”和“Runnable对象”的工具。每一个Handler实例之后会提到贰个线程和该线程的消息队列。当你创立七个Handler的时候,从此时开首,它就能够自动关联到所在的线程/音信队列,然后它就能时断时续把Message/Runnalbe分发到音讯队列,并在它们出队的时候管理掉。

从官方文书档案中,大家轻松寻觅当中的重大词,正是“线程”。大家都明白,贰个提到到互连网操作,耗费时间操作等的Android应用,都离不开八线程操作,可是,要是此时大家允许出现更新UI,那么最后变成控件的情状都以不可明确的。所以,大家能够通过对控件进行加锁,在无需用时解锁,那是一个缓慢解决方案之一,但最终很轻松导致线程阻塞,效能会要命差。所以,Google选拔了只同意在主线程更新UI,所以作为线程通信桥梁的Handler也就出现了。

概述

对于刚同志入门的同学来讲,往往都会对Handler相比较盲目,到底Handler是个怎样的事物。当然,大概对于部分有职业经验的技术员来讲,他们也不自然能很规范地描述,大家来看下API的牵线。

Handler是用来整合线程的新闻队列来发送、管理“Message对象”和“Runnable对象”的工具。每贰个Handler实例之后会涉嫌八个线程和该线程的音讯队列。当您制造一个Handler的时候,从那儿开首,它就能自行关联到所在的线程/音讯队列,然后它就能时有时无把Message/Runnalbe分发到新闻队列,并在它们出队的时候管理掉。

从官方文书档案中,我们简单寻找里面包车型客车重要词,正是“线程”。我们都精晓,贰个关乎到网络操作,耗费时间操作等的Android应用,都离不开多线程操作,可是,纵然那时候我们允许出现更新UI,那么最后促成控件的状态都以不足鲜明的。所以,大家得以由此对控件举行加锁,在无需用时解锁,这是多个消除方案之一,但最终很轻易变成线程阻塞,功用会那几个差。所以,谷歌(Google)动用了只同目的在于主线程更新UI,所以作为线程通讯桥梁的Handler也就应际而生了。

Android 实现倒计时的秘诀有各个,Handler 延时发送 Message,Timer 和 TimerTask 协作使用,使用 CountDownTimer 类等。相比较来讲,经过系统封装的 CountDownTimer 算是使用起来最为有利的艺术之一。

效果图

待提交

起头正题

好吧,前几日联合具名回想下,关于Android中落实倒计时功能吧~

后天为我们介绍俩种格局,都能够兑现倒计时效率。那俩种方法分别是:

  1. Handler+Thread
  2. CountDownTimer

兴许大家对此第一种完结格局必然不会目生了,差不离So easy那再次回顾下第一种写法

Looper、MessageQueue、Message、Handler的关系

讲到Handler,明确离不开Looper、MessageQueue、Message那三者和Handler之间的关联,上面简略地带过,详细自个儿能够查阅相关资料,可能查看源码,那样更实惠大家深切学习。

Looper、MessageQueue、Message、Handler的关系

讲到Handler,确定离不开Looper、MessageQueue、Message那三者和Handler之间的关联,上边简略地带过,详细本人能够查阅相关资料,也许查看源码,那样更便利大家深远学习。

而是,CountDownTimer 有多少个应用上的题目大家不得不稍加介怀:计时不正确、内部存款和储蓄器泄漏难点。大家来组金敬道码逐个解析一下。

CountDownTimer 介绍

  • CountDownTimer 直接 new 出来使用,其构造函数
public CountDownTimer(long millisInFuture, long countDownInterval) {  
    mMillisInFuture = millisInFuture;  
    mCountdownInterval = countDownInterval;  
} 

1.参数 - millisInFuture:设置倒计时的总时间(阿秒)
2.参数 - countDownInterval:设置每回减去的时间(皮秒)

  • 方法
public final void cancel ()  

public abstract void onFinish ()  

public abstract void onTick (long millisUntilFinished)  

public final CountDownTimer start () 

1.cancel() 打消当前职务
2.onFinish() 当前任务完毕的时候调用
3.onTick(long millisUntilFinished) 当前任务每成功二次倒计时间隔时间时回调
4.start() 最初当前的义务
注:调用时介意start() 方法的调用,要不倒计时是不起成效的。。

1.通过使用Handler+Thread达成倒计时

Looper

每一个线程唯有二个Looper,各类线程在起先化Looper之后,然后Looper会维护好该线程的音讯队列,用来寄存Handler发送的Message,并拍卖消息队列出队的Message。它的天性是它跟它的线程是绑定的,处理音信也是在Looper所在的线程去处理,所以当大家在主线程创设Handler时,它就能够跟主线程独一的Looper绑定,从而大家利用Handler在子线程发新闻时,最后也是在主线程管理,达到了异步的法力。

那就是说就能有人问,为啥大家运用Handler的时候根本都无需创立Looper呢?那是因为在主线程中,ActivityThread暗许会把Looper初步化好,prepare现在,当前线程就能够形成叁个Looper线程。

Looper

每四个线程只有四个Looper,各类线程在初步化Looper之后,然后Looper会维护好该线程的音讯队列,用来寄存Handler发送的Message,并拍卖新闻队列出队的Message。它的表征是它跟它的线程是绑定的,管理新闻也是在Looper所在的线程去管理,所以当大家在主线程创造Handler时,它就能够跟主线程唯一的Looper绑定,进而大家利用Handler在子线程发新闻时,最后也是在主线程管理,达到了异步的成效。

那正是说就能有人问,为何大家运用Handler的时候根本都不须要创设Looper呢?那是因为在主线程中,ActivityThread默许会把Looper早先化好,prepare今后,当前线程就能够成为一个Looper线程。

举个差不离的例证,利用 CountDownTimer 完结二个时长为 5 秒的 View 倒计时展现,供给从 5s 初叶每隔 1 秒倒计时展现到 1s:

案例

public class ZpTimerActivity extends Activity {  

    private CountDownTimer mTimer;  

    @Override  
    protected void onCreate(@Nullable Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  

        setContentView(R.layout.activity_timer);  
        initView();  
    }  

    private void initView() {  
        if (mTimer == null) {  
            mTimer = new CountDownTimer((long) (5 * 1000), 1000) {  

                @Override  
                public void onTick(long millisUntilFinished) {  
                    if (!ZpTimerActivity.this.isFinishing()) {  
                        int remainTime = (int) (millisUntilFinished / 1000L);  
                        Log.e("zpan","======remainTime=====" + remainTime);  
                    }  
                }  

                @Override  
                public void onFinish() {  
                    Log.e("zpan","======onFinish=====");  
                }  
            };  
            mTimer.start();  
        }  
    }  

    @Override  
    protected void onDestroy() {  
        super.onDestroy();  
        if (mTimer != null) {  
            mTimer.cancel();  
            mTimer = null;  
        }  
    }  
}  

Log

12-06 16:31:17.809 20276-20276/com.example.zpdemo E/zpan: ======remainTime=====4  
12-06 16:31:18.811 20276-20276/com.example.zpdemo E/zpan: ======remainTime=====3  
12-06 16:31:19.812 20276-20276/com.example.zpdemo E/zpan: ======remainTime=====2  
12-06 16:31:20.813 20276-20276/com.example.zpdemo E/zpan: ======remainTime=====1  
12-06 16:31:22.769 20276-20276/com.example.zpdemo E/zpan: ======onFinish=====  
先是编写布局文件

布局文件很简短,便是一个TextView,暗许呈现Handler获取验证码,点击TextView,举办倒计时操作,落成后复原默许显示。

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <TextView
        android:id="@+id/tv_show_h"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="193dp"
        android:text="Handler获取验证码" />

</RelativeLayout>

MessageQueue

MessageQueue是三个消息队列,用来寄放Handler发送的信息。每种线程最五唯有贰个MessageQueue。MessageQueue常常都以由Looper来处理,而主线程创建时,会创设一个暗中同意的Looper对象,而Looper对象的创始,将自动成立三个MessageQueue。别的非主线程,不会自动创造Looper。

MessageQueue

MessageQueue是贰个音信队列,用来贮存在Handler发送的消息。各个线程最多独有三个MessageQueue。MessageQueue平时都以由Looper来治本,而主线程创立时,会成立一个暗中认可的Looper对象,而Looper对象的创办,将电动创立贰个MessageQueue。别的非主线程,不会自行创造Looper。

CountDownTimer timer = new CountDownTimer(5000, 1000){ @Override public void onTick(long millisUntilFinished) { mSampleTv.setText(millisUntilFinished / 1000 + "s"); } @Override public void onFinish() { }};timer.start();

踩过的坑

在有个别场景下,CountDownTimer 会导致空指针,也是有一点都不小希望导致内部存款和储蓄器泄漏。
只要在Activity或然Fragment被回收时未有调用CountDown提姆er的cancel()方法结束本身,那一年CountDownTimer的Handler方法中一旦判定到近期的时日未走完,那么会一连调用onTick方法,Activity只怕Fragment已经被系统回收,进而里面包车型大巴变量被设置为Null,同一时间,CountDownTimer中的Handler方法还在继续实施,这一块空间始终无法被系统回收也就招致了内存泄漏。

  • 在CountDownTimer的onTick方法中记得对日前指标做判空管理
    activity
if(!activity.isFinishing()){  
        // TODO  
}

fragment

if(getActivity()!=null){  
      // TODO  
}  
  • 在和Dialog结合使用的时候,在onFinish()方法调用 dismiss()方法让弹框消失,要看清getFragmentManager是或不是为空
@Override  
public void onFinish() {  
    if(getFragmentManager()!=null){  
        dismiss();  
    }  
} 
  • 在运用CountDownTimer时,在Activity或fragment生命周期甘休时,调用timer.cancle()方法
@Override  
protected void onDestroy() {  
    super.onDestroy();  
    if (mTimer != null) {  
        mTimer.cancel();  
        mTimer = null;  
    }  
} 
放大招,编写Activity,完成效果与利益~
public class MainActivity extends Activity {

    private TextView tvShowH;

    private Handler handler = new Handler() {
        public void handleMessage(Message msg) {
            tvShowH.setText(msg.what - 1 + "s");
            if (msg.what == 0) {
                // 倒计时结束让按钮可用
                tvShowH.setEnabled(true);
                tvShowH.setText("Handler获取验证码");
            }
        }
    };

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

        tvShowH = (TextView) findViewById(R.id.tv_show_h);

        tvShowH.setOnClickListener(listenerH);

    }

    private OnClickListener listenerH = new View.OnClickListener() {

        @Override
        public void onClick(View v) {
            tvShowH.setEnabled(false);
            new Thread(new Runnable() {
                @Override
                public void run() {
                    for (int i = 10; i >= 0; i--) {
                        handler.sendEmptyMessage(i);
                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }).start();
        }
    };

}

Message

消息对象,就是MessageQueue里面存放的对象,一个MessageQueu能够满含八个Message。当大家需求发送一个Message时,大家日常不提议选择new Message()的格局来创制,更推荐应用Message.obtain()来博取Message实例,因为在Message类里面定义了贰个新闻池,当音信池里存在未使用的音信时,便回来,若无未利用的音信,则经过new的措施创制再次来到,所以选用Message.obtain()的艺术来赢得实例能够大大缩短当有大量Message对象而产生的污源回收难题。

四者关系完全如下(如有不对的地方,感激建议)
澳门博发娱乐官网 2

Message

消息对象,正是MessageQueue里面存放的靶子,多个MessageQueu可以归纳八个Message。当大家要求发送三个Message时,我们日常不提出利用new Message()的款型来创立,更推荐使用Message.obtain()来获得Message实例,因为在Message类里面定义了二个音讯池,当消息池里设有未利用的音讯时,便重回,若无未使用的信息,则通过new的艺术开创重回,所以选取Message.obtain()的不二秘诀来博取实例能够大大缩小当有恢宏Message对象而发生的杂质回收难题。

四者关系完全如下(如有不对的地点,感激提出)
澳门博发娱乐官网 3

不错图景下,TextView 依照大家想象的那样,从 "5s" 最先显得,然后 “4s”、“3s”,直到突显 “1s”。然则事实却是从 “4s” 最早彰显的(例子很简短,此处不再放图)。

来张效果图瞅瞅呗~

澳门博发娱乐官网 4

此地写图片描述

Handler的首要用途

  1. 推送以后某些时间点将在施行的Message或然Runnable到音信队列。
  2. 在子线程把须求在另三个线程推行的操作加入到音信队列中去。

废话没多少说,通过比如来佛申明Handler的三个首要用途。

Handler的主要用途

  1. 推送今后某些时间点将在实施的Message只怕Runnable到音信队列。
  2. 在子线程把要求在另贰个线程实践的操作参预到新闻队列中去。

废话相当的少说,通过举个例子来表明Handler的八个重要用途。

那表达在 onTick 回调方法中的参数有题目,这就在该措施中增添一句日志:

2.经过CountDownTimer实现倒计时

1. 推送今后某些时间点将在试行的Message也许Runnable到音信队列

实例:通过Handler协作Message或然Runnable达成倒计时

  • 第一看一下功用图

澳门博发娱乐官网 5

  • 艺术一,通过Handler + Message的情势贯彻倒计时。代码如下:
public class MainActivity extends AppCompatActivity {
    private ActivityMainBinding mBinding;

    private Handler mHandler ;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);

        //设置监听事件
        mBinding.clickBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //通过Handler + Message的方式实现倒计时
                for (int i = 1; i <= 10; i++) {
                    Message message = Message.obtain(mHandler);
                    message.what = 10 - i;
                    mHandler.sendMessageDelayed(message, 1000 * i); //通过延迟发送消息,每隔一秒发送一条消息
                }
            }
        });

        mHandler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                mBinding.time.setText(msg.what + "");   //在handleMessage中处理消息队列中的消息
            }
        };
    }
}

其实代码不用怎么解释,都相比较简单明了,但是此地运用了DataBiding,或者没用过的校友看起来有一点点出乎意料,但实际反而简略了代码,有自然基础的同校看起来都不会有太大压力,所以不做太多解释。通过那些小程序,笔者希望我们能够精晓到Handler的一个职能正是,在主线程中,能够通过Handler来管理部分有种种的操作,让它们在一定的光阴点被推行。

  • 主意二,通过Handler + Runnable的情势贯彻倒计时。代码如下:
public class MainActivity extends AppCompatActivity {
    private ActivityMainBinding mBinding;
    private Handler mHandler = new Handler();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);

        //设置监听事件
        mBinding.clickBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                for (int i = 1; i <= 10; i++) {
                    final int fadedSecond = i;
                    //每延迟一秒,发送一个Runnable对象
                    mHandler.postDelayed(new Runnable() {
                        @Override
                        public void run() {
                            mBinding.time.setText((10 - fadedSecond) + "");
                        }
                    }, 1000 * i);
                }
            }
        });
    }
}

办法二也是通过代码让我们加深Handler管理有序事件的用途,之所以分手Runnable和Message二种办法来完成,是因为众几人都搞不清楚为何Handler能够推送Runnable和Message三种对象。实在,无论Handler将Runnable还是Message参与MessageQueue,最后都只是将Message参加到MessageQueue。只要大家看一下源码就足以知晓,Handler的post Runnable对象那一个法子只是对post Message举办了一层封装,所以最终大家都以由此Handler推送了叁个Message罢了,至于缘何会分别三种方法,下文子禽给大家详说毕竟。下边再来看看Handler的第一个首要用途。

1. 推送以后有些时间点就要实践的Message或然Runnable到音信队列

实例:通过Handler合作Message恐怕Runnable实现倒计时

  • 先是看一下意义图

澳门博发娱乐官网 6

  • 主意一,通过Handler + Message的法子贯彻倒计时。代码如下:
public class MainActivity extends AppCompatActivity {
    private ActivityMainBinding mBinding;

    private Handler mHandler ;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);

        //设置监听事件
        mBinding.clickBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //通过Handler + Message的方式实现倒计时
                for (int i = 1; i <= 10; i++) {
                    Message message = Message.obtain(mHandler);
                    message.what = 10 - i;
                    mHandler.sendMessageDelayed(message, 1000 * i); //通过延迟发送消息,每隔一秒发送一条消息
                }
            }
        });

        mHandler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                mBinding.time.setText(msg.what + "");   //在handleMessage中处理消息队列中的消息
            }
        };
    }
}

实则代码不用怎么解释,都相比较老妪能解,不过此地运用了DataBiding,大概没用过的同桌看起来有一点意外,但实际上反而简略了代码,有早晚基础的同室看起来都不会有太大压力,所以不做太多解释。通过这么些小程序,作者希望我们能够理解到Handler的二个作用正是,在主线程中,能够经过Handler来管理部分有各样的操作,让它们在坚固的大运点被实践。

  • 方法二,通过Handler + Runnable的办法贯彻倒计时。代码如下:
public class MainActivity extends AppCompatActivity {
    private ActivityMainBinding mBinding;
    private Handler mHandler = new Handler();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);

        //设置监听事件
        mBinding.clickBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                for (int i = 1; i <= 10; i++) {
                    final int fadedSecond = i;
                    //每延迟一秒,发送一个Runnable对象
                    mHandler.postDelayed(new Runnable() {
                        @Override
                        public void run() {
                            mBinding.time.setText((10 - fadedSecond) + "");
                        }
                    }, 1000 * i);
                }
            }
        });
    }
}

主意二也是通过代码让大家加深Handler管理有序事件的用途,之所以分手Runnable和Message三种艺术来达成,是因为不菲人都搞不清楚为何Handler能够推送Runnable和Message两种对象。事实上,无论Handler将Runnable依然Message加入MessageQueue,最终都只是将Message出席到MessageQueue。只要我们看一下源码就能够清楚,Handler的post Runnable对象那些格局只是对post Message进行了一层封装,所以最终我们都是通过Handler推送了二个Message罢了,至于为何会分离二种办法,下文仲给大家详说终归。上边再来看看Handler的首个重要用途。

本文由胜博发-编程发布,转载请注明来源:从 "5s澳门博发娱乐官网:" 开始显示,这俩种方