动画+事件处理篇
前言
提示:秋招在即,计蒙准备在国庆假期结束前整理一套Android初级面试题籍,希望对大家有所帮助
提示:以下是本篇文章正文内容
动画
1、Android 中的动画有哪几类
帧动画、补间动画、属性动画
2、动画能组合在一起使用么?
可以将动画组合在一起使用AnimatorSet,
AnimatorSet.play() 播放当前动画的同时可以
- .with() :将现有动画和传入的动画同时执行
- .after() :将现有动画插入到传入的动画之后执行
- .before() : 将现有动画插入到传入的动画之前执行
3、插值器的种类有哪些?
- AccelerateDecelerateInterpolator :在动画开始与结束的地方速率改变比较慢,在中间的时候加速
- AccelerateInterpolator:在动画开始的地方速率改变比较慢,然后开始速率变化加快
- LinearInterpolator:以常量速率改变
- AnticipateInterpolator:开始的时候向后然后向前甩
- PathInterpolator:动画执行的效果按贝塞尔曲线
- anticipateOvershootInterpolator:开始的时候向后然后向前甩一定值后返回最后的值
- CycleInterpolator:动画循环播放特定的次数,速率改变沿着正弦曲线
- OvershootInterpolator:向前甩一定值后再回到原来位置
- BounceInterpolator:动画结束的时候有弹起效果
4.如何自定义插值器
写一个类实现Interpolator接口,
Interpolator是一个空的接口继承了TimeInterpolator接口,
定义getInterpolation方法即可
5.如何修改 Activity 进入和退出动画
可以通过两种方式,一是通过定义 Activity 的主题,二是通过覆写 Activity 的overridePendingTransition 方法。
事件处理
1、Handler 机制
Handler能充当子线程和主线程之间的桥梁。
通常将 Handler 声明在 Activity 中,然后覆写 Handler 中的 handleMessage 方法,当子线程调用 handler.sendMessage()方法后 handleMessage 方法就会在主线程中执行。
这里面除了 Handler、Message 外还有隐藏的 Looper 和 MessageQueue 对象。在主线程中 Android 默认已经调用了 Looper.preper()方法,调用该方法的目的是在 Looper 中
创建 MessageQueue 成员变量并把 Looper 对象绑定到当前线程中。当调用 Handler 的sendMessage(对象)方法的时候就将 Message 对象添加到了 Looper 创建的 MessageQueue队列中,同时给 Message 指定了 target 对象,其实这个 target 对象就是 Handler 对象。主线程默认执行了 Looper.looper()方法,该方法从 Looper 的成员变量 MessageQueue 中取出 Message。
然后调用 Message 的 target 对象的 handleMessage()方法。这样就完成了整个消息机制。
2、onTouch 和 onTouchEvent 有什么区别
这两个方法都是在 View 的 dispatchTouchEvent 中调用的,onTouch 优先于 onTouchEvent执行。如果在 onTouch 方法中通过返回 true 将事件消费掉,onTouchEvent 将不会再执行。
另外需要注意的是,onTouch 能够得到执行需要两个前提条件,第一 mOnTouchListener 的值不能为空,第二当前点击的控件必须是 enable 的。因此如果你有一个控件是非 enable 的,那么给它注册 onTouch 事件将永远得不到执行。对于这一类控件,如果我们想要监听它的 touch 事件,就必须通过在该控件中重写 onTouchEvent 方法来实现。
3、子线程中能不能 new handler?为什么?
不能,如果在子线程中直接 new Handler()会抛出异常
当我们在dao主线程中创建Handler对象的时制候没有问题,是因为主线程会自动调用Looper.prepare()方法去给当前主线程创建并设置一个Looper对象,随意在Handler构造函数中从当前线程的对象身上拿到这个Looper。
但是子线程中并不会自动调用这个方法,所以要想在子线程中创建Handler对象就必须在创建之前手动调用Looper.prepare()方法,否则就会报错。
4、子线程发消息到主线程进行更新 UI,除了 handler 和 AsyncTask,还有什么?
1、用 Activity 对象的 runOnUiThread 方法更新,在子线程中通过 runOnUiThread()方法更新 UI:
2、用 View.post(Runnable r)方法更新 UI
五、为什么系统不建议在子线程访问UI?
并不是子线程不能更新UI,而是非Looper线程不能更新UI。所以要想更新UI,需要保证该线程是一个Looper线程。
那么怎么才能成为一个合格的Looper线程呢?
个人知识有限,自我感觉良好的大概总结了一下。一个Looper线程应该具有如下特点:
1.首先需要调用Looper.prepare()方法
执行该方法会将当前线程初始化为一个Looper线程,实际上就是在该线程中创建一个Looper对象。
2.创建Handler对象
该Handler对象会将Runnable对象post到当前线程里Looper的MessageQueue中。
具体要执行的代码就可以写到该Runnable对象的run方法里。
3.调用Looper.loop方法,循环处理消息队列里的消息(任务)
循环处理,处理获取到的每一条消息,将消息交付给该消息对应的handler对象(消息中包含其对应的handler),handler对象通过调用dispatchMessage方法处理该消息, 从而执行消息中的逻辑代码(Runnable对象run方法体中的代码)。
由于Toast.MakeText方法底层会创建一个handler,所以可以像上面那样直接调用Toast。当前也可以自己显示的创建一个handler对象,然后handler再去post消息到Looper的消息队列中:
public void backUpSms(View view) { new Thread() { @Override public void run() { //备份短信,耗时操作 boolean result = SmsUtils.backUp(XXXActivity.this); if (result) { Looper.prepare(); //显示创建Handler,将Runnable对象post到Looper的MessageQueue中 Handler myHandler = new Handler(); myHandler.post(new Runnable() { @Override public void run() { Toast.makeText(XXXActivity.this, "备份成功!!!!", Toast.LENGTH_SHORT).show(); } }); Looper.loop(); } else { Looper.prepare(); Toast.makeText(XXXActivity.this, "备份失败", Toast.LENGTH_SHORT).show(); Looper.loop(); } } }.start();