摘自阿里巴巴Android开发手册
强制要求的
- 1. Activity 间的数据通信,对于数据量比较大的,避免使用
intent + Parcelable
的方式,可以考虑EventBus
等替代方案,以免造成TransationTooLargeException
- 2.
Activity
间通过隐士Intent
的跳转,在发出Intent
之前必须通过resolveActivity
检查,避免找不到合适的调用组件,造成ActivityNotFoundException
的异常。1
2
3
4
5
6
7
8
9
10public void viewUrl(String url, String mimeType) {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.parse(url), mimeType);
if (getPackageManager().resolveActivity(intent, PackageManager.MATCH_DEFAULT_
ONLY) != null) {
startActivity(intent);
}else {
// 找不到指定的 Activity
}
}
而不应该:1
2
3
4
5
6
7Intent intent = new Intent();
intent.setAction("com.example.DemoIntent ");
try {
startActivity(intent);
} catch (ActivityNotFoundException e) {
e.printStackTrace();
}
3. 避免在
Service#onStartCommand/onBind()
方法中执行耗时操作,如果确实有需求,应采用IntentService
或采用其他异步机制完成。
正例:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25public class MainActivity extends Activity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
public void startIntentService(View source) {
Intent intent = new Intent(this, MyIntentService.class);
startService(intent);
}
}
public class MyIntentService extends IntentService {
public MyIntentService() {
super("MyIntentService");
}
protected void onHandleIntent(Intent intent) {
synchronized (this) {
try {
......
} catch (Exception e) {
}
}
}
}4. 避免在
BroadcastReceive#onReceive()
中执行耗时操作,如果有耗时工作,应该创建IntentService
完成,而不应该在BroadcastReceiver
内创建子线程去做。
说明:
由于该方法是在主线程执行,如果执行耗时操作会导致 UI
不流畅,可以使用 IntentService
,创建 HanlderThread
或者调用 Context#registerReceiver(BroadcastReceiver,IntentFitter,String,Handler)
方法等方式,在其他 Worker
线程执行 onReceive
.BroadcastReceiver#onReceive()
方法耗时超过10秒钟,可能会被系统杀死。
正例:
1 | IntentFilter filter = new IntentFilter(); |
反例:1
2
3
4
5
6
7
8
9mBroadcastReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
MyDatabaseHelper myDB = new MyDatabaseHelper(context);
myDB.initData();
// have more database operation here
}
};
- 5. 避免使用隐士
Intent
广播敏感信息,信息可能被其他注册了对应BroadcastReceiver
的App接收。
说明:
通过Context#sendBroadcast()
发送的隐士广播会被感兴趣的 receiver
接收,恶意应用注册监听该广播的 receiver
可能会获取到 Intent
中传递的敏感信息,并进行其他危险操作。如果发送的广播为使用 Context#sendOrderedBroadcast()
方法发送的有序广播,优先级较高的恶意 receiver
可能直接丢弃该广播,造成服务不可用,或者向广播结果塞入恶意数据。
如果广播仅限于应用内,则可以是iyongLocalBroadcastManager#sendBroadcast()
实现,避免敏感信息外泄和intent拦截的风险。
正例:1
2
3Intent intent = new Intent("my-sensitive-event");
intent.putExtra("event", "this is a test event");
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
反例:1
2
3
4
5
6
7
8
9
10
11Intent intent = new Intent();
v1.setAction("com.sample.action.server_running");
v1.putExtra("local_ip", v0.h);
v1.putExtra("port", v0.i);
v1.putExtra("code", v0.g);
v1.putExtra("connected", v0.s);
v1.putExtra("pwd_predefined", v0.r);
if (!TextUtils.isEmpty(v0.t)) {
v1.putExtra("connected_usr", v0.t);
}
context.sendBroadcast(v1);
以上广播可能被其他应用的如下 receiver
接收导致敏感信息泄露:1
2
3
4
5
6
7
8
9
10
11
12
13final class MyReceiver extends BroadcastReceiver {
public final void onReceive(Context context, Intent intent) {
if (intent != null && intent.getAction() != null) {
String s = intent.getAction();
if (s.equals("com.sample.action.server_running") {
String ip = intent.getStringExtra("local_ip");
String pwd = intent.getStringExtra("code");
String port = intent.getIntExtra("port", 8888);
boolean status = intent.getBooleanExtra("connected", false);
}
}
}
}