安卓項目開發總結

安卓項目開發總結

1、網絡請求

  1. 線程+Handlerjava

    • 使用線程池提升應用性能。
  • AsyncTask
  • xUtilsandroid

    • 接口回調。封裝網絡請求,在子線程中執行,根據響應碼判斷結果,經過Handler調用接口的方法,完成對不一樣狀態的不一樣操做。
  • 使用GSON,將JSON字符串轉換爲JavaBean對象。數據庫

備註:HttpClient在Android 6.0中已被移除,可是HttpUrlConnection仍然可使用。canvas

2、數據緩存

  1. 普通數據的緩存緩存

    • 首先判斷本地是否有緩存數據,若是有,先顯示本地數據,若是沒有直接訪問網絡獲取最新數據並保存時間戳。
    • 本地有緩存數據並顯示完畢後,攜帶本地數據對應的時間戳訪問服務器,判斷當前數據是否爲最新數據。
    • 若是是最新數據,再也不執行任何操做。
    • 若是不是最新數據,請求服務器返回最新數據和對應的時間戳,緩存到本地文件或者數據庫中,並進行顯示。
  • 圖片的緩存

3、斷點下載/上傳

  1. 斷點下載性能優化

    • 經過設置range請求頭,請求服務器要獲取文件的字節範圍,去下載指定數據段的文件。
    • 經過DownloadTask執行下載任務,在下載過程當中,每寫一段文件數據就將已寫文件數據大小保存至文件或數據庫,以便下次開始下載的時候用於指定range的範圍。
    • 經過Handler去更新UI界面,若是有多個任務同時進行下載,分別爲每個DownloadTask設置DownloadListener。
    • 爲了不ListView不一樣item顯示錯誤的下載進度,使用ViewHolder對ListView進行優化處理。
  • 斷點上傳服務器

    • 該功能須要服務器支持才能夠進行。

4、業務邏輯

  1. 封裝JavaBean,頁面展現,友盟SDK,百度地圖,支付集成等
  2. 數據存儲(sp存儲,文件存儲,數據庫和網絡存儲)
  3. Service:開啓線程,和服務器保持鏈接,接收服務器推送消息
  4. BroadcaseReceiver:網絡

    • 註冊經常使用廣播事件,判斷本身服務是否在運行,若是服務沒有運行,開啓服務,能夠作到服務長時間在後臺保持運行。
    • 廣播也能夠做爲四大組件間通訊的工具

5、頁面層

  1. Activity框架

    • 抽取BaseActivity,重寫onCreate方法,依次執行initView,initData,initEvent,封裝訪問網絡的操做,在回調結果裏執行子類Activity的操做,須要子類提供的數據可使用抽象方法讓子類去實現或者暴露方法給子類,讓子類去覆寫該方法。
    • 用集合記錄已經打開/關閉的Activity,方便在任何Activity中執行退出應用的操做,退出後還須要調用killProcess(pid),殺死進程。
    • 封裝startAnActivity方法,在BaseActivity中使用一個靜態變量記錄當前應用的Activity是否在棧中的最頂層,若是在,直接開啓Activity,若是不在,新建一個任務棧開啓Activity。
  • Fragment異步

    • show/hide:執行效率高,可是會佔用內存
    • replace:執行效率低,可是內存佔用少
  • 經常使用控件

  • ListView:優化,局部刷新的重點是,找到要更新的那項的View,而後再根據業務邏輯更新數據便可。重寫updateItem方法,更新界面後,對應的數據也要更新,不然下次再滾動到該View的時候可能又還原了。
private void updateItem(int index) {
    int visiblePosition = listView.getFirstVisiblePosition();
    if (index - visiblePosition >= 0) {
        //獲得要更新的item的view
        View view = listView.getChildAt(index - visiblePosition);
 
        // 更新界面(示例參考)
        // TextView nameView = ViewLess.$(view, R.id.name);
        // nameView.setText("update " + index);
        // 更新列表數據(示例參考)
        // list.get(index).setName("Update " + index);
    }
}
  • ViewPager:使用動畫就使用JazzyViewPager
  • LinearLayout
  • RelativeLayout
  • FrameLayout
  • PercentLayout
  1. 自定義控件:能夠拖動的GrideView
  2. 屏幕適配:dp和px的相互轉換,使用百分比佈局
  3. 動畫
    1. 屬性動畫(會改變控件的真實位置,功能強大,代碼複雜)
    2. 補間動畫(不會改變控件的真實位置,包含4種)
      1. 位移動畫
      2. 旋轉動畫
      3. 透明度
      4. 縮放動畫
      5. 組合動畫(以上4中動畫能夠組合爲一個動畫)
    3. 幀動畫(圖片的切換)

6、優化

  1. 佈局優化
    1. include:佈局重用
    2. merge:減小視圖層級,例如你的主佈局文件是垂直佈局,引入了一個垂直佈局的include,這是若是include佈局使用的LinearLayout就沒意義了,使用的話反而減慢你的UI表現。這時可使用 標籤優化。
    3. ViewStub:須要時記載,使用該標籤並不會影響UI初始化時的性能。當調用inflate()函數的時候,ViewStub被引用的資源替代,而且返回引用的view。
    4. 注:ViewStub目前有個缺陷就是還不支持 標籤。
    5. 經過代碼增長或刪除View(addView/removeView)
  2. 代碼優化
    1. 使用註解框架,ButterKnife,Dagger2,xUtils3,lint代碼分析
  3. 內存/性能優化
    1. oom內存溢出,多是由內存泄露致使,經過mat插件進行分析
  4. 電量優化
  5. WebView,HTML5,Android新特性

