Android开发注意事项

2021-02-25  本文已影响0人  米开朗琪戈

以下总结全部来源于开发经验积累,干货满满的,有问题请邮箱1057915589@qq.com,感谢!敬礼~

1、安卓xml命名:比如以音乐模块为例
music_activity.xml、music_fragment.xml、music_dialog.xml、music_list_item.xml、

music_recycle_item.xml、music_grid_item.xml等

2、资源文件命名:登录按钮背景资源图片(模块名_功能_控件描述_控件限定词)

base_login_btn_pressed.png、base_login_btn_normal.png

3、颜色由于是整个app共用的,所以我不太同意阿里规约的命名方式,我感觉可以写一套直接根据色值查找更合理

比如:白色<color name="color_ffffff">#ffffff</color> 只需要命名一套即可

4、控件命名可以使用控件名称缩写作为前缀,如下:

LinearLayout对应ll、RelativeLayout对应rl、ConstraintLayout对应cl、ListView对应lv

ScollView对应sv、TextView对应tv、Button对应btn、ImageView对应iv、CheckBox对应cb

RadioButton对应rb、EditText对应et

5、Android的四大组件:Activity、Fragment、Service、BroadcastReceiver

Activity间通信可以考虑EventBus,避免数据太大报TransactionTooLargeException

Activity的onSaveInstanceState()方法不是生命周期方法,不保证一定会被调用,它是Activity意外被销毁保存Ui状态的,只能用于临时保存数据,持久化存储应该放在onPause、onStop中

6、Activity间隐式跳转,在发出Intent之前要通过resolveActivity检查目标组件能否找到,避免报ActivityNotFoundException的异常,比如:

 if(getPackageManager().resolveActivity(intent, PackageManager.MATCH_DEFAULT_ ONLY) !=null) {

..................

}

7、Service的onStartCommand()、onBind()不能执行耗时操作,如果需要应改用IntentService或者采用异步机制完成

8、避免在BroadcastReceiver的onReceiver()中执行耗时操作,可以通过创建IntentService完成

9、Context的sendBroadcast()发送隐式广播会被所有感兴趣的receiver接收,避免敏感信息泄露,广播可以仅限于应用内,可以使用LocalBroadcastManager的sendBroadcast()方法,避免敏感信息外泄和Intent拦截风险,比如:

Intent intent = new Intent("my-sensitive-event");

intent.putExtra("event", "this is a test event");

LocalBroadcastManager.getInstance(this).sendBroadcast(intent);

10、不要在Activity的onDestory()内执行释放工作,比如线程的销毁、停止,由于onDestory()执行的时机比较晚,可以按实际需要结合ifFinishing()判断在Activity的onPause()、onStop()中

11、Service组件运行在主线程中,避免耗时操作,如果有耗时操作可以使用IntentService执行后台任务

12、当前Activity的onPause方法执行结束后会执行下一个Activity的onCreate方法,所以onPause方法中不适合执行耗时工作,会影响页面间跳转效率。

13、不要在Application对象缓存全局数据,尽量用Intent传递或者SharedPreferences数据持久化机制

14、Activity或者Fragment中动态注册的BroadCastReceiver时,registerReceiver()和unregisterReceiver()要成对出现

15、布局尽量扁平化,防止View渲染经过measure、layout、draw消耗过多时间,尽量控制每一帧在16毫秒内绘制完成。

16、禁止在布局中多次设置子View和父View中为同样的背景造成过度绘制

17、尽量不要使用AnimationDrawable,它在初始化的时候将所有图片加载到内存中,特别占内存,并且还不能释放,容易内存溢出

18、不要使用ScrollView包裹LIstView/GridView/ExpandableListView,因为它会把ListView的所有Item都加载到内存中,要消耗巨大的内存与CPU去绘制图面,如果非要用,推荐NestedScrollView。

19、不要通过Intent在Android基础组件之间传递大数据(binder transaction 缓存为1MB),可能导致OOM。

20、Application的业务初始化加入进程判断,确保只在自己需要的进程初始化,特别是后台进程减少不必要的业务初始化。

21、新建线程时,必须通过线程池提供,不允许在应用中自行闲时创建线程。

比如:

int NUMBER_OF_CORES = Runtime.getRuntime().availableProcessors();

int KEEP_ALIVE_TIME = 1;

TimeUnit KEEP_ALIVE_TIME_UNIT = TimeUnit.SECONDS;

BlockingQueue taskQueue = new LinkedBlockingQueue();

ExecutorService executorService = new ThreadPoolExecutor(NUMBER_OF_CORES,NUMBER_OF_CORES*2, KEEP_ALIVE_TIME, KEEP_ALIVE_TIME_UNIT, taskQueue,new BackgroundThreadFactory(), new DefaultRejectedExecutionHandler());

//

执行任务

executorService.execute(new Runnnable() {

...

});

22、子线程中不能更新界面,更新界面必须在主线程中进行,网络操作不能在主线程中调用。

23、ThreadPoolExecutor设置线程存活时间,确保空闲时线程能被释放。

24、谨慎使用Android多进程,多进程虽然能够降低主进程的内存压力,但会有如下问题:

第一、不能实现完全退出所有Activity的功能

第二、首次进入新启动进程页面会有延时的现象(黑屏、白屏几秒)

第三、应用内多进程是,Application实例化多次,需要考虑各个模块是否都需要在所有进程初始化;

第四、多进程间通过SharedPreferencs共享数据是不稳定

