Android面試基礎題總結二

weixin_34402408發表於2017-07-21

Android效能優化(高階)

  1. 簡述Android的系統架構?

    • android的系統架構從下往上分為Linux核心層,執行庫,應用程式框架層和應用程式層。
  2. 如何對Android應用進行效能分析;

    • 使用ddms工具中的traceview,heap,allocation tracker工具。traceview是Android平臺特有的資料採集和分析工具,可以用來分析耗時操作等。heap檢視工具可以幫助我們檢查程式碼中是否存在有造成記憶體洩漏的地方,allocation tracker工具是記憶體分配跟蹤工具。
  3. 什麼情況下會導致記憶體洩露;

    • Android的虛擬機器是基於暫存器的Dalvik,它的最大堆記憶體是16M,部分機器是24M,因此能利用的記憶體空間是有限的,一旦超出就會造成OutOfMemory異常。
    • 記憶體洩漏的幾點原因:1)資源釋放問題,程式程式碼的問題,長期保持某些資源,如context,cursor,io流的引用,資源得不到釋放就造成記憶體洩漏。2)物件記憶體過大問題,儲存了多個耗用記憶體過大的物件(如bitmap,xml檔案),造成記憶體超出限制。3)static關鍵字的使用,static在Java中,當用來修飾成員變數的時候,那麼該變數就屬於該類,而不是該類的例項,因此用static修飾的變數,生命週期很長。針對static的解決方案:儘量避免static成員變數引用資源耗費過多的例項,比如context,context儘量使用ApplicationContext,因為Application的context的生命週期比較長,引用他不會出現記憶體洩漏的問題。4)執行緒導致記憶體洩漏,執行緒的生命週期不可控。
  4. OOM是什麼?應如何避免?

    • 記憶體溢位,要避免OOM異常需要先知道是什麼原因導致的異常,

    • 圖片過大導致OOM,在Android中用bitmap很容易導致記憶體溢位,比如報如下錯誤:
      Java.lang.OutOfMemoryError : bitmap size exceeds VM budget。

      • 解決方法:

          //1)等比例縮小圖片
          options.inSampleSize = 2;
          //Options 只儲存圖片尺寸大小,不儲存圖片到記憶體
          BitmapFactory.Options opts = new BitmapFactory.Options();
          opts.inSampleSize = 2;
          Bitmap bmp = null;
          bmp = BitmapFactory.decodeResource(getResources(),
          mImageIds[position],opts);
          //回收
          bmp.recycle();
        
          //2)對圖片採用弱引用,及時的進行recycle()操作。
          SoftReference<Bitmap> bitmap = new SoftReference<Bitmap>(pBitmap);
              if(bitmap != null){
                  if(bitmap.get() != null && !bitmap.get().isRecycled()){
                      bitmap.get().recycle();
                      bitmap = null;
              }
          }
           3)使用圖片載入框架處理圖片。
        
    • 介面切換的時候導致OOM,一般情況下,開發中都會禁止橫屏,一旦橫豎屏切換的多了,activity的生命週期就會重新銷燬然後建立。切換的次數多了,就會導致OOM。這種問題沒有固定的解決方案,可以從一下幾方面著手分析,

      • 1)看頁面佈局中有沒有大的圖片,如背景圖之類的,去除xml檔案中相關設定,改在程式碼中設定(放在onCreate()方法中)

          Drawable drawable = getResources().getDrawable(R.drawable.id);
          ImageView imageView = new ImageView(this);
          imageView.setBackgroundDrawable(drawable);
        
          //在activity  destory的時候注意,要drawable.setCallback(null),防止得不到及時的釋放。
        
    • 查新資料庫時沒有關閉遊標。

    • 構造adapter時,沒有使用快取convertView,使用convertView的好處:
      當convertView 為空時,用setTag()方法為每個View 繫結一個存放控制元件的ViewHolder 物件。當convertView 不為空,重複利用已經建立的view 的時候,使用getTag()方法獲取繫結的ViewHolder 物件,這樣就避免了findViewById 對控制元件的層層查詢,而是快速定位到控制元件。

    • bitmap物件不再使用的時候呼叫recycle()方法釋放記憶體。

    • 使用廣播沒有登出的時候也會產生OOM。

  5. ANR是什麼? 應如何避免和解決?

    • application not responding 程式無響應。ANR一般有三種型別: activity 5秒,broadcastReceiver10秒,services20秒。超時的原因一般有兩種:1)當前的事件沒有機會得到處理(UI執行緒正在處理前一個事件沒有及時完成或者looper被某種原因阻塞住)2)當前的事件正在處理,但沒有及時完成,UI執行緒儘量只做UI相關的工作,耗時操作(資料庫操作,io流,連線網路或者其他可能阻礙UI執行緒的操作)放入單獨的執行緒處理,儘量用handler來處理UI thread和thread之間的互動。
  6. Android中執行緒間通訊有那幾種方式?

    • 共享記憶體(變數),檔案,資料庫,handler,Java中wait(),notify(),notifyAll()。
  7. 執行緒和程式之間的區別?

    • 一個應用程式至少有一個程式,一個程式至少有一條執行緒,一個執行緒可以建立和撤銷另一個執行緒,同一個程式中的多個執行緒可以併發執行。從邏輯角度講,多執行緒的意義在於一個應用程式中,有多個執行部分可以同時執行,但作業系統並沒有將多個執行緒看成多個獨立的應用,來實現程式的排程,管理和資源分配。

