開發(fā)藝術(shù)探索 設(shè)計(jì)模式 個(gè)人讀書筆記

Activity

  • 打開一個(gè)新activity時(shí),舊的activity先回調(diào)onPause(),新的activity才開始啟動(dòng)。所以不要再onPause里做太多耗時(shí)操作。
  • Activity調(diào)用onSaveInstanceState()時(shí)會(huì)委托Window去保存數(shù)據(jù),Window又委托它上面的頂級容器一般是DecorView,然后DecorView又遍歷子View去保存數(shù)據(jù)。一種典型的委托思想。
  • 在intent中設(shè)置標(biāo)記位intent.addFlags來指定啟動(dòng)模式,優(yōu)先級大于在AndroidMenifest文件中指定。
  • 要想讓activity支持隱式啟動(dòng),category.DEFAULT一定要加上哦。
  • URL中的schema有默認(rèn)值:content、file。7.1以后直接使用file的URL會(huì)CRASH,請使用FileProvider。
  • 隱式啟動(dòng)activity請使用intent.resolveActivity(getPackageManager())判斷是否有符合條件的activity。
  • android:exported="true",true表示其他應(yīng)用可以打開這個(gè)activity,同樣適用于service、contentprovider。
  • 如果不想讓activity出現(xiàn)在最近打開列表,設(shè)置android:excludeFromRecents="true"。
  • Scheme跳轉(zhuǎn)協(xié)議:可以在瀏覽器中根據(jù)url跳轉(zhuǎn)到activity。詳細(xì)參考:http://blog.csdn.net/qq_23547831/article/details/51685310
  • Activity的啟動(dòng)過程:有點(diǎn)復(fù)雜,死記硬背沒得用,先占坑。

IPC

跟著書走了一遍,還是有點(diǎn)蒙,想要真正掌握這個(gè)點(diǎn),我想還是需要實(shí)際項(xiàng)目的經(jīng)驗(yàn)。初步認(rèn)識(shí)了Binder。Binder指的是一種跨進(jìn)程通信方式,比如說AIDL使用Binder進(jìn)行通信,指的就是這種IPC機(jī)制。

對于開發(fā)人員來講,Binder是Android中的一個(gè)可以幫助你進(jìn)行跨進(jìn)程通信的類,是客戶端和服務(wù)端進(jìn)行通信的媒介。Binder驅(qū)動(dòng)會(huì)對Binder對象進(jìn)行特殊處理,幫助你完成數(shù)據(jù)的轉(zhuǎn)換。

(服務(wù)端實(shí)現(xiàn)的Binder對象返回一個(gè)代理對象到客戶端,客戶端對這個(gè)代理Binder對象進(jìn)行操作,會(huì)通過Binder驅(qū)動(dòng)轉(zhuǎn)發(fā)到服務(wù)端的本地Binder對象上去。Binder驅(qū)動(dòng)會(huì)對這個(gè)對象進(jìn)行特殊處理,幫助你完成數(shù)據(jù)的轉(zhuǎn)換)

在安卓framework層中,ServiceManager通過Binder連接了各種Manager,比如WindowManager、ActivityManager等等。。。android中常用的實(shí)現(xiàn)IPC的方式,Bundle,文件共享,AIDL,Messenger,CP、Socket。

View

View的屬性top、left、right、bottom,x、y,translationX、translationY。

x,y是View的左上角坐標(biāo),換算關(guān)系如下:

x = left + translationX ;

y = top + translationY ;

view在平移的過程中,改變的是x、y、translationX、translationY這四個(gè)屬性,t、l、r、b不會(huì)發(fā)生改變,這四個(gè)屬性在onLayout()之后就確定了。

  • TouchSlop,一個(gè)常量,在不同的設(shè)備上可能有不同的值。它代表最小的滑動(dòng)距離,大于這個(gè)值,可以認(rèn)為用戶是在滑動(dòng),使用ViewConfiguration.get(getContext()).getScaledTouchSlop()得到。
  • VelocityTracker,addMovement(MotionEvent ev)添加事件,然后通過設(shè)定時(shí)間間隔計(jì)算出X、Y方向的速度。使用完成之后務(wù)必釋放資源:clear(),recycle();

  • GestureDetector,手勢檢測,如果你的自定義View需要檢測用戶的單擊、長按、雙擊等行為,使用它會(huì)比較方便。如果只需要檢測滑動(dòng),就直接在onTouchEvent中處理吧。

  • scrollTo/By,對View的內(nèi)容進(jìn)行移動(dòng)。

  • 事件分發(fā)機(jī)制:

      public boolean dispatchTouchEvent(MotionEvent ev){
      boolean consume = false;
      if(onInterceptTouchEvent(ev)){
          //如果攔截事件
          consume = onTouchEvent(ev);
      } else {
          //把事件交給子View
          consume = child.dispatchTouchEvent(ev);
          }
      
      return consume;
      }
    
  • ViewRoot連接WindowManager和DecorView的紐帶。View的繪制從ViewRoot的performTraverSals開始,完成DecorView的measure、layout、draw。

  • DecorView:頂級View。

  • MeasureSpec,一個(gè)32位的int值,一個(gè)值其實(shí)包含了兩個(gè)值:高2位是測量模式,低30位是測量尺寸。提供了打包解包方法。

  • 根據(jù)子View的LayoutParams和父View的MeasureSpec還有子View的margin和padding值來確定子View的MeasureSpec,比如在ViewGroup的measureChilWithMargins()方法的實(shí)現(xiàn)。

  • Measure過程:ViewGroup.onMeasure()里測量子View:measureChild()里getChildMeasureSpec()然后調(diào)用child.measure();然后View的onmeasure()里setMeasureDimension(getDefaultSize(),getDefaultSize()),getDefaultSize()默認(rèn)返回measureSpec的測量數(shù)值。這個(gè)時(shí)候測量的寬高就可以確定了??梢酝ㄟ^getMeasureHeight/Width獲取到值了。

  • Layout過程:最外層的ViewGroup的先layout(l,t,r,b),中使用setFrame()設(shè)置本View的四個(gè)頂點(diǎn)位置。在onLayout(抽象方法)中確定子View的位置,如LinearLayout會(huì)遍歷子View,循環(huán)調(diào)用setChildFrame()-->子View.layout()。在onLayout()之后會(huì)確定View的left,top,right,bottom屬性,這時(shí)可以通過getHeight/Width()獲取真實(shí)寬高了。

  • 最外層ViewGroup的draw():其中會(huì)先后調(diào)用background.draw()(繪制背景)、onDraw()(繪制自己)、dispatchDraw()(繪制子View)、onDrawScrollBars()(繪制裝飾)。

  • 讓自定義View支持wrap_content,需要在onMeasure()中對wrap_content進(jìn)行特殊處理。具體情況具體處理。

  • 自定義View:定義自定義屬性,獲取自定義屬性,onMeasure,onLayout(一般自定義ViewGroup根據(jù)需要去實(shí)現(xiàn)),onDraw,如有需要,別忘了處理點(diǎn)擊事件。

  • 獲取measure()后的寬高:
    1.Activity#onWindowFocusChange()中調(diào)用獲取
    2.view.post(Runnable)將獲取的代碼投遞到消息隊(duì)列的尾部。
    3.ViewTreeObservable。

  • 熟悉View的彈性滑動(dòng)、布局參數(shù)、滑動(dòng)沖突、繪制步驟與原理、使用動(dòng)畫、SVG矢量圖的使用等,在平時(shí)開發(fā)中注意積累經(jīng)驗(yàn),學(xué)會(huì)融會(huì)貫通,自定義View就會(huì)得心應(yīng)手了。

