記一場 Android 技術答疑
之前在Stuq的Android課程中有幸分享了一些關于優化的問題,后期又處理了一些來自網友的問題,這里簡單以文字形式做個整理.
網絡IO應該在哪種形式的線程中執行
-
首先網絡IO一般耗時比較長,有的可能到幾十毫秒
-
由于耗時較長,如果采用單一線程處理,勢必導致后續的請求無法快速執行
-
建議使用線程池來處理達到快速響應和線程的復用。
簡單示例:
private void testDoNetworkRequest() {
int corePoolSize = 5;
int maxPoolSize = 10;
//線程數量超過核心線程數之后的超時時間,即超過這個時間還沒有新的task,多余的線程則銷毀掉。
long keepAliveTime = 10;
ThreadPoolExecutor executor = new ThreadPoolExecutor(corePoolSize, maxPoolSize, keepAliveTime, TimeUnit.SECONDS, new LinkedBlockingDeque<Runnable>());
executor.execute(new Runnable() {
@Override
public void run() {
//Do network IO here
}
});
}
如何優化字符串拼接
-
字符串拼接無法避免的創建StringBuilder對象
-
如果是循環情況下拼接,需要顯式在循環外聲明一個StringBuilder對象
不好的代碼
public void implicitUseStringBuilder(String[] values) {
String result = "";
for (int i = 0 ; i < values.length; i ++) {
result += values[i];//create new StringBuilder object every time
}
System.out.println(result);
}
改進后的代碼
public void explicitUseStringBuider(String[] values) {
StringBuilder result = new StringBuilder();
for (int i = 0; i < values.length; i ++) {
result.append(values[i]);
}
}
使用Handler到底需不需要使用弱引用,什么時候情況下用
-
正常境況下的引用都為強引用,其特點是及時內存溢出也不可以被回收
ArrayList list = new ArrayList();
-
弱引用則會在垃圾回收時被回收掉,因而弱引用解決內存泄露的一種方法。
ArrayList list = new ArrayList();
WeakReference<ArrayList> listWeakRef = new WeakReference<ArrayList>(list);
ArrayList myList = listWeakRef.get();
-
Handler是否需要設置弱引用,取決于它是否可能發生內存泄露
Handler內存泄露的場景
- Message的target變量實際是Handler對象
- Message存放在MessageQueue中
- MessageQueue通常為Looper持有
- Looper和可以認為和線程生命周期相同
- 通常情況下,我們使用匿名內部類的形式創建Handler,而匿名內部類(非靜態內部類)會隱式持有外部類的引用。即如下的mHandler會隱式持有Activity的實例引用。
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
}
};
-
如果有一個延遲很久的消息,可能會導致Activity內存泄露
-
可以使用弱引用解決內存泄露問題
-
也可以在Activity onDestory方法中調用handler.removeCallbacksAndMessages(null);
網絡數據返回先通知界面還是先更新數據庫
- 通常境況下,可以選擇先更新界面再更新數據庫
- 如果數據很重要,建議先更新數據庫在通知界面更新
業務場景:需要定時后臺掃描數據庫,上傳本地照片至云端,定時任務采用何種模式
-
Handler或者Timer定時一般為秒級別的任務,Timer會啟動額外線程,而Handler可以不用。
-
無論是Handler還是Timer都需要依賴于進程存活
-
利用Handler實現定時任務的類: HandlerTimer
-
如果時間較長,則需要使用AlarmManager
-
另外,我們對于這種業務應該優先考慮是否可以基于事件通知。
-
如果是加入媒體庫的文件,我們可以使用registerContentObserver監聽媒體庫文件變化。
static 單例是怎么保證單例的?沒太看明白
-
static變量為類所有
-
staitc只初始化一次,即在調用的時候。
-
如下代碼,STATIC_OBJECT只在第一次調用時初始化,后續調用則不會再執行初始化
public class Example {
public static Object STATIC_OBJECT = new Object();
}
- 使用static機制創建單例
public class SingleInstance {
private SingleInstance() {
}
public static SingleInstance getInstance() {
return SingleInstanceHolder.sInstance;
}
private static class SingleInstanceHolder {
private static SingleInstance sInstance = new SingleInstance();
}
}
把Activity作為參數傳給一個靜態方法,會影響這個Activity的正常銷毀嗎
-
內存泄露與方法是否是靜態與否無關,與內部的方法體實現有關系。
-
內存泄露可以簡單理解成:生命周期長的對象不正確持有了持有了生命周期短的對象,導致生命周期短的對象無法回收。
-
比如Activity實例被Application對象持有,Activity實例被靜態變量持有。
Bitmap優化
-
options.inJustDecodeBounds = true;可以獲取width,height和mimetype等信息,但不會申請內存占用
-
合理進行縮放,一個高分辨率的圖片不僅展示在一個小的imageView中,不僅不會有任何視覺優勢,反而還占用了很大的內存
-
將Bitmap處理移除主線程
-
使用LruCache或者DiskLruCache緩存Bitmap
-
before 2.3 手動調用recycle()方法
多次在生產簽名打包后的apk,出現功能不可用的情況,比方說有個社會化分享功能,寫代碼時都可以正常實現,但簽名生成apk后該功能無法再使用了,點擊分享面板的平臺,沒有任何響應。請問是怎么回事,這種問題解決應該從哪幾個方面入手,希望有一些思路可供參考
-
應該是混淆引起的
-
混淆是將易讀性較好的變量,方法和類名替換成可讀性較差的名稱
-
混淆的目的是為了加大逆向的成本,但不能避免
-
通常混淆的處理是將某些庫不加入混淆
-
第三方的庫不建議混淆
一些需要排除混淆的
-
被native方法調用的java方法
-
供javascript調用的java方法
-
反射調用的方法
-
AndroidManifest中聲明的組件
-
總結:即所有硬編碼的元素(變量,方法,類)
來自:http://www.udpwork.com/item/15888.html