android的螢幕適配 :

  1. 螢幕適配的方式有哪些?

    • 適配方式有:權重weight適配,layout適配,程式碼使配,dp適配(layout中定義佈局設定的引數使用dp),dimens適配。
    • 在values-1280x720目錄中的dimens。xml檔案中定義同樣的尺寸名稱,但是使用不同的尺寸,當在佈局檔案中使用長或寬單位時,用@dimens/width來定義。如果在values-1280x720中放置了dimens常量,一定要記得將該常量的對應值在values目錄中的dimens.xml中也放一份,因為該檔案是預設配置,當使用者的手機不是1280*720的時候,系統應用用的是預設values目錄中的dimens.xml。
  2. 螢幕適配的處理技巧?

    • 在解析度大小不同的問題上,推薦使用權重weight適配,一般應用於線性佈局中。
    • 儘量使用線性佈局,相對佈局,如果螢幕放不下資料,可以使用ScrollView來拖動。
    • 儘量使用9-patch圖片,可以自動的根據圖片上面顯示的內容被拉伸和收縮。

AIDL

  1. 什麼是ALDI?應如何使用?

    • AIDL是android interface definition language 意思是Android介面定義語言。使用aidl可以幫助我們釋出以及呼叫遠端服務,實現跨程式通訊。
  2. AIDL如何工作,能處理哪些型別資料?

    • 編譯器可以通過aidl檔案生成一段程式碼,通過預先定義的介面達到兩個程式內部通訊程式跨程式物件訪問的目的,需要完成兩件事:一是引入aidl的相關類;二是呼叫aidl產生的class檔案,理論上,引數可以傳遞基本資料型別和String,還有就是Bundle的派生類。

android 的事件處理 :

handler訊息機制:

  1. Android中主執行緒主要是用來建立,更新UI的,而耗時操作,網路請求等則需要在子執行緒中操作。而handler主要接受子執行緒傳送的資料,並用該資料來配合主執行緒更新UI,handler執行在主執行緒中,他和子執行緒通過message物件來傳遞資料(子執行緒通過sendMessage()方法來傳送訊息,資料),將子執行緒傳送來的這些訊息放入到主執行緒中,配合主執行緒來更新UI。

  2. handleThread,Looper,MessageQueue和Message的關係:handlerThread負責將需要傳遞的資訊封裝成Message物件,通過handler物件的sendMesage()方法將訊息傳遞給looper,在有looper將message放入messageQueue訊息佇列中,當looper物件看見MessageQueue中含有Message時,就將其廣播出去,該handler物件手到該訊息之後,呼叫相應的handler物件的handlerMessage()方法對其進行處理。

  3. handler訊息機制的底層簡單分析:

    • 首先是messageQueue和Looper的建立:當系統啟動的時候,先載入activityThread這個類,在這個類中的main方法會呼叫Looper.prepareMainLooper()這個方法,來建立一個Looper物件,Looper物件就會通過ThreadLocal把他和當前執行緒繫結在一起,建立Looper的時候就建立了一個MessageQueue,MessageQueue是個final型別的成員變數。這樣就保證了一個Looper對應一個MessageQueue,所有的MessageQueue建立好了之後,就會一個執行緒對應唯一的messageQueue。然後MessageQueue在建立的時候通過JNI建立了一個NativeMessageQueue,他又建立了一個c++Looper,所以說Handler的底層是通過C++來實現的。MessageQueue中儲存了一個int型別的成員變數mptr,他儲存了NativeMessageQueue的指標,這樣就是了MessageQueue和NativeMessageQueue的對應。
    • 接下來是從訊息佇列中取訊息:之後就會呼叫Looper.loop()來取訊息,這裡面有一個死迴圈,在這個死迴圈裡存在著queue.next();的方法他是阻塞主執行緒的,它實際上就是呼叫了NativeMessageQueue去C++層取訊息,如果取出來這個loop就去執行,沒取出來就會阻塞在這裡不去執行,這樣就能是介面能夠停留而不至於程式碼執行完介面就跳出;取出訊息後呼叫handler.dispatchMessage()來分發訊息,message這裡面有一個回撥,handler在建立的時候有一個回撥,如果兩個回撥都為空的那麼直接呼叫handleMessage()來處理訊息,這就是取訊息。
    • 最後就是存訊息:也就是向訊息佇列中傳送訊息,不管是sendMessage還是sendMessageDelaty等他們呼叫都是sendMessageAtTime(),在這個方法裡面他實際呼叫的是messqueue.enqueuemessage()這裡面實際上就是拿著當前訊息要執行的時間進行排序,然後就會通過訊息佇列儲存起來,這裡面有一個message.next()他們都可以通過這個方法一條指向下一條,這樣一條一條連起來,當有訊息需要馬上執行就會呼叫nativewake(),這個方法就會把Looper.looper()的queue.next()喚醒就能取出訊息,他就可以開始工作.