動(dòng)畫

  • View動(dòng)畫:平移動(dòng)畫<translate>,縮放動(dòng)畫<scale>,旋轉(zhuǎn)動(dòng)畫<rotate>,透明度動(dòng)畫<alpha>。
  • 幀動(dòng)畫:順序播放一組預(yù)先定義好的圖片。
  • 屬性動(dòng)畫:可以對任意對象的屬性做變化,在一個(gè)時(shí)間間隔內(nèi)對對象的屬性從一個(gè)值到另一個(gè)值。View動(dòng)畫不真正改變View的屬性,屬性動(dòng)畫是真正的改變屬性,要求屬性提供get/set方法。
  • 如果想使用屬性動(dòng)畫改變一個(gè)屬性,然而卻沒有g(shù)et/set方法,則可以用一個(gè)類來包裝原始對象,間接的為其提供get/set方法。
  • 插值器和估值器,用來實(shí)現(xiàn)非勻速動(dòng)畫。

Window和WindowManager

  • Window,一個(gè)窗口的概念,起到了承載視圖的作用,是View的直接管理者。每一個(gè)Window都對應(yīng)著一個(gè)View和一個(gè)ViewRootImpl,Window和View通過ViewRootImpl來建立聯(lián)系。
  • 只能使用WindowManager來管理Window,WindowManager有三個(gè)接口方法:addView,updateViewLayout以及removeView。
  • Window的添加過程:WindowManager的實(shí)現(xiàn)類WindowManagerImpl.addView---->然后委托WindowManagerGlobal類進(jìn)一步操作:1:檢查window。2,創(chuàng)建ViewRootImpl并將View添加。3,通過ViewRootImpl更新界面,然后使用IPC和WindowManagerService進(jìn)行通信,交給WMS完成Window的添加。
  • Activity中Window的創(chuàng)建過程:在Activity的attach方法里,系統(tǒng)會(huì)由Policy類創(chuàng)建Window的實(shí)現(xiàn)類PhoneWindow。并設(shè)置回調(diào)CallBack接口(onAttachedToWindow()、dispatchTouchEvent()等等),然后創(chuàng)建DecorView,然后通過Activity#setContentView()調(diào)用PhoneWindow的setContentView把布局添加到DecorView里。最后使用WindowManager.addView通知遠(yuǎn)端WMS,然后才真正完成了添加和顯示過程。
  • Window的實(shí)體是存在于遠(yuǎn)端的WindowMangerService中,所以增刪改Window在本端是修改是通過ViewRootImpl重繪View,通過WindowSession(每個(gè)應(yīng)用一個(gè))在遠(yuǎn)端修改Window。
  • 有View的地方就會(huì)有Window,比如在Activity,Dialog,Toast,PopUpWindow,Menu等視圖都對應(yīng)著一個(gè)Window。所以一個(gè)應(yīng)用有幾個(gè)Window?

Android中的消息機(jī)制

隨便記,不涉及原理。

  • Handler:在主線程創(chuàng)建一個(gè)Handler,在其他線程調(diào)用sendMessage()發(fā)出消息,此時(shí)主線程的MessageQueue中會(huì)插入一條message,然后Looper會(huì)把消息取出,然后在主線程Handler中的handlerMessage方法中處理消息。
  • MessageQueue:消息隊(duì)列,使用一個(gè)單鏈表維護(hù)消息。enqueueMessage方法是往消息隊(duì)列中插入一條消息,next方法是從消息隊(duì)列讀取一條消息并刪除消息。next方法會(huì)無限循環(huán)。
  • Looper:Looper創(chuàng)建的時(shí)候會(huì)創(chuàng)建一個(gè)MessageQueue,調(diào)用loop()方法的時(shí)候消息循環(huán)開始,loop()也是一個(gè)死循環(huán),會(huì)不斷調(diào)用messageQueue的next(),當(dāng)有消息就處理,否則阻塞在messageQueue的next()中。當(dāng)Looper的quit()被調(diào)用的時(shí)候會(huì)調(diào)用messageQueue的quit(),此時(shí)next()會(huì)返回null,然后loop()方法也跟著退出。
  • ThreadLocal:使用ThreadLocal,可以實(shí)現(xiàn)同一個(gè)變量在不同的線程存儲(chǔ)不同的值。對應(yīng)有g(shù)et/set方法。原理:還沒弄懂。
  • 為什么只能在主線程操作UI:因?yàn)閁I操作較為復(fù)雜,多線程同時(shí)操作可能會(huì)導(dǎo)致不可預(yù)期的情況,而如果使用加鎖管理,則邏輯變得更復(fù)雜而且降低效率。所以使用了單線程模型來管理UI操作。APP啟動(dòng)時(shí),主線程被創(chuàng)建。在其他線程操作UI時(shí),在ViewRootImpl中會(huì)檢查線程,如果不是主線程則會(huì)拋出異常。

Android中的多線程

