記一場 Android 技術答疑

分類:技術 時間:2016-10-25

之前在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


ads
ads

相關文章
ads

相關文章

ad