事件分發機制

  1. OnTouchEvent的事件傳遞機制:

    • 當手指觸控到螢幕時,系統會呼叫相應的view的onTouchEvent,傳入一系列的action,那麼首先觸發的是activity的dispatchTouchEvent,然後觸發activity的onUserInteraction,在觸Layout的dispatchTouchEvent,然後觸發Layout的onInterceptTouchEvent.

    如果dispatchTouchEvent:
    事件由此分發,通常會呼叫super. DispatchTouchEvent.
    如果onInterceptTouchEvent(攔截事件):
    返回true:表示事件被攔截會傳遞給自己的onTouchEvent處理,
    返回false:不進行攔截,會將事件傳遞給下一個view的dispatchTouchEvent()進行判斷.
    如果onTouchEvent:
    返回結果為true:表示事件由自己處理,消費.
    返回結果為false:表示當前事件自己不做處理,交給父view的onTouchEvent處理.

view的繪製流程:

參考博文:http://www.jianshu.com/p/5a71014e7b1b
  1. 子執行緒發訊息到主執行緒更新UI,處理handler,asyncTask還有什麼;

    • 用activity物件的runOnUiThread()線上程中更新UI。

        new Thread() {
        @Override
        public void run() {
        super.run();
        //這兒是耗時操作,完成之後更新ui.
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                //更新ui
                ImageView.setImageBitmap(bitmap);
            }
        });
        }
        }.start();
      
            //如果是非上下文類中(activity),可以通過傳遞上下文實現呼叫;
            //Activity activity = (Activity) imageView.getContext() ;
        
         activity.runOnUiThread(new Runable() {
          @Override
          public void run() {
            imageView.setImageBitmap(bitmap);
            }
         });   
      
  2. 子執行緒中能不能new handler,為什麼?

    • 不能,如果在子執行緒中直接new Handler() 會拋異常。

Android 中的動畫 :

  1. 動畫型別有幾種,特點和區別是什麼?

    • 屬性動畫,補間動畫;補間動畫只是顯示的位置變動,view的實際位置未改變,表現為view移動到其他地方,點選事件仍在原處才能相應,而屬性動畫在控制元件移動後時間響應就在控制元件移動後本身進行處理。
  2. 如何修改Activity進入和退出的動畫;

    • 通過兩種方式:1)通過定義activity的主題,2)通過複寫activity的overridePendingTransition(R.anim.fade,R.anim.hold)方法。