除了在java的多線程知識(shí),在android中,還需要了解在android在Thread的基礎(chǔ)上封裝的幾個(gè)類,AsyncTask、HandlerThead、IntentService。

  • AsyncTask:一個(gè)輕量級的異步任務(wù)抽象類,使用時(shí)需要繼承它然后實(shí)現(xiàn)它的4個(gè)核心方法。AsyncTask里使用到了線程池。需要特別注意的是:在不同的SDK版本中,AsycnTask的實(shí)現(xiàn)會(huì)有差異。android 3.0之后默認(rèn)是串行執(zhí)行的,也可以通過executeOnExecutor方法來并行執(zhí)行任務(wù)。

  • HandlerThread:繼承自Thread,一個(gè)可以使用Handler的Thread。在內(nèi)部創(chuàng)建了一個(gè)Looper,也就是在內(nèi)部創(chuàng)建了消息隊(duì)列,外部可以發(fā)送消息到HandlerThread,然后它會(huì)執(zhí)行特定任務(wù)。

  • IntentService:繼承自Service,抽象類。因?yàn)槭欠?wù),所以優(yōu)先級較高,而且在異步任務(wù)執(zhí)行完成后,會(huì)自動(dòng)停止。IntentService封裝了HandlerThread和Handler。我們重寫onHandleIntent(Intent intent)方法,在里面根據(jù)intent中所包含的信息進(jìn)行判斷,然后進(jìn)行執(zhí)行特定任務(wù)。so easy!

  • 在多線程編程的時(shí),如果有多個(gè)線程同時(shí)對同一個(gè)對象進(jìn)行操作的情況,可以使用一些能夠保證線程安全的類比如Vector、StringBuffer、ConcurrentHashMap等。

  • Android中的線程池:首先,使用線程池能給我們帶來什么好處呢?1.使用線程池來管理線程,可以有效避免線程頻繁創(chuàng)建和銷毀所帶來的性能損耗和資源浪費(fèi)。線程池會(huì)對線程進(jìn)行重用。2,能有效的控制最大并發(fā)數(shù),提高系統(tǒng)資源利用率。3,提供了定時(shí)任務(wù)、定期執(zhí)行、指定間隔循環(huán)執(zhí)行等管理功能。

  • ThreadPoolExecutor,它的構(gòu)造方法提供了一系列參數(shù)來配置線程。

      int corePoolSize ;//線程池的核心線程數(shù)
      int maximumPoolSize;//線程池所能容納的最大線程數(shù)。
      long keepAliveTime; //非核心線程閑置時(shí)間的超時(shí)時(shí)長。
      TimeUnit unit;//指定keepAliveTime參數(shù)的時(shí)間單位。
      BlockingQueue<Runnable> workQueue;//線程池中的人物隊(duì)列,通過execute方法提交的Runnable對象會(huì)存儲(chǔ)在這個(gè)參數(shù)中。
      ThreadFactory threadFactory;//線程工廠,為線程池提供創(chuàng)建新線程的功能。它是一個(gè)接口,只有一個(gè)方法:Thread newThread(Runnable r)。
    

以上就是主要的參數(shù),還有一些不常用參數(shù)未列出。

Android中常見的四類具有不同功能特性的線程池,他們都直接或間接地通過配置ThreadPoolExecutor來實(shí)現(xiàn)自己的功能特性。

  1. FixedThreadPool:通過Executors的newFixedThreadPool(int nThreads)來創(chuàng)建。它是一種線程數(shù)量固定的線程池。
  2. CachedThreadPool:一種縣城數(shù)量不定的線程池,它只有非核心線程,并且最大線程數(shù)為Integer.MAX_VALUE。線程超時(shí)時(shí)間為60秒,超時(shí)則會(huì)被回收。這個(gè)線程池比較適合執(zhí)行大量的耗時(shí)較少的任務(wù)。當(dāng)線程池處于閑置狀態(tài)時(shí),所有線程都會(huì)被超時(shí)回收,和上面的FixedThreadPool不一樣。
  3. ScheduledThreadPool:這個(gè)線程池的核心線程數(shù)固定,最大線程數(shù)沒有限制。并且當(dāng)非核心線程閑置時(shí)會(huì)被立即回收。這類線程池主要用于執(zhí)行定時(shí)任務(wù)和具有固定周期的重復(fù)任務(wù)。
  4. SingleThreadExecutor:這類線程池內(nèi)部只有一個(gè)核心線程,它確保所有的任務(wù)都在同一個(gè)線程中按順序執(zhí)行。SingleThreadExecutor的意義在于統(tǒng)一所有的外界任務(wù)到一個(gè)線程中去執(zhí)行。所以在線程同步問題上不需要去過多地去考慮。

對了,這兩年出現(xiàn)了一個(gè)特別牛B的庫:RxJava。異步、簡潔的鏈?zhǔn)秸{(diào)用。這個(gè)Cool得不行的響應(yīng)式編程框架一用根本停不下來,沒用過的可以去試試!

Bitmap和Cache

  • Bitmap的高效加載:使用BitmapFactory.Options里的inSampleSize參數(shù),即采樣率。當(dāng)inSampleSzie為1時(shí),采樣后圖片大小為原始大小,當(dāng)inSampleSize為2時(shí),那么采樣后的寬高為原始寬高的1/2,即占用內(nèi)存大小變?yōu)?/4。計(jì)算出正確的采樣率,然后設(shè)置給BitmapFactory的四個(gè)加載Bitmap的方法。就可以加快圖片加載速度以及減少內(nèi)存的消耗,就可以有效的避免OOM了。
  • Android中的緩存策略:一般的圖片加載框架都有著3級緩存機(jī)制,即內(nèi)存-磁盤-網(wǎng)絡(luò)。先看內(nèi)存緩存,再查找磁盤緩存,都沒有緩存的話再從網(wǎng)絡(luò)中加載。目前常用的緩存算法為LRU(Least Recently Used),即近期最少使用算法。會(huì)優(yōu)先淘汰掉近期最少使用的緩存對象。
  • LruCache:一個(gè)內(nèi)存緩存工具類,內(nèi)部采用一個(gè)LinkedHashMap以強(qiáng)引用的方式存儲(chǔ)外界的緩存對象。提供了get/put方法完成緩存的獲取和添加操作。使用的時(shí)候只需要提供緩存的總?cè)萘看笮∪缓笾貙憇izeOf方法來計(jì)算單個(gè)緩存對象的大小方法就可以了。
  • DiskLruCache:上面是內(nèi)存緩存,這個(gè)一看名字就懂了,DiskLruCache就是用于實(shí)現(xiàn)存儲(chǔ)設(shè)備,一般是磁盤緩存的了。它通過講緩存對象寫入文件系統(tǒng)來實(shí)現(xiàn)緩存。DiskLruCache的使用方法相對比較復(fù)雜。請查閱相關(guān)的具體文檔。
  • 如何實(shí)現(xiàn)一個(gè)ImageLoader:大概的說一下
    • 使用線程與線程池實(shí)現(xiàn)圖片的異步加載
    • 圖片的同步加載
    • 圖片的壓縮,避免OOM。使用BitmapFactory加載正確尺寸。
    • 緩存功能:使用LruCache和DiskLruCache實(shí)現(xiàn)緩存功能。
    • 網(wǎng)絡(luò)拉取功能:使用網(wǎng)絡(luò)從服務(wù)器上獲取圖片,把文件輸出流轉(zhuǎn)化為Bitmap。