7、自定義控件

  1. 建立自定義控件
    1. 繼承View/ViewGroup/已有控件(包括佈局控件)
    2. 在3個構造方法中,從參數少的到參數多的,依次調用,能夠實現傳入一個上下文,就能返回一個帶有默認效果的控件,這也是第三個參數的做用。
  2. 自定義控件執行的流程
    1. onMeasure:測量,RatioFrameLayout可讓圖片按照比例顯示的佈局
      1. 兩個參數:widthMeasureSpec/heightMeasureSpec
      2. 每一個參數分別表明寬度的測量規格和高度的測量規格,值爲一個32位的二進制數,前兩位表明測量模式,後三十位表明測量值。
      3. 能夠經過MeasureSpec.getMode得到測量模式
      4. 能夠經過MeasureSpec.getSize得到測量值
      5. 該方法是在當前View的measure方法中調用,因爲不能重寫measure方法,只能重寫onMeasure方法對控件進行測量
    2. onLayout:佈局,自定義流水佈局FlowLayout
      1. 該方法是經過當前View的layout方法中調用,一樣,須要重寫onLayout完成對子控件的佈局
      2. 因爲View沒有子控件,因此該方法只針對ViewGroup
    3. onDraw:繪製,快速索引控件
      1. 在該方法中能夠完成對控件的繪製,須要用到canvas和paint
      2. 不要在該方法中new對象,不然可能形成GC回收不及時致使內存溢出或者GC時致使界面卡頓
  3. 自定義控件的事件處理
    1. onTouchEvent(返回值)
      1. 調用invalidate對控件進行重繪
      2. 返回true,消費事件
      3. 返回false,執行父View的
    2. dispatchTouchEvent:是否分發
      1. 返回true,不分發,事件直接返回不處理
      2. 返回false,分發,
        1. 若是子View是ViewGroup,執行onInterceptTouchEvent判斷是否對事件進行攔截
        2. 若是子View是View,執行onTouchEvent判斷是否對事件進行處理
    3. onInterceptTouchEvent(ViewGroup纔有)
      1. 返回true,對事件進行攔截,直接返回不處理
      2. 返回false,不進行攔截,調用子View的dispatchTouchEvent
    4. requestDisallowInterceptTouchEvent
      1. 子View告訴父容器,不要攔截本身的事件
  4. 經過回調,返回自定義控件的當前狀態
    1. 定義控件的全部狀態
    2. 定義回調接口和回調方法(參數)
    3. 設置成員變量(setXXXListener)
    4. 在適當的位置調用回調方法
    5. 外部在回調方法中執行自定義的任務
  5. 自定義控件的動畫
    1. 幀動畫
    2. 補間動畫
    3. 屬性動畫(性能比補間動畫低)
      1. 插值器(Interpolator)
      2. 估值器(TypeEvaluator)
      3. ValueAnimator(是屬性動畫的核心類)
      4. 參考文檔:Android動畫學習
  6. ViewDragHelper,滑動刪除控件,nineoldandroid.jar(在低版本2.3上執行屬性動畫仍然不會改變控件的真實位置,因此低版本的Android系統不支持屬性動畫)

8、圖片緩存

連接:Android官方培訓課程

  1. 不能致使應用崩潰(OOM),須要進行壓縮處理
    1. 使用xUtils中的BitmapDisplayConfig中的optimizeMaxSizeByView方法對圖片進行壓縮
  2. 不能致使卡頓,須要進行異步加載(使用Thread或者AsyncTask)
  3. 不能顯示錯位,由於快速滑動的時候對圖片進行異步加載,因爲ListView中item的複用可能會致使圖片的錯位顯示,對ListView/GridView中的item設置tag,異步記載完成後對tag進行判斷,若是tag相同才進行顯示。
  4. 加載要快,對已加載的圖片進行緩存
    1. 內存緩存(LruCache),LruCache的本質是使用LinkedHashMap集合,該集合會根據使用的狀況,按照使用頻率進行排序,立即將超出內存大小時,將使用頻率最低的圖片進行移除。
    2. 磁盤緩存
final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);

// Use 1/8th of the available memory for this memory cache.
final int cacheSize = maxMemory / 8;
mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {
    @Override
    protected int sizeOf(String key, Bitmap bitmap) {
        // The cache size will be measured in kilobytes rather than
        // number of items.
        return bitmap.getByteCount() / 1024;
    }
};

9、Handler

  1. 爲何要有Handler?
    1. 主線程不能作耗時操做,須要放在子線程中執行
    2. 子線程不能更新UI,只有主線程才能更新UI,因此須要使用Handler對子線程和主線程之間進行通訊
  2. 使用步驟
    1. new Handler(),該操做只能在主線程中執行
    2. 重寫handleMessage方法
    3. 在子線程中發送消息sendMessage
    4. post能夠延時發送消息
    5. 發送的消息可使用Message.obtain()方式獲取
  3. 消息隊列MessageQueue
    1. Looper.prepare
    2. Looper.loop
  4. 全部的界面操做都依賴於Handler機制
  5. 子線程只須要調用Looper.prepare和Looper.loop,就能夠在這兩行代碼之間使用WindowManager修改UI
  6. 主線程也不能修改子線程建立的UI
  7. Handler是線程間通訊的工具
相關文章
相關標籤/搜索