之前在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 LinkedBlockingDequelt;Runnablegt;()); executor.execute(new Runnable() { @Override public void run() { //Do network IO here } }); }
如何優化字符串拼接
- 字符串拼接無法避免的創建StringBuilder對象
- 如果是循環情況下拼接,需要顯式在循環外聲明一個StringBuilder對象
不好的代碼
public void implicitUseStringBuilder(String[] values) { String result = quot;quot;; for (int i = 0 ; i lt; 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 lt; values.length; i ) { result.append(values[i]); } }
使用Handler到底需不需要使用弱引用,什么時候情況下用
- 正常境況下的引用都為強引用,其特點是及時內存溢出也不可以被回收
ArrayList list = new ArrayList();
- 弱引用則會在垃圾回收時被回收掉,因而弱引用解決內存泄露的一種方法。
ArrayList list = new ArrayList(); WeakReferencelt;ArrayListgt; listWeakRef = new WeakReferencelt;ArrayListgt;(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中聲明的組件
- 總結:即所有硬編碼的元素(變量,方法,類)
關于混淆,請參考文章 讀懂 Android 中的代碼混淆
Tags: 數據庫 安卓開發
文章來源:http://www.udpwork.com/item/15888.html