我看過google出品的圖片加載框架gilde的代碼總體架構(gòu),只能說驚了。過一段時(shí)間我會(huì)動(dòng)手寫一個(gè)ImageLoader來練手。。。以熟悉設(shè)計(jì)模式、網(wǎng)絡(luò)請求、內(nèi)存優(yōu)化以及上邊的知識(shí)點(diǎn)等等。加油加油。

綜合技術(shù)

  • 使用CrashHandler來獲取應(yīng)用的crash信息:寫一個(gè)類實(shí)現(xiàn)UncaughtExceptionHandler接口,重寫uncaughtException方法,可以獲取到未catch的crash信息。然后做相應(yīng)處理,寫入文件,下一次再上傳到服務(wù)器什么的。不過現(xiàn)在app一般會(huì)使用騰訊Bugly等SDK來獲取crash信息了,比較專業(yè)。
  • 使用multidex來解決方法數(shù)65536:這個(gè)在Gradle里配置一下就好了。還可以使用插件化來解決這個(gè)65536。
  • Android插件化技術(shù):也叫動(dòng)態(tài)加載技術(shù)。先占坑。。。研究ing。。
  • 反編譯技術(shù):smail....占坑。

JNI和NDK編程

  • JNI:Java Native Interface 。通過JNI,可以用java調(diào)用native的C、C++方法。

  • NDK:是Android所提供的一個(gè)工具集合,通過NDK可以在Android中更加方便地通過JNI來訪問本地代碼。使用NDK有如下好處:

    • 提高代碼的安全性,由于so庫反編譯比較困難,相對來講的。所以NDK提高了程序安全性。
    • 可以很方便的使用已有的C/C++開源庫。
    • 便于平臺(tái)間的移植。通過C/C++實(shí)現(xiàn)的動(dòng)態(tài)庫可以很方便的在其他平臺(tái)上使用。
    • 提高程序在某些特定情形下的執(zhí)行效率,但是并不能明顯提升Android程序的性能。
  • JNI的開發(fā)流程:

    1. 在java中聲明native方法。
    2. 編譯java源文件得到class文件,然后通過javah命令導(dǎo)出JNI的頭文件。
    3. 實(shí)現(xiàn)JNI方法。
    4. 編譯so庫并在java中調(diào)用。
  • NDK的開發(fā)流程:

    1. 下載并配置NDK。
    2. 創(chuàng)建android項(xiàng)目,并聲明所需的native方法。
    3. 實(shí)現(xiàn)Android項(xiàng)目中的native方法。
    4. 切換到j(luò)ni目錄的父目錄,然后通過ndk-build命令編譯產(chǎn)生so庫。
  • JNI調(diào)用java方法的流程:先通過類名找到類,然后再根據(jù)方法名找到方法的id,最后就可以調(diào)用這個(gè)方法了。如果調(diào)用的是非靜態(tài)方法,那么還需要構(gòu)造出類的對象。詳細(xì)步驟略。

Android性能優(yōu)化

  • 布局優(yōu)化:
    • 減少布局文件中的層級嵌套,能用一個(gè)ViewGroup解決的,就別用2個(gè)。
    • 使用<include>標(biāo)簽和<merge>標(biāo)簽搭配,以重用布局和減少布局層級。
    • ViewStub,ViewStub繼承了View,它非常輕量級,不參與任何的布局和繪制過程。使用ViewStub可以實(shí)現(xiàn)按需加載,即需要加載某個(gè)界面的時(shí)候再加載,這個(gè)界面或許不會(huì)出現(xiàn),需要出現(xiàn)了再去加載。可以提高資源利用率。比如說加載網(wǎng)絡(luò)錯(cuò)誤界面。
  • 繪制優(yōu)化:繪制優(yōu)化是指View的onDraw方法要避免執(zhí)行大量的操作。
    • 不要在onDraw中創(chuàng)建新的布局對象。
    • 不要在onDraw中執(zhí)行耗時(shí)的任務(wù)。

其實(shí)不僅是onDraw,在onMeasure和onLayout中也要盡量注意。優(yōu)化我們的算法邏輯。以提高性能。

  • 內(nèi)存泄漏優(yōu)化:內(nèi)存泄漏,老生常談了。一般是指無用的對象的引用被持有,導(dǎo)致無用對象不能被回收而停留在內(nèi)存中,使內(nèi)存得不到釋放的一種情況。在平時(shí)的android開發(fā)中,需要注意以下幾點(diǎn):

    • 靜態(tài)變量導(dǎo)致的內(nèi)存泄漏。在靜態(tài)變量中持有其他變量的引用,會(huì)導(dǎo)致那個(gè)變量的內(nèi)存的不到釋放。
    • 單例模式導(dǎo)致的內(nèi)存泄漏:和上面差不多,可以使用弱引用或者使用application的context。
    • 屬性動(dòng)畫導(dǎo)致的內(nèi)存泄漏:使用屬性動(dòng)畫播放無限循環(huán)的動(dòng)畫時(shí),記得停止。
    • 注冊沒取消、資源沒關(guān)閉的造成的內(nèi)存泄漏:比如廣播接收器,Cursor。
    • 匿名內(nèi)部類和非靜態(tài)內(nèi)部類持有外部類的引用造成的內(nèi)存泄漏:比如說我們常用的Handler,使用不當(dāng)就很容易造成內(nèi)存泄漏。
    • WebView造成的泄露,講道理webview坑比較多。
  • 響應(yīng)速度優(yōu)化:比如說不要在onPause中執(zhí)行太多操作,會(huì)減慢新activity的顯示速度。多使用線程做計(jì)算、耗時(shí)操作。即使給予用戶反饋,比如說加載新頁面馬上顯示loading。。。等。

  • ListView和Bitmap優(yōu)化:ViewHolder的使用、快速滑動(dòng)時(shí)不要開啟大量線程任務(wù)。Bitmap優(yōu)化上面也介紹過了。

  • 線程優(yōu)化:使用線程池,可以有效提高系統(tǒng)資源利用率。

  • 其他:

    • 避免創(chuàng)建過多的對象。
    • 盡量避免使用枚舉。
    • 常量使用static final修飾。
    • 使用Android特有的數(shù)據(jù)結(jié)構(gòu):比如SparseArray、Pair等,這些數(shù)據(jù)結(jié)構(gòu)在移動(dòng)平臺(tái)上使用更少的內(nèi)存,具有較好的性能。
    • 適當(dāng)使用軟引用和弱引用。
    • 使用緩存。

