×

Android 在使用接口回调时调用 Thread.Sleep() 引发的思考

96
龙衣袭
2018.07.15 16:03* 字数 1109

写这篇文章的原因

原本只是想用最简单最容易理解的方式去介绍在 Android 中如何使用接口回调机制。刚开始我也觉得接口回调也很朦胧,只知道是为了处理任务异步,以及能使代码看起来更加容易理解和维护,但是如何去实现还不太清楚。

通过看了其他大神的博客,终于能用自己的方式去理解接口回调如何实现,于是想着花十几分钟整理出一个小例子,也让不太理解该机制的人,能够快速理解。

但是真正写起来,才发现很多东西都我都没理解好,所以在这里将这次的事件做个记录。

接口回调简单理解和实现

接口回调的使用场景

在 A 类中调用 B 类中的方法,在该方法处理完成后需要将结果告知 A 类即可用接口回调实现

例如在 TestCallBackActivity 中有个按钮,通过点击这个按钮可以去做一些事情,比如我想通过点击这个按钮,让 Wang.class 这个类里面的 dowork() 方法去做一些事情,当Wang.class做完了事情之后需要通知 TestCallBackActivity它做完了。

通俗易懂的理解

下面一段是吐槽,可以跳过!!
又或者是今天老板S给了一个需求给程序员A,让程序员去做,不管程序员A怎么做,程序员A只要在完成任务后将成品给老板看就行(一般情况下不可能当场就做出来,需要一定的时间,所以老板这时候就可以去给其他程序员提其他需求或者是去喝杯咖啡??又或者在你旁边一直等着你做出来,但是谁知道你什么时候做出来,哈哈哈)

实现

  • 创建CallBack接口,声明好会出现的结果方法
public interface ICallBack {
    void aBiggerThanb() ;
    void aSmallThanb() ;
}

  • 再创建Wang.class,写上doWork()方法
public class Wang {
   public void doWork(int a, int b, ICallBack callBack){
       if (a > b){
           callBack.aBiggerThanb();
       }else {
           callBack.aSmallThanb();
       }
   }
}
  • TestCallBackActivity中调用,并弹出Toast告诉TestCallBackActivity结果
Button btnCallWangToWork = findViewById(R.id.btn_call_wang_to_work) ;
final Wang wang = new Wang();

btnCallWangToWork.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        Toast.makeText(CallBackTestActivity.this, "小王正在计算中...", Toast.LENGTH_SHORT).show();

        wang.doWork(10, 50, new ICallBack() {
            @Override
            public void aBiggerThanb() {
                new Timer().schedule(new TimerTask() {
                    @Override
                    public void run() {
                        Looper.prepare();
                        Toast.makeText(CallBackTestActivity.this, "a > b", Toast.LENGTH_SHORT).show();
                        Looper.loop();
                    }
                }, 4 * 1000);
            }

            @Override
            public void aSmallThanb() {
                try {
                    Thread.sleep(500);
                    Toast.makeText(CallBackTestActivity.this, "a < b", Toast.LENGTH_SHORT).show();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
    }
});

一些问题

  • Thread.Sleep() 的含义
    为什么会讲到这个问题呢?因为我在实现的时候,刚开始是让参数a>b,当点击按钮的时候先Toast:小王正在计算中...,然后调用 Thread.Sleep(5000)休息5s后才Toast 计算返回的结果。想法很完美,但是Toast:小王正在计算中...就是一直不显示,系统也没报错,所以我想到了肯定是Thread.Sleep搞的鬼。

Thread.Sleep的表示的含义我们可以点击进入方法查看到方法描述:

Causes the currently executing thread to sleep
 (temporarily cease execution) for the specified number 
 of milliseconds, subject to the precision 
 and accuracy of system timers and schedulers.
  The thread does not lose ownership of any monitors

主要是说Sleep方法会让当前线程休眠指定的毫秒数,目标对象服从系统的时间和调度。从该描述中结合 Toast 默认的显示时长我们可以知道是什么原因导致Toast不弹出了。

  • Toast 默认的显示时长
    Android 自带的两个 Toast 时长 LENGTH_SHORT (2秒)LENGTH_LONG (3.5秒),上面我们的Thread.Sleep(5000)让当前线程(主线程)休眠5s显然已经超过 Toast 的默认显示时长。所以当我们让线程休眠完成后第一个Toast 已经显示完成了,所以当休眠完成后才会看不到 Toast 的文本。那么我想先弹出 Toast 提示后台正在计算,然后5s后显示计算结果,怎么做呢?

  • 定时任务
    利用定时任务去实现,这里使用的是 new Timer().schedule(new TimerTask() {...}实现,但是在里面进行 Toast 是会报错的Can't create handler inside thread that has not called Looper.prepare(),因为 Toast 的显示需要Looper 通过Handler去发送消息给主线程更新UI,但是 Android 系统默认情况下非主线程中没有开启 Looper,而且 Handler 对象必须绑定 Looper 对象,所以知道原因我们就知道如何去实现了。

  • 如何给开启 Looper

Looper.prepare();
....doSomething...
Looper.loop();

相关文章推荐

开发
Web note ad 1