以下總結(jié)全部來源于開發(fā)經(jīng)驗(yàn)積累嘶窄,干貨滿滿的别瞭,有問題請郵箱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岸更、顏色由于是整個(gè)app共用的,所以我不太同意阿里規(guī)約的命名方式膊升,我感覺可以寫一套直接根據(jù)色值查找更合理
比如:白色<color name="color_ffffff">#ffffff</color> 只需要命名一套即可
4坐慰、控件命名可以使用控件名稱縮寫作為前綴,如下:
LinearLayout對應(yīng)ll、RelativeLayout對應(yīng)rl结胀、ConstraintLayout對應(yīng)cl赞咙、ListView對應(yīng)lv
ScollView對應(yīng)sv、TextView對應(yīng)tv糟港、Button對應(yīng)btn攀操、ImageView對應(yīng)iv、CheckBox對應(yīng)cb
RadioButton對應(yīng)rb秸抚、EditText對應(yīng)et
5速和、Android的四大組件:Activity、Fragment剥汤、Service颠放、BroadcastReceiver
Activity間通信可以考慮EventBus,避免數(shù)據(jù)太大報(bào)TransactionTooLargeException
Activity的onSaveInstanceState()方法不是生命周期方法吭敢,不保證一定會(huì)被調(diào)用碰凶,它是Activity意外被銷毀保存Ui狀態(tài)的,只能用于臨時(shí)保存數(shù)據(jù)鹿驼,持久化存儲應(yīng)該放在onPause欲低、onStop中
6、Activity間隱式跳轉(zhuǎn)畜晰,在發(fā)出Intent之前要通過resolveActivity檢查目標(biāo)組件能否找到砾莱,避免報(bào)ActivityNotFoundException的異常,比如:
?if(getPackageManager().resolveActivity(intent, PackageManager.MATCH_DEFAULT_ ONLY) !=null) {
..................
}
7凄鼻、Service的onStartCommand()腊瑟、onBind()不能執(zhí)行耗時(shí)操作,如果需要應(yīng)改用IntentService或者采用異步機(jī)制完成
8块蚌、避免在BroadcastReceiver的onReceiver()中執(zhí)行耗時(shí)操作扫步,可以通過創(chuàng)建IntentService完成
9、Context的sendBroadcast()發(fā)送隱式廣播會(huì)被所有感興趣的receiver接收匈子,避免敏感信息泄露,廣播可以僅限于應(yīng)用內(nèi)闯袒,可以使用LocalBroadcastManager的sendBroadcast()方法,避免敏感信息外泄和Intent攔截風(fēng)險(xiǎn)其徙,比如:
Intent intent = new Intent("my-sensitive-event");
intent.putExtra("event", "this is a test event");
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
10、不要在Activity的onDestory()內(nèi)執(zhí)行釋放工作唾那,比如線程的銷毀闹获、停止,由于onDestory()執(zhí)行的時(shí)機(jī)比較晚龟虎,可以按實(shí)際需要結(jié)合ifFinishing()判斷在Activity的onPause()鲤妥、onStop()中
11棉安、Service組件運(yùn)行在主線程中,避免耗時(shí)操作贡耽,如果有耗時(shí)操作可以使用IntentService執(zhí)行后臺任務(wù)
12菇爪、當(dāng)前Activity的onPause方法執(zhí)行結(jié)束后會(huì)執(zhí)行下一個(gè)Activity的onCreate方法凳宙,所以onPause方法中不適合執(zhí)行耗時(shí)工作氏涩,會(huì)影響頁面間跳轉(zhuǎn)效率是尖。
13饺汹、不要在Application對象緩存全局?jǐn)?shù)據(jù),盡量用Intent傳遞或者SharedPreferences數(shù)據(jù)持久化機(jī)制
14兜辞、Activity或者Fragment中動(dòng)態(tài)注冊的BroadCastReceiver時(shí)逸吵,registerReceiver()和unregisterReceiver()要成對出現(xiàn)
15扫皱、布局盡量扁平化韩脑,防止View渲染經(jīng)過measure扰才、layout衩匣、draw消耗過多時(shí)間,盡量控制每一幀在16毫秒內(nèi)繪制完成生百。
16蚀浆、禁止在布局中多次設(shè)置子View和父View中為同樣的背景造成過度繪制
17市俊、盡量不要使用AnimationDrawable,它在初始化的時(shí)候?qū)⑺袌D片加載到內(nèi)存中滤奈,特別占內(nèi)存蜒程,并且還不能釋放昭躺,容易內(nèi)存溢出
18、不要使用ScrollView包裹LIstView/GridView/ExpandableListView偶垮,因?yàn)樗鼤?huì)把ListView的所有Item都加載到內(nèi)存中似舵,要消耗巨大的內(nèi)存與CPU去繪制圖面碟狞,如果非要用族沃,推薦NestedScrollView脆淹。
19盖溺、不要通過Intent在Android基礎(chǔ)組件之間傳遞大數(shù)據(jù)(binder transaction 緩存為1MB)烘嘱,可能導(dǎo)致OOM蝇庭。
20哮内、Application的業(yè)務(wù)初始化加入進(jìn)程判斷,確保只在自己需要的進(jìn)程初始化纹因,特別是后臺進(jìn)程減少不必要的業(yè)務(wù)初始化。
21从绘、新建線程時(shí)僵井,必須通過線程池提供批什,不允許在應(yīng)用中自行閑時(shí)創(chuàng)建線程乳规。
比如:
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());
//
執(zhí)行任務(wù)
executorService.execute(new Runnnable() {
...
});
22暮的、子線程中不能更新界面冻辩,更新界面必須在主線程中進(jìn)行,網(wǎng)絡(luò)操作不能在主線程中調(diào)用倘感。
23老玛、ThreadPoolExecutor設(shè)置線程存活時(shí)間钧敞,確保空閑時(shí)線程能被釋放余素。
24、謹(jǐn)慎使用Android多進(jìn)程视乐,多進(jìn)程雖然能夠降低主進(jìn)程的內(nèi)存壓力敢茁,但會(huì)有如下問題:
第一佑淀、不能實(shí)現(xiàn)完全退出所有Activity的功能
第二、首次進(jìn)入新啟動(dòng)進(jìn)程頁面會(huì)有延時(shí)的現(xiàn)象(黑屏彰檬、白屏幾秒)
第三伸刃、應(yīng)用內(nèi)多進(jìn)程是,Application實(shí)例化多次逢倍,需要考慮各個(gè)模塊是否都需要在所有進(jìn)程初始化捧颅;
第四、多進(jìn)程間通過SharedPreferencs共享數(shù)據(jù)是不穩(wěn)定
25较雕、SharedPreference提交數(shù)據(jù)時(shí)碉哑,盡量使用Editor的apply(),而非Editor的commit()亮蒋,僅當(dāng)需要確定提交結(jié)果扣典,并據(jù)此有后續(xù)操作是,才用commit()闰蛔。(apply方法提交先寫入內(nèi)存蚤吹,然后異步寫入磁盤二驰,commit方法直接寫入磁盤唬复,頻繁操作的話休建,apply的性能會(huì)優(yōu)于commit);
26、數(shù)據(jù)庫Cursor必須確保使用完后關(guān)閉,以免內(nèi)存泄漏
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男图、多線程操作寫入數(shù)據(jù)庫時(shí),需要使用實(shí)物,避免出現(xiàn)同步問題。
比如:
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谍憔、大數(shù)據(jù)寫入數(shù)據(jù)庫時(shí),請使用事務(wù)或其他能夠提高I/O效率的機(jī)制,保證執(zhí)行速度月而。
比如:
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世杀、加載大圖片或者一次性加載多張圖片所刀,應(yīng)在異步線程中進(jìn)行斩披,圖片加載設(shè)計(jì)到IO操作,以及CPU密集操作绑青,容易引起卡頓。
正例:
class BitmapWorkerTask extends AsyncTask<Integer, Void, Bitmap> {
...
//
在后臺進(jìn)行圖片解碼
@Override
protected Bitmap doInBackground(Integer... params) {
final Bitmap bitmap = BitmapFactory.decodeFile("some path");
return bitmap;
}
...
}
30庇楞、在 ListView吕晌,ViewPager睛驳,RecyclerView乏沸,GirdView 等組件中使用圖片時(shí)炬转,
應(yīng)做好圖片的緩存荐吵,避免始終持有圖片導(dǎo)致內(nèi)存泄露袒哥,也避免重復(fù)創(chuàng)建圖片,引起
性 能 問 題 哩照。建議使用Fresco购桑、Glide等圖片庫漓帚,可以使用系統(tǒng)LruCache緩存:
正例:
private LruCache mMemoryCache;@Override
protected void onCreate(Bundle savedInstanceState) {
...
//
獲取可用內(nèi)存的最大值叨恨,使用內(nèi)存超出這個(gè)值將拋出 OutOfMemory 異常邪狞。LruCache 通
過構(gòu)造函數(shù)傳入緩存值,以 KB 為單位次伶。
final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
// 把最大可用內(nèi)存的 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 與動(dòng)畫
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> {
...
// 在后臺進(jìn)行圖片解碼
@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()回調(diào)中,關(guān)閉當(dāng)前activity正在執(zhí)行的動(dòng)畫豪娜。
33餐胀、使用ARGB_565代替ARGB_888,在不怎么降低視覺效果的前提下瘤载,減少內(nèi)存占用
34否灾、在有強(qiáng)依賴 onAnimationEnd 回調(diào)的交互時(shí),如動(dòng)畫播放完畢才能操作頁
面鸣奔,onAnimationEnd 可能會(huì)因各種異常沒被回調(diào)墨技,建 議 加 上 超 時(shí) 保 護(hù) 或 通 過 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挎狸、未完扣汪,待更新~