LRUCache的底層原理:

  1. 通過獲取記憶體的最大可用值,lrucache通過建構函式傳入快取值,它是kb為單位,在不超出可使用記憶體的最大值的情況下,超出就會OOM,通過使用最大快取值的1/8作為快取的大小,重寫sizeOf()方法來返回每一張圖片的大小,這就是lurcache的是使用方法,那麼lruchche為何這樣強大,原因是它的主要演算法原理是將最近最少使用的物件用強引用儲存在LinkedHashMap中,並且將最近最少使用的物件在快取值達到預設值之前從記憶體中移除,在過去經常使用一種非常流行的快取技術實現,就是軟引用和弱引用,但現在不再使用了,因為在Android2.3之後。垃圾回收機制更容易傾向於回收持有軟引用和弱引用的物件,這就讓軟引用和弱引用顯得不可靠,另外在Android3,0之後,圖片的資料會儲存在本地記憶體中,因而無法用一種可預見的方式將其釋放,這就會潛在的造成應用程式記憶體溢位或者崩潰,而再有了lruCache這個功能之後,解決這些問題就不在難了。

JNI的呼叫過程:

  1. 安裝和下載cygwin,下載Android NDK.
  2. ndk專案中JNI介面的設計,
  3. 使用C/C++實現本地方法
  4. JNI生成動態連結庫.so檔案
  5. 將動態連結庫複製到Java工程,在Java工程中呼叫,執行Java工程即可。

圖片載入框架picasso,glide,imageLoader,Fresco之間的區別:

  1. 共同的優點:

    • 使用簡單--都可以通過一句程式碼實現圖片的獲取和顯示。
    • 可配置度高,自適應行性高--可根據系統效能初始化快取配置,給句cpu核數確定最大併發數,根據網路狀態變化來調整最大併發數,根據可用記憶體確定最大快取大小,
    • 多級快取--每種框架至少有兩級快取,可以提高圖片的載入速度。
    • 支援多種資料來源--網路,本地,資原始檔。
    • 支援多種displayer--不僅支援imageView,同時支援多種view以及一些虛擬的imageview。
    • 支援動畫。

imageLoader的設計模式:

* 一個強大的圖片載入框架,很好的處理了圖片載入的多執行緒,快取,記憶體溢位等問題。多執行緒非同步載入和顯示圖片(圖片來源於網路,sd卡,assets資料夾,drawable資料夾,不能載入9patch圖片,可以載入視訊縮圖)
* ImageLoader 收到載入及顯示圖片的任務,並將它交給 ImageLoaderEngine,ImageLoaderEngine 分發任務到具體執行緒池去執行,任務通過 Cache 及 ImageDownloader 獲取圖片,中間可能經過 BitmapProcessor 和 ImageDecoder 處理,最終轉換為Bitmap 交給 BitmapDisplayer 在 ImageAware 中顯示。
* imageloader的優點:
* 
    * 支援下載進度條監聽,支援在view的滾動中暫停圖片的載入,實現了多種記憶體快取演算法,支援本地快取檔名規則定義。
    * 支援監視載入的過程,可以暫停載入圖片,在經常使用的listview,GridView,可以設定滑動時暫停載入,停止滑動的時候載入圖片。
    * 高度可定製化,可以根據自己的需求進行各種配置,(執行緒池,圖片下載器,記憶體快取策略等)
    * 支援圖片記憶體快取,檔案快取
    * 在網路速度較慢的時候,還可以對圖片進行載入並設定下載監聽。
    * 避免同一個uri載入過程中重複開啟任務載入
    * 減少載入大圖片出現oom的情況。
    * 不足:
    * 
        * 不支援載入GIF圖片。

Picasso的設計模式:

* Picasso 收到載入及顯示圖片的任務,建立 Request 並將它交給 Dispatcher,Dispatcher 分發任務到具體 RequestHandler,任務通過 MemoryCache 及 Handler(資料獲取介面) 獲取圖片,圖片獲取成功後通過 PicassoDrawable 顯示到 Target 中。
* Picasso的優點:
* 
    * 自帶統計監控功能--支援圖片快取使用的監控,包括已使用記憶體大小,節省的流量。
    * 支援優先順序處理。
    * 支援延遲到圖片尺寸計算完成載入,
    * 支援飛航模式,併發執行緒數根據網路型別而變。
    * 無本地快取--不是說沒有本地快取,而是Picasso自身沒有定義本地快取的介面,預設使用http的本地快取。

* 不足:
* 
    * 不支援載入GIF圖片,快取之後的圖片沒有進行縮放

glide的設計模式:

* Glide 收到載入及顯示資源的任務,建立 Request 並將它交給RequestManager,Request 啟動 Engine 去資料來源獲取資源(通過 Fetcher ),獲取到後 Transformation 處理後交給 Target。Glide 依賴於 DiskLRUCache、GifDecoder 等開源庫去完成本地快取和 Gif 圖片解碼工作。
* glide的優點:
    * 支援多種圖片快取,GIF,webP,縮圖,甚至是video。
    * 支援優先順序處理
    * 支援velloy,okHttp.實際上imageloader。Picasso也支援velloy,OKHttp。
    * 記憶體快取的是處理之後的圖片,而不是原始圖片,節省記憶體大小。

fresco的優點:

* 支援流式,支援類似於網頁上的從模糊到清晰載入圖片,漸進式載入JPEG圖片。
* 圖片可以從任意的中心點顯示在imageView,而不僅僅是圖片的中心。
* 支援多幀動畫,GIF,webP.
* 缺點: 框架較大,影響apk的體積,使用較繁瑣。

網路請求框架Volley 和Ok-http,android-async-http,retrofit的區別:

  1. 參考博文:http://www.cnblogs.com/changyaohua/p/4992987.html

volley框架:

* google推出的非同步網路請求框架和圖片載入框架,適合資料量小,通訊頻繁的網路操作。
* 能夠使網路通訊更快,更簡單,擴充性更好一點,
* get,post網路請求以及網路影象的高效率非同步處理請求。
* 可以對網路請求進行排序優先順序管理。
* 支援網路請求的快取
* 多級別取消請求
* 使用volley可以簡化一些網路通訊的開發,不適合大資料和流媒體的網路請求,例如上百兆檔案,視訊上傳。
* volley在Android2.2以下使用httpClient,2.2以上使用的是httpUriConnection.
* Volley的使用:http://blog.csdn.net/sinyu890807/article/details/17482095

基本的使用方法: http://www.kwstu.com/ArticleView/kwstu_20144118313429
直接返回Object的話,用Gson/FastJson與Volley的結合:http://www.cnblogs.com/freexiaoyu/p/3955137.html

* Volley問題收錄:Volley的request預設回撥到主執行緒中,如果有需求是要載入到sqlite等等仍需要在子執行緒中進行的操作 解決方案 :https://www.zhihu.com/question/36672622/answer/76003423   

async-Http框架:

* 清晰地網路請求回撥
* 網路請求使用執行緒池ThreadPool,限制併發資源使用情況
* get/post基於引數構建使用(RequestParams)
* 支援Multipart檔案上傳,大資料上傳下載。
* 內建響應解析成json.
* 持久化cookie儲存,儲存cookie到應用程式的sharedPreferences.
* 支援二進位制檔案,圖片的下載
* 使用的是httpClient

okhttp框架:

* OKhttp和retrofit都出自於Square公司,是高效能的http庫。
* OKhttp使用okio進行資料傳輸,  包含一般的get,post請求;基於http的檔案,圖片上傳,載入;支援請求回撥,直接返回物件,物件集合;支援session的保持。
* 支援spdy,http2.0,websocket,支援同步,非同步,
* 封裝了執行緒池,資料轉換,引數使用,錯誤處理等;
* OKhttp使用教程:http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0106/2275.html

retrofit框架:

* 出自於Square公司,是對OKhttp做了一層封裝。
* 支援Gson解析,retrofit已經在內部封裝了json解析

非同步載入框架handler,asyncTask,RXJava :

  1. 非同步載入框架之asyncTask:

    1. 需要重寫的四個方法:doInBackground(Params params)執行在後臺執行緒中;onPreExecute(),onProgressUpdate(progress),onPostExecute(result)這三個方法是執行在UI執行緒中。
    2. 使用aysncTack需要遵守的原則:task例項必須在UI執行緒中建立;execute方法必須在UI執行緒中呼叫;不要手動的呼叫那四個方法。
    3. asyncTask內部也是handler機制完成的,只不過Android提供了執行框架來提供執行緒池來執相應的任務,因為執行緒池的大小的問題,所以asyncTask值應該用來執行耗時較短的任務,比如HTTP請求,大規模的下載和資料庫的更改不適用於asyncTask,因為會導致執行緒池堵塞,沒有執行緒來執行其他任務,導致asyncTask根本執行不了。
  2. rxjava框架:

    1. rxjava是一個非同步操作庫,在JavaVM上使用可觀測的序列來組成非同步的,基於事件的程式的庫,rxjava的優勢在於簡潔,隨著程式邏輯變得越來越複雜,rxJava確一直簡潔,能夠很大程度的提升程式碼的閱讀性。他通過擴充的觀察者模式來實現的。rxjava有四個基本的概念:被觀察者Observable,觀察者Observer,訂閱事件subscribe,Observable和observer通過subscribe()來實現訂閱關係,從而Observable可以在需要的時候發出事件來通知Observer。