待完善。。。

設(shè)計(jì)模式 個(gè)人筆記

面向?qū)ο罅笤瓌t

  • 單一職責(zé)原則:一個(gè)類只負(fù)責(zé)做好一件事情。
  • 開閉原則:對于拓展是開放的,對于修改是封閉的。也就是說,我們應(yīng)該通過拓展來實(shí)現(xiàn)變化,而不是修改原有代碼。當(dāng)然了,這只是一種理想狀態(tài),實(shí)際開發(fā)中不要太拘泥于此。
  • 里氏替換原則:所有引用基類的地方必須能夠透明地使用其子類的對象。也就是多態(tài)這個(gè)特性的正確使用方法咯。
  • 依賴倒置原則:主要是實(shí)現(xiàn)解耦,使得高層次的模塊不依賴于低層次模塊的具體實(shí)現(xiàn)細(xì)節(jié)。依賴于抽象類型:抽象類或接口。比如:各個(gè)模塊之間相互傳遞的參數(shù)聲明為抽象類型,而不是聲明為具體的實(shí)現(xiàn)類。
  • 接口隔離原則:類之間的依賴關(guān)系應(yīng)該建立在最小的接口上。其原則是將非常龐大的、臃腫的接口拆分成更小的更具體的接口。
  • 迪米特原則:一個(gè)對象應(yīng)該對其他的對象有最少的了解。比如說:假設(shè)類A實(shí)現(xiàn)了某個(gè)功能,類B需要調(diào)用類A的去執(zhí)行這個(gè)功能,那么類A應(yīng)該只暴露一個(gè)函數(shù)給類B,這個(gè)函數(shù)表示是實(shí)現(xiàn)這個(gè)功能的函數(shù),而不是讓類A把實(shí)現(xiàn)這個(gè)功能的所有細(xì)分的函數(shù)暴露給B。

設(shè)計(jì)模式

單例模式

單例模式就不用過多的介紹了。下面列兩種推薦寫法:

  • 靜態(tài)內(nèi)部類單例模式:

      public class Singleton{
          private Singleton(){}
          public static Singleton getInstance(){
              return SingletonHolder.sInstance;
          }
          
          private static class SingletonHolder{
              private static final Singleton sInstance = new Singleton();
          }
      }
    

在第一次調(diào)用Singleton的getInstance方法時(shí),JVM會(huì)加載SingletonHolder類,因?yàn)檫@一步發(fā)生在JVM,所以保證了線程安全與單例對象的唯一性,同時(shí)還有延遲加載的效果。

  • 枚舉單例模式:

      public enum Singleton{
          INSTANCE;
          public void dosomething(){......}
      }
    

是的沒錯(cuò),就是如此的簡單。枚舉單例模式不僅寫法簡單,而且在保證了線程安全與唯一性的同時(shí),還保證了反序列化時(shí)不會(huì)重新生成對象??梢哉f這種寫法是目前單例模式的最佳寫法。

  • 什么時(shí)候該使用單例模式?

    需要確保類有且只有一個(gè)對象時(shí),比如說有一個(gè)進(jìn)行網(wǎng)絡(luò)請求的倉庫類,這個(gè)類消耗的系統(tǒng)資源較多,而且不需要存在多個(gè)實(shí)例的時(shí)候。在android framework中,Application類就是一個(gè)單例類,在整個(gè)APP運(yùn)行過程中,僅存在一個(gè)Application對象(單進(jìn)程)。

Builder模式(建造者模式)

Builder模式的定義:將一個(gè)復(fù)雜對象的構(gòu)建與它的表示分離,使得同樣的構(gòu)建過程可以創(chuàng)建不同的表示。
相對于直接在javabean里使用setter,builder模式更加易讀,在調(diào)用build()方法之后才返回相應(yīng)的對象,保證了對象的一致性。

public class MyBuilder{
    private int id;
    private String num;
    public MyData build(){
        MyData d=new MyData();
        d.setId(id);
        d.setNum(num);
        return t;
        //build之后返回組裝好的對象。
        //在這里可以對設(shè)置數(shù)據(jù)的調(diào)用順序進(jìn)行正確的控制。
    }
    public MyBuilder setId(int id){
        this.id=id;
        return this;
    }
    //返回自身this,用于鏈?zhǔn)秸{(diào)用。
    public MyBuilder setNum(String num){
        this.num=num;
        return this;
    }

}

public class Test{
    public static void  main(String[] args){
        MyData d=new MyBuilder().setId(10).setNum("hc").build();
    }

 }

什么時(shí)候使用builder模式呢?

  • 相同的方法,不同的執(zhí)行順序,產(chǎn)生不同的事件結(jié)果時(shí)。
  • 多個(gè)部件或者零件,都可以裝配到一個(gè)對象中,但是產(chǎn)生時(shí)運(yùn)行結(jié)果又不相同時(shí)。
  • 產(chǎn)品類非常復(fù)雜,或者產(chǎn)品類中的調(diào)用順序不同產(chǎn)生了不同的作用,這個(gè)時(shí)候使用建造者模式非常合適。
  • 當(dāng)初始化一個(gè)對象特別復(fù)雜,如參數(shù)多,且很多參數(shù)都具有默認(rèn)值時(shí)。

Android中的builder模式

AlertDialog.Builer builder=new AlertDialog.Builder(context);
builder.setIcon(R.drawable.icon)
        .setTitle("title")
        .setMessage("message")
        .setPositiveButton("Button1", 
            new DialogInterface.OnclickListener(){
                public void onClick(DialogInterface dialog,int whichButton){
                    setTitle("click");
                }   
            })
        .create()
        .show();