25、SharedPreference提交数据时,尽量使用Editor的apply(),而非Editor的commit(),仅当需要确定提交结果,并据此有后续操作是,才用commit()。(apply方法提交先写入内存,然后异步写入磁盘,commit方法直接写入磁盘,频繁操作的话,apply的性能会优于commit);

26、数据库Cursor必须确保使用完后关闭,以免内存泄漏

public void handlePhotos(SQLiteDatabase db, String userId) {

Cursor cursor;

try {

cursor = db.query(TUserPhoto, new String[] { "userId", "content" }, "userId=?", new

String[] { userId }, null, null, null);

while (cursor.moveToNext()) {

// TODO

}

} catch (Exception e) {// TODO

} finally {

if (cursor != null) {

cursor.close();

}

}

}

27、多线程操作写入数据库时,需要使用实物,避免出现同步问题。

比如:

public void insertUserPhoto(SQLiteDatabase db, String userId, String content) {

ContentValues cv = new ContentValues();

cv.put("userId", userId);

cv.put("content", content);

db.beginTransaction();

try {

db.insert(TUserPhoto, null, cv);

// 其他操作

db.setTransactionSuccessful();} catch (Exception e) {

// TODO

} finally {

db.endTransaction();

}

}

28、大数据写入数据库时,请使用事务或其他能够提高I/O效率的机制,保证执行速度。

比如:

public void insertBulk(SQLiteDatabase db, ArrayList users) {db.beginTransaction();

try {

for (int i = 0; i < users.size; i++) {

ContentValues cv = new ContentValues();

cv.put("userId", users[i].userId);

cv.put("content", users[i].content);

db.insert(TUserPhoto, null, cv);

}

//

其他操作db.setTransactionSuccessful();

} catch (Exception e) {

// TODO

} finally {

db.endTransaction();

}

}

29、加载大图片或者一次性加载多张图片,应在异步线程中进行,图片加载设计到IO操作,以及CPU密集操作,容易引起卡顿。

正例:

class BitmapWorkerTask extends AsyncTask<Integer, Void, Bitmap> {

...

//

在后台进行图片解码

@Override

protected Bitmap doInBackground(Integer... params) {

final Bitmap bitmap = BitmapFactory.decodeFile("some path");

return bitmap;

}

...

}

30、在 ListView,ViewPager,RecyclerView,GirdView 等组件中使用图片时,

应做好图片的缓存,避免始终持有图片导致内存泄露,也避免重复创建图片,引起

性 能 问 题 。建议使用Fresco、Glide等图片库,可以使用系统LruCache缓存:

正例:

private LruCache mMemoryCache;@Override

protected void onCreate(Bundle savedInstanceState) {

...

//

获取可用内存的最大值,使用内存超出这个值将抛出 OutOfMemory 异常。LruCache 通

过构造函数传入缓存值,以 KB 为单位。

final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);

// 把最大可用内存的 1/8 作为缓存空间

final int cacheSize = maxMemory / 8;

mMemoryCache = new LruCache(cacheSize) {

@Override

protected int sizeOf(String key, Bitmap bitmap) {

return bitmap.getByteCount() / 1024;

}

};

...

}

public void addBitmapToMemoryCache(String key, Bitmap bitmap) {

if (getBitmapFromMemCache(key) == null) {

mMemoryCache.put(key, bitmap);

}

}

public Bitmap getBitmapFromMemCache(String key) {

return mMemoryCache.get(key);

}

public void loadBitmap(int resId, ImageView imageView) {

final String imageKey = String.valueOf(resId);

- 45 -

七、Bitmap、Drawable 与动画

final Bitmap bitmap = getBitmapFromMemCache(imageKey);

if (bitmap != null) {

mImageView.setImageBitmap(bitmap);

} else {

mImageView.setImageResource(R.drawable.image_placeholder);

BitmapWorkerTask task = new BitmapWorkerTask(mImageView);

task.execute(resId);

}

}

class BitmapWorkerTask extends AsyncTask<Integer, Void, Bitmap> {

...

// 在后台进行图片解码

@Override

protected Bitmap doInBackground(Integer... params) {

final Bitmap bitmap = decodeSampledBitmapFromResource(getResources(),

params[0], 100, 100));

addBitmapToMemoryCache(String.valueOf(params[0]), bitmap);return bitmap;

}

...

}

31、png图片使用tinypng工具压缩处理,减少apk包体积大小

32、在Activity.onPause()或者Activity.onStop()回调中,关闭当前activity正在执行的动画。

33、使用ARGB_565代替ARGB_888,在不怎么降低视觉效果的前提下,减少内存占用

34、在有强依赖 onAnimationEnd 回调的交互时,如动画播放完毕才能操作页

面,onAnimationEnd 可能会因各种异常没被回调,建 议 加 上 超 时 保 护 或 通 过 postDelay 替 代

onAnimationEnd。

正例:View v = findViewById(R.id.xxxViewID);

final FadeUpAnimation anim = new FadeUpAnimation(v);anim.setInterpolator(new AccelerateInterpolator());anim.setDuration(1000);

anim.setFillAfter(true);

anim.setAnimationListener(new AnimationListener() {

@Override

public void onAnimationEnd(Animation arg0) {

//判断一下资源是否被释放了if (v != null) {

v.clearAnimation();

}

}

});

v.startAnimation(anim);

35、未完,待更新~

上一篇下一篇

猜你喜欢

热点阅读