MVC和MVP的區別;

  1. MVC是model (模型) view (檢視) controller(控制器),view強依賴於model是MVC的主要問題,使用MVC,將業務邏輯抽離到controller中,讓view層專注於UI.
  2. MVC指的是model view controller,model著的是資料層,主要負責相關的業務邏輯,包括資料庫,網路本地快取等,view是指介面,主要負責UI相關的業務邏輯,包括佈局介面,相關控制元件的顯示,controller是控制層,主要負責處理在物件狀態下呼叫model和view的方法實現資料和UI展示的相關邏輯.以MVC的設計模式的開發流程在一定程度上提高了程式碼的可維護性,比如要修改UI介面的相關資料,就可以找到對應的處理層來處理程式碼,但由於model和view的相關邏輯都寫在avtivity控制層了,這樣後期維護起來比較麻煩,因此就產生了一種新的設計模式,MVP,MVP指的是model view presenter,是在MVC的基礎上,將controller層該為了presenter層,它成為了model和view層之間互動的橋樑,他本身不具有任何的邏輯程式碼,只是在對應的狀態下呼叫model和view層的方法來實現資料的相關邏輯和UI展示.
  3. 兩者的區別在於MVP中view不能直接的使用model層,它們之間的通訊是通過Presenter(MVC中的Controller)來進行的,所有的互動都發生在Presenter內部,而在MVC中View會直接從Model中讀取資料而不是通過 Controller。

網路請求get和post的區別;

  1. get是從伺服器上獲取資料,post是向伺服器上傳輸資料。
  2. get是把引數資料佇列加到提交表單的ACTION屬性所指的URL中,值和表單內各個欄位一一對應,在URL中可以看到。post是通過HTTP post機制,將表單內各個欄位與其內容放置在HTML HEADER內一起傳送到ACTION屬性所指的URL地址。使用者看不到這個過程。
  3. 對於get方式,伺服器端用Request.QueryString獲取變數的值,對於post方式,伺服器端用Request.Form獲取提交的資料。
  4. get傳送的資料量較小,不能大於2KB。post傳送的資料量較大,一般被預設為不受限制。但理論上,IIS4中最大量為80KB,IIS5中為100KB。
  5. get安全性非常低,post安全性較高。但是執行效率卻比Post方法好。
  6. get可以被瀏覽器快取,post不可以。
  7. get請求是安全的,post不安全。

Android中常見的解決衝突的方案:

  1. 多個滑動必然會產生衝突,比如最常見的scrollView中巢狀listview,一般做法是計算出listview的總高度,這樣就不用去滑動listview了。再比如viewpager巢狀fragment,fragment中又有listview,這原本是由滑動衝突的,但是viewpager內部已經幫我們解決了這種衝突,如果需要自己解決的話,可以通過下面兩種方式解決:一是外部攔截法,外部攔截法是指在有點選事件時都要經過父容器,那麼在父容器時如果需要攔截就攔截自己處理,不需要則傳遞給下一層進行處理,主要的攔截是需要重寫onInterceptTouchEvent()方法。二是內部攔截法,是指父容器不攔截任何事件,所有事件都傳遞給子view,如果需要就直接消費掉,不需要在傳給父容器處理。需要重寫dispatchTouchEvent()方法。
  2. 參考博文:http://blog.csdn.net/lylodyf/article/details/52438997

簡述對Binder機制的理解。

  1. binder機制是用來實現不同程式之間的通訊的。binder屬於一個驅動,工作在linux層,執行在核心態,它的操作完成是基於一段記憶體,因此我們開發的程式中對binder的呼叫都是通過系統的呼叫來完成的,binder的架構由服務端,binder驅動,客戶端三部分組成。處於對程式的安全性,可靠性,傳輸效能的考慮,Android選用binder來實現不同程式之間的通訊。

談談對context的理解。

  1. 從字面意思理解是“上下文"的意思,從類的繼承關係來看,context是一個抽象的基類,它的實現子類有三種:application,activity和service。我們通過它來訪問當前包的資源(getResources,getAssets),啟動其他元件(activity,service,broadCastReceiver)以及得到各種服務(getSystemService)。換句話說,context提供了一個應用執行的環境,在context的大環境中,應用才可以訪問資源,才能完成和其他元件,服務互動。

