Android 代码编写事宜

Android 基本组件指 Activity、Fragment、Service、BroadcastReceiver、ContentProvider 等等。
1.【强制】Activity 间的数据通信,对于数据量比较大的,避免使用 Intent + Parcelable的方式,可以考虑
EventBus 等替代方案,以免造成 TransactionTooLargeException 。
说明:对于数据量“较大”没有明确定义,IPC缓存区最大为1M,官方给的建议是:避免传递bitmap对象或者超大
string数组
2.【推荐】Activity#onSaveInstanceState() 方法不是 Activity 生命周期方法,也不保证一定会被调用。它是用
来在 Activity 被意外销毁时保存 UI 状态的,只能用于保存临时性数据,例如 UI 控件的属性等,不能跟数据的持久
化存储混为一谈。持久化存储应该在 Activity#onPause()/onStop() 中实行。
3.【强制】Activity 间通过隐式 Intent 的跳转
(1)如果需要对目标Activity存在与否作相应的处理逻辑,那么在发出 Intent 之前必须通过 resolveActivity检查
Good:
Bad:
(2)如果不care目标Activity是否存在并且不想让应用崩溃的话,需要加try/catch包裹,并且将Exception日志打

4.【强制】避免在 Service#onStartCommand()/onBind() 方法中执行耗时操作,如果确实有需求,应改用
IntentService 或采用其他异步机制完成。
Good:
public 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找不到的逻辑
}
}
Intent intent = new Intent();
intent.setAction(“com.great.activity_intent.Intent_Demo1_Result3”);
Intent intent = new Intent(Intent.ACTION_VIEW);
try {
startActivity(intent);
}catch (Exception e) {
Log.e(TAG, e.getMessage())
}
5.【强制】避免在 BroadcastReceiver#onReceive()中执行耗时操作,如果有耗时工作,应该创建 IntentService
完成,而不应该在 BroadcastReceiver 内创建子线程去做。
说明: 由于该方法是在主线程执行,如果执行耗时操作会导致 UI 不流畅。可以使用IntentService 、 创 建
HandlerThread 或 者 调 用 Context#registerReceiver(BroadcastReceiver, IntentFilter, String,
Handler) 方法等方式,在其他 Wroker 线程执行 onReceive 方法。BroadcastReceiver#onReceive() 方法耗
时超过 10 秒钟,可能会被系统杀死。
Good:
public class MainActivity extends Activity {
@Override
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”);
}
@Override
protected void onHandleIntent(Intent intent) {
synchronized (this) {
try {

} catch (Exception e) {
}
}
}
}
IntentFilter filter = new IntentFilter();
filter.addAction(LOGIN_SUCCESS);
this.registerReceiver(mBroadcastReceiver, filter);
mBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
Intent userHomeIntent = new Intent();
userHomeIntent.setClass(this, UseHomeActivity.class);
this.startActivity(userHomeIntent);
}
};
Bad:
6.【推荐】总是使用显式 Intent 启动或者绑定 Service,且不要为服务声明 Intent Filter,保证应用的安全性。如
果确实需要使用隐式调用,则可为 Service 提供 Intent Filter并从 Intent 中排除相应的组件名称,但必须搭配使用
Intent#setPackage() 方法设置Intent 的指定包名,这样可以充分消除目标服务的不确定性
7.【推荐】Service 组件一般运行主线程,应当避免耗时操作,如果有耗时操作应该在 Worker线程执行。 推荐使
用 IntentService 执行后台任务。
Good:
Bad:
mBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
MyDatabaseHelper myDB = new MyDatabaseHelper(context);
myDB.initData();
// have more database operation here
}
};
public class SingleIntentService extends IntentService {
public SingleIntentService() {
super(“single-service thread”);
}
@Override
protected void onHandleIntent(Intent intent) {
try {

} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class HelloService extends Service {

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Toast.makeText(this, “service starting”, Toast.LENGTH_SHORT).show();
new Thread(new Runnable() {
@Override
public void run() {
//操作语句
}
}).start();

}
}
8.【推荐】对于只用于应用内的广播,优先使用 LocalBroadcastManager 来进行注册和发送,
LocalBroadcastManager 安全性更好,同时拥有更高的运行效率。
说明: 对于使用 Context#sendBroadcast() 等方法发送全局广播的代码进行提示。如果该广播仅用于应用
内,则可以使用 LocalBroadcastManager 来避免广播泄漏以及广播被拦截等安全问题,同时相对全局广播
本地广播的更高效。
Good:
Bad:
public class MainActivity extends ActionBarActivity {
private MyReceiver receiver;
private IntentFilter filter;
private Context context;
private static final String MY_BROADCAST_TAG = “com.example.localbroadcast”;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
receiver = new MyReceiver();
filter = new IntentFilter();
filter.addAction(MY_BROADCAST_TAG);
Button button = (Button) findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent();
intent.setAction(MY_BROADCAST_TAG);
LocalBroadcastManager.getInstance(context).sendBroadcast(intent);
}});
}
@Override
protected void onResume() {
super.onResume();
LocalBroadcastManager.getInstance(context).registerReceiver(receiver, filter);
}
@Override
protected void onPause() {
super.onPause();
LocalBroadcastManager.getInstance(context).unregisterReceiver(receiver);
}
class MyReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context arg0, Intent arg1) {
// message received
}
}
}
所有广播都使用全局广播
9.【推荐】当前Activity的onPause方法执行结束后才会执行下一个Activity的onCreate方法,所以在 onPause 方
法中不适合做耗时较长的工作,这会影响到页面之间的跳转效率。
14.【强制】不要在 Android 的 Application 对象中缓存数据。基础组件之间的数据共享请使用 Intent 等机制,也
可使用 SharedPreferences 等数据持久化机制。
Bad:
//In activity, sending broadcast
Intent intent = new Intent(“com.example.broadcastreceiver.SOME_ACTION”);
sendBroadcast(intent);
class MyApplication extends Application {
String username;
String getUsername() {
return username;
}
void setUsername(String username) {
this.username = username;
}
}
class SetUsernameActivity extends Activity {
void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.set_username);
MyApplication app = (MyApplication) getApplication();
app.setUsername(“tester1”);
startActivity(new Intent(this, GetUsernameActivity.class));
}
}
class GetUsernameActivity extends Activity {
TextView tv;
void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.get_username);
tv = (TextView)findViewById(R.id.username);
}
void onResume() {
super.onResume();
MyApplication app = (MyApplication) getApplication();
tv.setText("Welcome back ! " + app.getUsername().toUpperCase());
}
}
10.【强制】Activity或者Fragment中动态注册BroadCastReceiver时, registerReceiver() 和
unregisterReceiver() 要成对出现。
说明: 如果 registerReceiver() 和 unregisterReceiver() 不成对出现,则可能导致已经注册的receiver
没有在合适的时机注销,导致内存泄漏,占用内存空间,加重 SystemService负担。部分机型会对 receiver 进
行资源管控,单个应用注册过多 receiver 会触发管控模块抛出异常,应用直接崩溃。
Good:
Bad:
Activity 的生命周期不对应,可能出现多次 onResume 造成 receiver 注册多个,但最终只注销一个,其余
receiver 产生内存泄漏。
public class MainActivity extends AppCompatActivity {
private static MyReceiver myReceiver = new MyReceiver();

@Override
protected void onResume() {
super.onResume();
IntentFilter filter = new IntentFilter(“com.example.myservice”);
registerReceiver(myReceiver, filter);
}
@Override
protected void onPause() {
super.onPause();
unregisterReceiver(myReceiver);
}

}
public class MainActivity extends AppCompatActivity {
private static MyReceiver myReceiver;
@Override
protected void onResume() {
super.onResume();
myReceiver = new MyReceiver();
IntentFilter filter = new IntentFilter(“com.example.myservice”);
registerReceiver(myReceiver, filter);
}
@Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(myReceiver);
}
}
UI
1.【推荐】在 Activity 中显示对话框或弹出浮层时,尽量使用 DialogFragment,而非Dialog/AlertDialog,这样便
于随Activity生命周期管理对话框/弹出浮层的生命周期。
Good:
【注意】在我们平时开发的过程中,使用DialogFragment的show,有会出现崩溃,报
IllegalStateExceptionStateLoss 的异常,主要原因是:
我们先看Dialogfragment的源码:
Android支持页面被销毁前通过Activity#onSaveInstanceState() 保存自己的状态。但如果
FragmentTransaction.commit() 发生在 Activity 状态保存之后,就会导致 Activity 重建、恢复状态时无法还原页
面状态,从而可能出错。为了避免给用户造成不好的体验,系统会抛出 IllegalStateExceptionStateLoss 异常。
如何避免这个异常:
1)避免异步调用方法中执行transactions 。这个包括经常被使用的方法比如AsyncTask#onPostExecute() 和
LoaderManager.LoaderCallbacks#onLoadFinished() 。在这些方法中执行transactions会有问题,因为他们当这
些方法被回调的时候,他们不知道Activity当前的生命周期。比如,考虑下面的事件序列:

  1. 一个Activity执行一个AsyncTask
  2. 用户按下Home键,导致这个Activity的onSaveInstanceState() 和onStop() 方法被回调。
  3. AsyncTask完成然后onPostExecute() 被调用,而不知道Activity已经处于stopped状态。
  4. 在onPostExectute() 方法中调用DialogFragment的show() ,导致一个异常被抛出。
    如果你的应用程序需要在这些回调方法中执行transaction,那么没有什么简单方法可以保证这些回调不会再
    onSaveInstanceState()后调用,你可能必须使用commitAllowStateLoss() 并且处理可能发生的状态丢失。(详见两
    篇StackOverFlow文章,文章1、文章2)
    public void showPromptDialog(String text){
    DialogFragment promptDialog = new DialogFragment() {
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle
    savedInstanceState) {
    getDialog().requestWindowFeature(Window.FEATURE_NO_TITLE);
    View view = inflater.inflate(R.layout.fragment_prompt, container);
    return view;
    }};
    promptDialog.show(getFragmentManager(), text);
    }
    public void show(FragmentManager manager, String tag) {
    mDismissed = false;
    mShownByMe = true;
    FragmentTransaction ft = manager.beginTransaction();
    ft.add(this, tag);
    ft.commit();
    }
    补充:show前先调用Activity.isFinishing 进行判断,以免出现状态异常
    2.【强制】禁止在非 ui 线程进行 view 相关操作。
    3.【强制】文本大小使用单位 sp,view 大小使用单位 dp。
    4.【推荐】灵活使用布局,推荐 Merge、ViewStub 来优化布局,尽可能多的减少 UI布局层级,推荐使用
    FrameLayout , LinearLayout 、RelativeLayout 次之。
    5.【推荐】尽量不要使用 AnimationDrawable,它在初始化的时候就将所有图片加载到内存中,特别占内存,并
    且还不能释放,释放之后下次进入再次加载时会报错。
    说明: Android 的帧动画可以使用 AnimationDrawable 实现,但是如果你的帧动画中如果包含过多帧图片,
    一次性加载所有帧图片所导致的内存消耗会使低端机发生 OOM异常。帧动画所使用的图片要注意降低内存消
    耗,当图片比较大时,容易出现 OOM。
    Good: 图片数量较少的 AnimationDrawable 还是可以接受的。
    Bad:
<?xml version="1.0" encoding="utf-8"?>






























上述如此多图片的动画就不建议使用 AnimationDrawable 了。
9.【强制】不能使用 ScrollView 包裹 ListView/GridView/ExpandableListVIew;因为这样会把 ListView 的所有 Item
都加载到内存中,要消耗巨大的内存和 cpu 去绘制图面。
Good:
Bad:









<?xml version="1.0" encoding="utf-8"?>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
当使用Android WorkManager编写代码时,首先需要在的Gradle文件中添加WorkManager依赖项。在app模块的build.gradle文件中,添加以下代码: ```groovy dependencies { def work_version = "2.7.0" implementation "androidx.work:work-runtime-ktx:$work_version" } ``` 接下来,你可以在代码中创建一个Worker类来执行后台任务。Worker类应继承自`androidx.work.Worker`类,并且需要实现`doWork()`方法。`doWork()`方法是在后台线程上运行的,你可以在其中执行耗时任务。 ```kotlin import androidx.work.Worker import androidx.work.WorkerParameters class MyWorker(context: Context, params: WorkerParameters) : Worker(context, params) { override fun doWork(): Result { // 执行后台任务逻辑 // 返回Result.success()表示任务执行成功,可以继续执行下一个任务 // 返回Result.failure()表示任务执行失败,WorkManager会根据重试策略进行重试 // 返回Result.retry()表示任务执行出现临时性错误,WorkManager会根据重试策略进行重试 return Result.success() } } ``` 创建Worker类后,你可以使用WorkManager来调度和运行这个后台任务。下面是一个示例: ```kotlin val constraints = Constraints.Builder() .setRequiredNetworkType(NetworkType.UNMETERED) // 设置网络类型要求 .setRequiresCharging(true) // 设置要求在充电时运行 .build() val workRequest = OneTimeWorkRequestBuilder<MyWorker>() .setConstraints(constraints) // 设置任务约束条件 .build() WorkManager.getInstance(context).enqueue(workRequest) ``` 在上面的示例中,我们创建了一个OneTimeWorkRequest,它表示只运行一次的后台任务。你可以根据需要选择不同的WorkRequest类型,例如PeriodicWorkRequest表示定期运行的后台任务。 这只是一个简单的示例,你还可以使用WorkManager的其他功能,如链式任务、任务重试策略等。你可以参考官方文档以获取更多详细信息:https://developer.android.com/topic/libraries/architecture/workmanager

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

江南一舟110

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值