熟悉吧!看著這一串的鏈?zhǔn)秸{(diào)用,是不是很舒服呢~~

工廠方法模式

定義:定義一個(gè)用于創(chuàng)建對象的接口,讓子類決定實(shí)例化哪個(gè)類。

//抽象產(chǎn)品
public abstract class Product{
    public abstract void method();
} 

//具體產(chǎn)品A
public class ConcreteProductA extends Prodect{
    public void method(){
        System.out.println("我是產(chǎn)品A!");
    }
}
//具體產(chǎn)品B
public class ConcreteProductB extends Prodect{
    public void method(){
        System.out.println("我是產(chǎn)品B!");
    }
}
//抽象工廠
public  abstract class Factory{
    public abstract Product createProduct();
}

//具體工廠
public class MyFactory extends Factory{
    //這里可以設(shè)置一個(gè)參數(shù),讓參數(shù)決定實(shí)例化哪個(gè)類。
    public Product createProduct(){
        return new ConcreteProductA();
    }
}

這里主要分為四大模塊:抽象工廠、具體工廠、抽象產(chǎn)品與具體產(chǎn)品。

在客戶端中,我們需要哪個(gè)產(chǎn)品,就在工廠中生產(chǎn)哪個(gè)產(chǎn)品。

在Android中,我們經(jīng)常會(huì)通過Context.getSystemService(String name)方法獲取系統(tǒng)級的服務(wù),在這個(gè)方法里,通過我們傳入的服務(wù)名稱字符參數(shù)來決定返回哪一個(gè)對象,各種系統(tǒng)級的服務(wù)都會(huì)注冊在ContextImpl的一個(gè)map容器中,這些服務(wù)都是單例。所以在這里,用到了單例和工廠方法模式。

public Object getSystemService(String name) {
    if (getBaseContext() == null) {
        throw new IllegalStateException("System services not available to Activities before onCreate()");
    }
    //........
    if (WINDOW_SERVICE.equals(name)) {
         return mWindowManager;
    } else if (SEARCH_SERVICE.equals(name)) {
        ensureSearchManager();
        return mSearchManager;
    }
    //.......
    return super.getSystemService(name);
}

抽象工廠模式

定義:為創(chuàng)建一組相關(guān)或者是相互依賴的對象提供一個(gè)接口,而不需要制定他們的具體類 。

放個(gè)簡單栗子:

public abstract class AbstractProductA{
    public abstract void method();
}
public abstract class AbstractProdectB{
    public abstract void method();
}

public class ConcreteProductA1 extends AbstractProductA{
    public void method(){
        System.out.println("具體產(chǎn)品A1的方法!");
    }
}
public class ConcreteProductA2 extends AbstractProductA{
    public void method(){
        System.out.println("具體產(chǎn)品A2的方法!");
    }
}
public class ConcreteProductB1 extends AbstractProductB{
    public void method(){
        System.out.println("具體產(chǎn)品B1的方法!");
    }
}
public class ConcreteProductB2 extends AbstractProductB{
    public void method(){
        System.out.println("具體產(chǎn)品B2的方法!");
    }
}

public abstract class AbstractFactory{
    public abstract AbstractProductA createProductA();

    public abstract AbstractProductB createProductB();
}

public  class ConcreteFactory1 extends AbstractFactory{
    public  AbstractProductA createProductA(){
        return new ConcreteProductA1();
    }

    public  AbstractProductB createProductB(){
        return new ConcreteProductB1();
    }
}

public  class ConcreteFactory2 extends AbstractFactory{
    public  AbstractProductA createProductA(){
        return new ConcreteProductA2();
    }

    public  AbstractProductB createProductB(){
        return new ConcreteProductB2();
    }
}

抽象工廠模式比工廠模式更加抽象。說實(shí)話,在實(shí)際開發(fā)當(dāng)中,工廠模式已經(jīng)可以解決大部分情況。

策略模式

定義:策略模式定義了一系列的算法,并將每一個(gè)算法封裝起來,而且使他們可以相互替換。策略模式讓算法獨(dú)立于使用它的客戶而獨(dú)立變化。

舉個(gè)例子:比如你現(xiàn)在又很多排序算法:冒泡、希爾、歸并、選擇等等。我們要根據(jù)實(shí)際情況來選擇使用哪種算法,有一種常見的方法是,通過if…else或者case…等條件判斷語句來選擇。但是這個(gè)類的維護(hù)成本會(huì)變高,維護(hù)時(shí)也容易發(fā)生錯(cuò)誤。這個(gè)時(shí)候就可以使用策略模式:我們可以定義一個(gè)算法抽象類AbstractAlgorithm,這個(gè)類定義一個(gè)抽象方法sort()。每個(gè)具體的排序算法去繼承AbstractAlgorithm類并重寫sort()實(shí)現(xiàn)排序。在需要使用排序的類Client類中,添加一個(gè)setAlgorithm(AbstractAlgorithm al);方法將算法注入Client,每次Client需要排序而是就調(diào)用al.sort()。

在Android中,我們平時(shí)在屬性動(dòng)畫中使用的時(shí)間插值器,插值器有著不同的策略:線性插值其、加速減速插值器、減速插值器、自定義插值器等。我們在客戶端中可以根據(jù)不同的需求注入不同的實(shí)現(xiàn)策略。

狀態(tài)模式

定義:當(dāng)一個(gè)對象的內(nèi)在狀態(tài)改變時(shí)允許改變其行為,這個(gè)對象看起來像是改變了其類。狀態(tài)模式把對象的行為包裝在不同的狀態(tài)對象里,每一個(gè)狀態(tài)對象都有一個(gè)共同的抽象狀態(tài)基類。狀態(tài)模式的一圖是讓一個(gè)對象在其內(nèi)部狀態(tài)改變的時(shí)候,其行為也隨之改變。
看例子:

public interface TvState{
    public void nextChannerl();
    public void prevChannerl();
    public void turnUp();
    public void turnDown();
}

//具體的狀態(tài):關(guān)機(jī)時(shí),對于操作不做具體響應(yīng)
public class PowerOffState implements TvState{
    public void nextChannel(){}
    public void prevChannel(){}
    public void turnUp(){}
    public void turnDown(){}

}

//開機(jī)時(shí),響應(yīng)具體的操作。
public class PowerOnState implements TvState{
    public void nextChannel(){
        System.out.println("下一頻道");
    }
    public void prevChannel(){
        System.out.println("上一頻道");
    }
    public void turnUp(){
        System.out.println("調(diào)高音量");
    }
    public void turnDown(){
        System.out.println("調(diào)低音量"); 
    }

}

public interface PowerController{
    public void powerOn();
    public void powerOff();
}

//相當(dāng)于一個(gè)電視遙控器。
public class TvController implements PowerController{
    TvState mTvState;
    public void setTvState(TvStete tvState){
        mTvState=tvState;
    }
    public void powerOn(){
        setTvState(new PowerOnState());
        System.out.println("開機(jī)啦");
    }
    public void powerOff(){
        setTvState(new PowerOffState());
        System.out.println("關(guān)機(jī)啦");
    }
    public void nextChannel(){
        mTvState.nextChannel();
    }
    public void prevChannel(){
        mTvState.prevChannel();
    }
    public void turnUp(){
        mTvState.turnUp();
    }
    public void turnDown(){
        mTvState.turnDown();
    }

}

//使用時(shí)
public class Client{
    public static void main(String[] args){
        TvController tvController=new TvController();
        tvController.powerOn();
        tvController.nextChannel();
        tvController.turnUp();

        tvController.powerOff();
        //調(diào)高音量,此時(shí)不會(huì)生效
        tvController.turnUp();
    }


}

可以想像到,如果不使用狀態(tài)模式,直接在客戶端使用if--else判斷當(dāng)前狀態(tài)的話,代碼會(huì)多么難以維護(hù)和混亂。我們把狀態(tài)封裝成了對象,在不同的具體狀態(tài)有著不同的實(shí)現(xiàn)。整個(gè)結(jié)構(gòu)就變得很清晰了。

在Android源碼中,WIFI管理模塊用到了狀態(tài)模式。當(dāng)WIFI開啟時(shí),自動(dòng)掃描周圍的接入點(diǎn),然后以列表的形式展示;當(dāng)wifi關(guān)閉時(shí)則清空。這里wifi管理模塊就是根據(jù)不同的狀態(tài)執(zhí)行不同的行為。

責(zé)任鏈模式

定義:使多個(gè)對象都有機(jī)會(huì)處理請求,從而避免請求的發(fā)送者和接受者直接的耦合關(guān)系,將這些對象連成一條鏈,并沿這條鏈傳遞該請求,直到有對象處理它為止。

Android源碼中的責(zé)任鏈模式:在Android處理點(diǎn)擊事件時(shí),父View先接收到點(diǎn)擊事件,如果父View不處理則交給子View,依次往下傳遞,直到有View 處理它便會(huì)停止傳遞。

解釋器模式

定義:給定一個(gè)語言,定義它的語法,并定義一個(gè)解釋器,這個(gè)解釋器用于解析語言。
這個(gè)實(shí)際開發(fā)中用得比較少。在Android中,我們經(jīng)常使用的AndroidManifest.xml文件里,<Activity>,<Service>等標(biāo)簽語句,就是一種語法,PackageManagerService就是解釋器,通過PackageManagerService解析這些標(biāo)簽,然后保存解析出來的信息。

命令模式

定義:將一個(gè)請求封裝成一個(gè)對象,從而讓用戶使用不同的請求把客戶端參數(shù)化,對請求排隊(duì)或者記錄請求日志,以及支持可撤銷的操作。

比如,當(dāng)我們點(diǎn)擊“關(guān)機(jī)”命令,系統(tǒng)會(huì)執(zhí)行一系列操作,比如暫停事件處理、保存系統(tǒng)配置、結(jié)束程序進(jìn)程、調(diào)用內(nèi)核命令關(guān)閉計(jì)算機(jī)等等,這些命令封裝從不同的對象,然后放入到隊(duì)列中一個(gè)個(gè)去執(zhí)行,還可以提供撤銷操作。

Android中的命令模式:在Android事件機(jī)制中,底層邏輯對事件的轉(zhuǎn)發(fā)處理。每次的按鍵事件會(huì)被封裝成NotifyKeyArgs對象。通過InputDispatcher封裝具體的事件操作。

觀察者模式

定義:定義對象間一種一對多的依賴關(guān)系,使得每當(dāng)一個(gè)對象改變狀態(tài),則所有依賴于它的對象都會(huì)得到通知并被更新。

觀察者模式中主要有以下角色:

  • Subject:抽象主題,也就是被觀察(Observable)的角色,抽象主題角色把所有觀察者對象的引用保存在一個(gè)集合中,每個(gè)主題可以有任意數(shù)量的觀察者,抽象主題提供一個(gè)接口,可以增加和刪除觀察者對象。
  • ConcreteSubject:具體主題,是抽象主題的具體實(shí)現(xiàn)。
  • Observer:抽象觀察者,該角色是觀察者的抽象類,它定義了一個(gè)更新接口,使得在得到主題的更改通知時(shí)更新自己。
  • ConcreteObserver:具體的觀察者,抽象觀察者的具體實(shí)現(xiàn)。

比如我們很熟悉的“訂閱--發(fā)布”系統(tǒng),就是觀察者模式的一個(gè)經(jīng)典應(yīng)用。有新消息發(fā)布時(shí),就會(huì)將消息發(fā)送給每個(gè)訂閱者。

Android中,ListView的Adapter中的notifyDataSetChanged(),這個(gè)函數(shù)通知ListView的每個(gè)Item,數(shù)據(jù)源發(fā)生了變化,請重繪。還有BroadcastReceiver廣播接收器,也是一種訂閱-發(fā)布的情況,也屬于觀察者模式。

備忘錄模式

定義:在不破壞封閉的前提下,捕獲一個(gè)對象的內(nèi)部狀態(tài),并在對象之外保存這個(gè)狀態(tài),這樣,以后就可將對象恢復(fù)到原先保存的狀態(tài)中。

在Android開發(fā)中,Activity里的onSaveInstanceState和onRestoreInstanceState我們都很熟悉,用于在異常情況中保存和恢復(fù)數(shù)據(jù)。這就是備忘錄模式啦。

迭代器模式

迭代器模式,又稱為(Cursor)模式。

定義:提供一種方法順序訪問一個(gè)容器對象中的各個(gè)元素,而不需要暴露該對象的內(nèi)部表示。

Java中的Iterator類就是迭代器模式。

在Android開發(fā)中,我們使用SQLiteDatabase或者ContentProvider的時(shí)候,使用query方法時(shí),通過返回的Cursor對象對數(shù)據(jù)進(jìn)行順序遍歷,這就是迭代器模式。

模板方法模式

定義:定義一個(gè)操作中的算法框架,而將一些步驟延遲到子類中,使得子類可以不改變一個(gè)算法的結(jié)構(gòu)即可重定義該算法的某些特定的步驟。

模板方法實(shí)際上是封裝了一個(gè)固定流程,就像是一套執(zhí)行模板一樣,這些都在父類中定義好,而子類可以有不同的具體實(shí)現(xiàn)。

在Android開發(fā)中,我們在使用Activity時(shí),用的就是系統(tǒng)給我們提供的模板,onCreate、onStart、onResume......我們只需要在這些方法里去實(shí)現(xiàn)我們的邏輯,就可以很輕松的完成一個(gè)activity了。

訪問者模式

定義:封裝一些作用于某種數(shù)據(jù)結(jié)構(gòu)中各元素的操作,它可以在不改變這個(gè)數(shù)據(jù)結(jié)構(gòu)的前提下定義作用于這些元素的新的操作。

Android中運(yùn)用訪問者模式,其實(shí)主要是在編譯期注解中,編譯期注解核心原理依賴APT(Annotation Processing Tools),著名的開源庫比如ButterKnife、Dagger、Retrofit都是基于APT。

中介者模式

定義:中介者模式包裝了一系列對象相互作用的方式,使得這些對象不必相互明顯調(diào)用,從而使他們可以輕松耦合。當(dāng)某些對象之間的作用發(fā)生改變時(shí),不會(huì)立即影響其他的一些對象之間的作用保證這些作用可以彼此獨(dú)立的變化,中介者模式將多對多的相互作用轉(zhuǎn)為一對多的相互作用。

Android中的Binder機(jī)制就是一種中介者模式。我們在開發(fā)多進(jìn)程應(yīng)用的時(shí)候,通過Binder這個(gè)媒介,實(shí)現(xiàn)IPC通信。在Android Framework層中也是如此,系統(tǒng)啟動(dòng)時(shí),各種系統(tǒng)服務(wù)會(huì)向ServiceManager提交注冊,即ServiceManager持有各種系統(tǒng)服務(wù)的引用 ,當(dāng)我們需要獲取系統(tǒng)的Service時(shí),比如ActivityManager、WindowManager等(它們都是Binder),首先是向ServiceManager查詢指定標(biāo)示符對應(yīng)的Binder,再由ServiceManager返回Binder的引用。并且客戶端和服務(wù)端之間的通信是通過Binder驅(qū)動(dòng)來實(shí)現(xiàn),這里的ServiceManager和Binder驅(qū)動(dòng)就是中介者。

代理模式

定義:為其他類提供一種代理以控制這個(gè)對象的訪問。

使用場景:當(dāng)無法或者不想直接訪問某個(gè)對象或訪問某個(gè)對象存在困難時(shí)可以通過一個(gè)代理對象來間接訪問,為了保證客戶端使用的透明性,委托對象與代理對象需要實(shí)現(xiàn)相同的接口。

代理模式在Android中,我們在使用AIDL進(jìn)行跨進(jìn)稱通信時(shí),操作的對象其實(shí)是遠(yuǎn)程對象的代理,AIDL生成一個(gè)代理類,幫我們完成把參數(shù)寫入到Parcelable對象等操作。

組合模式

定義:將對象組成成樹形結(jié)構(gòu),以表示“部分-整體”的層次結(jié)構(gòu),使得用戶對單個(gè)對象和組合對象的使用具有一致性。

在Android中View的結(jié)構(gòu)是樹形結(jié)構(gòu),每個(gè)ViewGroup包含一系列的View,而ViewGroup本身又是View。這是Android中非常典型的組合模式。

適配器模式

定義:把一個(gè)類的接口變換成客戶端所期待的另一個(gè)接口,從而使原本因接口不匹配而無法在一起工作的兩個(gè)類能夠在一起工作。

在Android開發(fā)當(dāng)中,我們在使用ListView或者RecyclerView的時(shí)候,我們知道數(shù)據(jù)源和ListView是沒有關(guān)系的,我們通過給ListView設(shè)置適配器,適配器中提供了getView方法把數(shù)據(jù)源轉(zhuǎn)化為ListView需要的對象,View。然后完成工作。這就是適配器模式。

裝飾模式

定義:動(dòng)態(tài)的給一個(gè)對象添加額外的智者,就增加功能來說,裝飾模式比子類繼承的方式更靈活。

裝飾模式是以對客戶端透明的方式拓展對象的功能,是繼承關(guān)系的一個(gè)替代方案,而代理模式則是給一個(gè)對象提供一個(gè)代理對象,并使用代理對象來控制對原有對象的引用。裝飾模式為所裝飾的對象增強(qiáng)功能,代理模式對代理的對象施加控制,不進(jìn)行增強(qiáng)。

Android中,ContextWrapper是Context的裝飾類。

享元模式

定義:使用享元對象有效地支持大量的細(xì)粒度對象。

享元模式主要是為了重用對象,在系統(tǒng)中存在大量相似對象時(shí),可以使用享元模式。比如Java中的常量池,線程池等。

在Android中,每次我們獲取Message時(shí)調(diào)用Message.obtain()其實(shí)就是從消息池中取出可重復(fù)使用的消息,避免產(chǎn)生大量的Message對象。

外觀模式

定義:要求一個(gè)子系統(tǒng)的外部與其內(nèi)部的通信必須通過一個(gè)統(tǒng)一的對象進(jìn)行。

Android內(nèi)部有很多復(fù)雜的功能比如startActivty、sendBroadcast、bindService等等,這些功能內(nèi)部的實(shí)現(xiàn)非常復(fù)雜,如果你看了源碼你就能感受得到,但是使用者無需關(guān)心它內(nèi)部實(shí)現(xiàn)了什么,只需要使用這些統(tǒng)一的高層接口就可以了。

橋接模式

定義:將抽象部分與實(shí)現(xiàn)部分分離,使他們獨(dú)立地進(jìn)行變化。

在Android中,View的視圖層級與執(zhí)行真正的硬件繪制相關(guān)類之間的關(guān)系可以看作是一種橋接模式。對于一個(gè)View來說,它有兩個(gè)維度的變化,一個(gè)是它的描述比如Button、TextView等等他們是View的描述維度上的變化,另一個(gè)維度就是將View真正繪制到屏幕上,這跟Display、HardwareLayer和Canvas有關(guān)。這兩個(gè)維度可以看成是橋接模式的應(yīng)用。

總結(jié)

講道理,看到那么多的設(shè)計(jì)模式我懵比了很久。在開發(fā)過程中,我們要注意運(yùn)用設(shè)計(jì)模式,寫出更加好的軟件。當(dāng)然,絕對要記住,拒絕過度設(shè)計(jì),不要為了設(shè)計(jì)而設(shè)計(jì)。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容