如何縮減apk的大小,apk的打包;

  1. Android打包本身會對png圖片進行無失真壓縮,但是純粹的進行無失真壓縮並不會對apk的減小有任何的效果,因此可以可以通過tinypng進行有失真壓縮。
  2. png換成jpg,如果圖片還大,在不降低畫質的情況下,可以在將jpg換成webp.
  3. 大圖縮小
  4. 覆蓋arr中一些預設的大圖,典型的是support-v4包中包含的一些可能用到的圖片,在實際中app是用不到的。並不是吧所有用不到的圖片替換掉,而是把幾張較大的圖片用1x1的圖片替換。
  5. 刪除armable-v7包中的so檔案, armable-v7和armable資料夾可以只保留armable。
  6. 微信資源壓縮打包。採用微信壓縮方案。
  7. proground深度混淆程式碼
  8. 深度清理程式碼和資源,引入的無用圖片,相同的圖片,圖片可用著色方案替換,用shape替換等。
  9. 去除重複庫
  10. 表情包線上化

談談對Android NDK的理解。

  1. Android NDK是一系列工具的集合,可以快速的幫助開發者開發C/C++的動態庫,並能自動將so檔案和Java應用一起打包成apk。
  2. ndk 提供了一份穩定的,功能有限的API標頭檔案宣告;
  3. NDK是Android平臺支援C開發的開端。

Android中程式間通訊的實現方式。

  1. Bundle/Intent傳遞資料:可傳遞基本型別,String,實現了Serializable或Parcellable介面的資料結構。Serializable是Java的序列化方法,Parcellable是Android的序列化方法,前者程式碼量少(僅一句),但I/O開銷較大,一般用於輸出到磁碟或網路卡;後者實現程式碼多,效率高,一般使用者記憶體間序列化和反序列化傳輸。

  2. 檔案共享:對同一個檔案先後寫讀,從而實現傳輸,Linux機制下,可以對檔案併發寫,所以要注意同步。順便一提,Windows下不支援併發讀或寫。

  3. Messenger:Messenger是基於AIDL實現的,服務端(被動方)提供一個Service來處理客戶端(主動方)連線,維護一個Handler來建立Messenger,在onBind時返回Messenger的binder。
    雙方用Messenger來傳送資料,用Handler來處理資料。Messenger處理資料依靠Handler,所以是序列的,也就是說,Handler接到多個message時,就要排隊依次處理。

  4. AIDL:AIDL通過定義服務端暴露的介面,以提供給客戶端來呼叫,AIDL使伺服器可以並行處理,而Messenger封裝了AIDL之後只能序列執行,所以Messenger一般用作訊息傳遞。
    通過編寫aidl檔案來設計想要暴露的介面,編譯後會自動生成響應的java檔案,伺服器將介面的具體實現寫在Stub中,用iBinder物件傳遞給客戶端,客戶端bindService的時候,用asInterface的形式將iBinder還原成介面,再呼叫其中的方法。

  5. ContentProvider:系統四大元件之一,底層也是Binder實現,主要用來為其他APP提供資料,可以說天生就是為程式通訊而生的。自己實現一個ContentProvider需要實現6個方法,其中onCreate是主執行緒中回撥的,其他方法是執行在Binder之中的。自定義的ContentProvider註冊時要提供authorities屬性,應用需要訪問的時候將屬性包裝成Uri.parse("content://authorities")。還可以設定permission,readPermission,writePermission來設定許可權。 ContentProvider有query,delete,insert等方法,看起來貌似是一個資料庫管理類,但其實可以用檔案,記憶體資料等等一切來充當資料來源,query返回的是一個Cursor,可以自定義繼承AbstractCursor的類來實現。

  6. Socket:學過計算機網路的對Socket不陌生,所以不需要詳細講述。只需要注意,Android不允許在主執行緒中請求網路,而且請求網路必須要注意宣告相應的permission。然後,在伺服器中定義ServerSocket來監聽埠,客戶端使用Socket來請求埠,連通後就可以進行通訊。

