面试题六:Activity的onActivityResult使用起来非常麻烦,为什么不设计成回调?
Activity的onActivityResult使用起来非常麻烦,为什么不设计成回调?
一、面试官视角:这道题想考察什么?
- 是否熟悉onActivityResult的用法
- 是否思考过用回调替代onActivityResult
- 是否实践过用回调替代onActivityResult
- 是否意识到回调存在的问题
- 是否能给出匿名内部类对外部类引用的解决方案
二、题目剖析:
1、onActivityResult是干什么的,怎么用?
干什么的:
从A页面跳转到B页面时,如果希望B页面回到A页面时,携带一些数据回来,那么就可以使用onActivityResult。
怎么用的:
1、Activity A:startActivityForResult(intent, requestCode);
2、Activity B:setResult(resultCode, intent);
3、Activity A:覆写onActivityResult(requestCode, resultCode, data)方法
存在的问题:
1、代码处理逻辑分离,容易出现遗漏和不一致的问题(有时startActivityForResult和onActivityResult调用处不在一起,经常顾此失彼,容易出现遗漏)
2、写法不够直观,且结果数据没有类型安全保障(setResult里面的intent,装载的是个Bundle,类似于HashMap,因此只有看到setResult具体的代码,才能在onActivityResult中知道回传数据的具体类型)
3、结果种类较多时,onActivityResult就会逐渐臃肿难以维护
2、回调在这样的场景下适用吗?
3、如果适用,那为什么不用回调?
4、如果不适用,给出你的理由?
假设:用回调实现
在Activity A中,通过假设出来的回调实现去调用并启动Activity B:
1
2
3
startActivityForResult(intent, new onResultCallback(){
...
});在Activity B中:
通常情况下,Activity B启动之后总会回到Activity A,但凡事总有意外,当Activity B长时间在栈顶,而Activity A因内存不足等原因被销毁了,这个时候Activity B通过setResult(resultCode, intent)返回时,系统会重新再new一个Activity A‘,但此时的 Activity A‘ 与之前的 Activity A是完全不同的两个实例了,而我们知道匿名内部类会引用外部类的实例,那么以下代码就会存在问题:
1
2
3
4
5
6
startActivityForResult(intent, new onResultCallback(){
public void onResult(Bundle bundle) {
// 在匿名内部类中使用外部类实例去更新组件时,就会存在问题,因为此时的mTextView是之前被销毁的Activiyt A 实例里面的mTextView成员,而不是现在的 Activity A‘ 实例里面的mTextView成员了,因此这行代码是无效的,不会起任何作用,也正是有这样的问题,所以不能直接使用回调。
mTextView.setText(bundle.getStringExtra("key"));
}
});转机:
基于注解处理器和Fragment的回调实现:
在Activity中创建一个空的Fragment并实现其回调,就算Activity和Fragment实例被销毁后重新创建了,也还是可以通过新的Fragment实例获取到新的Activity实例,在通过新的Activity实例去拿里面的mTextvView成员从而进行组件更新。
销毁被重新创建后,如何获取新的外部类实例的新的自由变量呢?因为自由变量在匿名内部类中只是一份快照,而它之前所依赖生存的外部类实例已经被销毁了,它也随之消耗,这个时候我们想找到新的外部类实例对应的新的自由变量,该怎么找呢?
通过id来找,也就是在Activity A启动Activity B的时候,将该自由变量的id存储起来,然后当Activity B返回Activity A‘ 的时候,在新的Fragment中,通过新的 Activity A‘ 的实例去findViewById来获取新的自由变量。
除了捕获View可以通过上面说的id来查找,那么Fragment如何找到新的呢?
捕获Fragment引用也可以类似通过字段mWho来替换,这个字段可以标识为唯一,但这个字段不是公开的,我们可以通过反射来获取到,然后去更新Fragment。
三、题目结论
为什么不直接使用回调:
onActivityResult确实麻烦
CallBack确实也可以简化代码编写
但Activity的销毁和恢复机制不允许匿名内部类出现
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!