我觉得这是一个很有趣的问题,有趣的除了题目本身,也在于其引申出的感悟。我们在使用和学习Android Framework相关的内容时,除了要了解其内部实现机制,还要求自己要试着去反思,或者提问其设计的目的,这样才能帮助我们更好的理解和吸收其设计的精髓之处。
1. 你觉得onActivityResult好用吗?
面试官在提出设计问题前可能会先抛砖引玉,先提出这个问题来探一探面试者有没有真正的去体验和总结相关的内容。大部分人可能会说,麻烦!那为什么麻烦呢?首先先看一下onActivityResult是怎么使用的:
// Activity A
startActivityForResult(intent, requestCode);
// Activity B
setResult(resultCode, intent);
// Activity A
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch(resultCode) {
...
}
}
从代码中可以看出,onActivityResult存在以下使用的问题:
1)代码处理逻辑分离,容易出现遗漏和不一致的地方
很明显,在使用上startActivity和onActivityResult的逻辑是分开的,假如,startActivity的requestCode被修改了,那么onActivityResult的requestCode也要修改,这样就很容易出现修改遗漏而导致不一致的地方。
2)写法不够直观,且结果数据没有类型安全保障
onActivityResult的用法要求Activity A和Activity B需要事先沟通好回传的内容字段和格式,如:
// Activity B
Intent intent = new Intent();
intent.putExtra("result", "true");
setResult(resultCode, intent);
// Activity A
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch(resultCode) {
...
boolean result = Boolean.valueOf(data.getString("result"));
}
}
如果Activity B修改了result
的回传格式为boolean
,但是又没有通知Activity A修改,这样编译时是不会发现问题,只有在运行时抛出异常了才发现:
// Activity B
Intent intent = new Intent();
intent.putExtra("result", true); // String修改为boolean
setResult(resultCode, intent);
// Activity A
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch(resultCode) {
...
// throws exception
boolean result = Boolean.valueOf(data.getString("result"));
}
}
3)当结果种类比较多时,onActivityResult会逐渐臃肿且难以维护
这个问题也是显而易见的,当处理场景较多时,就会出现很多switch-case语句。当然,把相应的case实现抽成方法,可以提高代码的可读性:
// Activity A
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch(resultCode) {
case PICK_PHOTO_BACK:
handlePickPhotoBack(data);
case CAMERA_BACK:
handleCameraBack(data);
case CROP_PHOTO_BACK:
handleCropPhotoBack(data);
...
}
}
2. onActivityResult能设计成回调吗?
假设onActivityResult可以设计成回调,那么startActivity的代码应该如下:
// Activity A
startActivityForResult(intent, new OnResultCallback(){
@Override
public void onResult(Intent data) {
textView.setText(data.getString("result"));
}
})
由于匿名内部类会持有外部类的引用,当Activity A被意外销毁时,由于其对象被OnResultCallback
可能会导致其无法正常被GC,当Activity B给Activity A回复时,OnResultCallback
被调用,新的Activity A2 被恢复,但是onResult
方法持有的依旧是被销毁的Activity A的引用,即:
// Activity A2
startActivityForResult(intent, new OnResultCallback(){
@Override
public void onResult(Intent data) {
activityA.textView.setText(data.getString("result"));
}
})
所以,结论就是不能使用回调,因为Activity的销毁和恢复机制不允许匿名内部类出现。