實現一個自定義view的基本流程;

  1. 自定義view的屬性:在res/values/下建立一個attrs.xml檔案,在裡面定義我們的屬性和宣告我們的整個樣式。在xml檔案中一定要引入名稱空間。
  2. 在view的構造方法中獲取到我們的自定義屬性
  3. 重寫onMersure()方法
  4. 重寫onDraw()方法
  5. 參考博文:http://blog.csdn.net/lmj623565791/article/details/24252901/

幾種常見的設計模式;

單例模式:

  1. 單例模式是確保某個類只有一個例項,有懶漢式和餓漢式,

     * 懶漢式,首先得私有化建構函式,防止類在外部被例項化,接下來就是書寫Singleton型別的getInstance()靜態的方法,避免執行緒不安全可以再靜態方法上加鎖synchronized.以下是執行緒安全的懶漢式的設計模式.
     
         public class Singleton { 
            private static Singleton instance; 
            private Singleton (){} 
            public static synchronized Singleton getInstance() { 
                 if (instance == null) { 
                           instance = new Singleton(); 
                      } 
                 return instance; 
            } 
         }
     * 餓漢式是在類一載入的時候就直接進行了例項化,本身就是執行緒安全的.
    
             //餓漢式單例類.在類初始化時,已經自行例項化  
            public class Singleton1 { 
                 private Singleton1() {} 
                 private static final Singleton1 single = new Singleton1(); 
                 //靜態工廠方法  
                 public static Singleton1 getInstance() { 
                      return single; 
                 } 
            }
    
  2. 什麼時候使用單例模式?
    * 當這個類的物件在多個地方建立的時候,使得內部的方法多次呼叫,但是我們希望只要一個物件操作這個方法,或者不希望多個地方同時呼叫這個方法,我們需要保持這個方法的單一性質,我們就用單利模式。

簡單的工廠類:

介面卡模式:

談談你在實際專案中怎樣解決一個BUG;

  1. 異常附近多列印log資訊
  2. 分析log日誌,進行斷點除錯,
  3. 除錯不出來,上stack Overflow貼上異常資訊,請加大牛
  4. 多看看程式碼,從原始碼中分析,查詢相關資訊。
  5. 網上搜尋相關問題,解決方案,或尋求師傅幫忙。

怎樣對Android進行優化

  1. listview優化,圖片優化,記憶體優化,儘量不使用過多的靜態類static,資料庫使用完成之後,要記得關閉cursor。廣播使用完之後要登出。

談談你對bitmap的理解,什麼時候應該手動呼叫bitmap.recycle().

  1. bitmap是Android中經常使用的一個類,它代表一個圖片資源,bitmap消耗記憶體很嚴重,如果不注意優化程式碼,經常會出現oom,優化方式通常有:使用快取;壓縮圖片;及時回收。
  2. 至於什麼時候使用是手動呼叫bitmap.recycle()方法,這個需要看具體場景了,原則是在不使用bitmap時,就要回收掉,需要注意的是,在Android2.3之前bitmap物件與畫素資料是分開存放的,bitmap物件存在Java heap中而畫素資料儲存在Native Memory中,這時黑有必要呼叫recycle回收記憶體,但是在2.3之後,bitmap物件和畫素資料都是存在Heap中,通過GC就可以回收記憶體。

你一般在開發專案中都是用什麼設計模式,如何來重構,優化你的程式碼?

  1. 較為常用的是單例設計模式和工廠設計模式以及觀察者模式,一般需要保證物件在記憶體中的唯一性時需要使用到單例模式,例如對資料庫操作的sqliteOpenHelpter的物件,工廠模式主要是為建立物件提供過渡介面,以便將建立的物件的具體過程遮蔽隔離起來,達到提高靈活性的目的,觀察者模式定義物件間的一種一對多的依賴關係,當一個物件的裝填發生變化時,所有依賴於它的物件都得到通知並自動更新。

Android中第二次登陸實現自動登入

  1. 這是一個實際的案例流程,前提條件是所有使用者相關的介面都走https,非使用者相關的列表類資料走http。
    1. 第一次登入的時候getUserInfo的時候帶一個長效的token,該長效的token用來判斷使用者是否登入和換取短的token;
    2. 把長效token儲存到sharedPreferences中,
    3. 介面請求用長效的token換取短token,短token服務端可以根據你的介面最後一次請求作為標識,超時時間為一天
    4. 所有介面都用短效token
    5. 如果返回短效token失效,執行3步驟在直接標識當前介面,
    6. 如果長效token失效(使用者換裝置或者超過兩週),提示使用者重新登入。

相關文章