自己總結的安卓面試題(一)

目錄

安卓的多線程

Java基礎知識

集合

網絡相關面試題

性能優化

View相關

進程

其他的補充知識點


  • 安卓的多線程

  1. 進程和線程的區別
    1. 進程是CPU資源分配的最小單位,線程的CPU調度的最小單位;
    2. 進程之間不能共享資源,線程之間可以共享所在進程的地址空間和資源;
    3. 一個進程中可以有多個線程,一個線程只能屬於一個進程;
    4. 進程可以開啓線程和其他進程
  2. 創建線程的三種方式
    1. 繼承Thread類重寫run方法;
    2. 實現Runnable接口重寫run方法;
    3. 實現Callable重寫call方法;

可以提供一個返回值

Call方法可以拋出一個異常

可以通過運行Callable得到的Future對象監聽目標線程調用call方法的結果,得到返回值;

  1. 對線程池的理解
    1. 線程池在任務未到來之前會創建一定數量的線程放在空閒隊列中,這些線程都是處於睡眠狀態;當請求到來之後,會給其分配一個空閒線程,然後運行;如果沒有空閒線程,會創建新線程,如果最大線程數滿了,就會拋出異常.
    2. 作用:
      • 是爲了儘可能減少對象創建和銷燬的次數,提高性能,減少CPU資源的消耗,可以控制線程數量,避免內存消耗過度.
      • 當線程調度任務發生異常時,會重新創建一個線程來代替異常線程;
    3. 如何創建:使用ThreadPoolExecutor
  2. 線程的狀態
    1. New:新建狀態,還沒有調用start
    2. Runnable:可運行狀態,調用start進入可運行狀態
    3. Blocked:阻塞狀態,被鎖阻塞,暫時不活動
    4. Synchronized:關鍵字修飾的方法或代碼塊獲取鎖時的狀態
    5. Waiting:等待狀態,不運行任何代碼,等待線程調度器調度,sleep,wait用來暫停當前線程的執行,任何其他線程都可以中斷當前線程的睡眠;
    6. Timed Waiting:超時等待,在指定時間自行返回;
    7. Terminated:終止狀態,包括正常終止和異常終止;
  3. wait和sleep的區別
    1. Wait用於線程間的通信,如果等待且其他線程被喚醒時,它會釋放鎖;
    2. Sleep僅是釋放CPU資源或者讓當前線程停止執行一段時間,並不會釋放鎖;
  4. 線程中斷
    1. Java中提供了線程中斷機制相關的interrupt()方法,他將中斷標識位設置爲true,具體是否要中斷由程序來判斷;
    2. New和Terminal不理會線程中斷請求;
    3. Runnable和Blocked調用interrupt會將標誌位設置爲true;
    4. Waiting和Timed Waiting會發生InterruptedException異常;
  5. Thread爲什麼不能用stop方法停止線程
    1. 會拋出ThreadDeath異常;
    2. 釋放該線程持有的所有的鎖,數據可能會被破壞;

 

 

  1. 同步方法和同步代碼塊

當多個線程同時操作一個可共享的資源變量時,就會導致數據不準確,解決方法:

    1. 同步方法.即用synchronized關鍵字修飾的方法,在調用此方法前,需要獲得內置鎖,否則處於阻塞狀態;synchronized也可以修飾靜態方法,調動此靜態方法,會鎖住整個類;
    2. 同步代碼塊:synchronized修飾的語句塊,
    3. 使用特殊域變量volatile實現線程同步,他會保證修改的值立即更新到主存中,即內存可見性;
    4. 使用重入鎖:
      • ReentrantLock()方法,創建一個ReentrantLock實例;
      • lock()獲得鎖;
      • unlock()釋放鎖;
    5. 使用局部變量實現線程同步:使用ThreadLocal來管理變量,每一個線程都有該變量的副本,副本之間獨立
  1. 線程通信機制
    1. 四大角色
      • Message:消息的載體,常用的四個字段:arg1,arg2,what,obj

Obj攜帶Object對象,其他三個攜帶整形數據

      • MessageQueue:消息隊列,每個線程只有一個
      • Looper:調用loop()方法,進入到一個無限循環(沒有新消息就阻塞),每當MessQueue有消息就取出來,每個線程只有一個Looper
      • Handler:發送和處理消息
      • ThreadLocal:每個線程私有的本地存儲區域,存儲對象
  1. 原子性,可見性,有序性
    1. 原子性:某一個操作不可分割,比如a=0是原子操作,a++不是原子操作,非原子操作都存在線程安全問題
    2. 可見性:指線程之間的可見性,如用volatile修飾的內容具有可見性,但不能保證其原子性,因爲volatile只能使用在變量級別,不能對方法進行修飾;
    3. 有序性:線程執行的順序按代碼的先後順序,java內存模型中,允許編譯器和處理器對指令進行重排序,這樣會影響到多線程併發執行的正確性.所以可以通過volatile和synchronized以及Lock保證一定的有序性.
  2. 死鎖產生的四個必要條件
    1. 互斥條件,一個資源一段時間內僅能夠被一個進程所佔有;
    2. 請求和保持條件:進程已經持有了至少一個資源,但又提出了新的資源請求,而該資源被其他進程所佔有,此時請求會被阻塞,但自己的資源又保持不放;
    3. 不可剝奪條件:進程所獲得的資源在未使用完畢之前,不能被其他進程強行奪走,只能自己主動釋放;
    4. 循環等待條件:若干進程形成循環等待資源的關係,環路中每一個進程所佔有的資源被另一個進程所申請.
  3. 死鎖的避免

系統對進程所發出的每一個能夠滿足的資源申請進行動態檢查,並根據檢查結果決定是否分配資源.

 

 

  1. 控制線程的個數
    1. 使用semphore來控制,acquire來請求一個線程,信號量-1,release()釋放一個信號量,信號量+1
    2. 使用線程池executor,new一個CachedThreadPool固定線程;
    3. ThreadPoolExecutor的六個參數:
      • CorePoolsize:核心池大小
      • Maxnumpoolsize最大池大小,工作隊列滿了之後放這裏,滿了就會報異常
      • Workqueue:工作隊列:核心池放不下的會先放在這裏
      •  

 

  • Java基礎知識

  1. Java中堆和棧的理解
    1. 堆內存:
      • 用於存儲java中的對象和數組,當我們new一個對象或者創建一個數組,就會在堆內存中開闢一塊空間;
      • 生存期不必告訴編譯器,存取速度較慢;
      • 堆是所有線程共享的一塊公共區域,對象都在堆裏創建,但爲了提升效率,線程會從堆中拷貝一個緩存到自己的棧中;
    2. 棧內存:
      • 主要用於執行程序,比如基本類型的變量和對象的引用變量;
      • 棧數據數據大小和生存期是確定的,存取速度比堆快;
      • 棧是一塊和線程相關的內存區域,每個線程都有自己的棧內存,用於存儲本地變量,方法參數和棧調用;
  2. JVM運行時的內存分佈
    1. 線程共享:
      • 方法區:存放已被加載的類信息,常量,靜態常量;
      • 堆:java內存最大的一塊,所有對象實例,數組都存放在java堆,gc回收的地方;
    2. 線程私有:
      • 虛擬機棧:java虛擬棧:存放基本數據類型,對象的引用,方法出口等;
      • 本地方法棧
      • 程序計數器
  3. 四種引用:
    1. 強引用:若內存中的對象具有強引用,即時內存不足,拋異常,垃圾回收器也不會回收;如果顯示地設置爲null,或超出生命週期範圍,就可以考慮回收;
    2. 軟引用:如果內存空間足夠,GC不會回收,內存空間不足,就會回收;如果軟引用被gc回收,虛擬機就會把這個軟引用加入到與之關聯的引用隊列中;
    3. 弱引用:gc一旦發現只具有弱引用的對象,就會回收;並把這個弱引用加入到與之相關聯的引用隊列中;
    4. 虛引用:並不會決定對象的生命週期,且必須和引用隊列聯合使用;
  4. equals和hashCode的區別:
    1. 兩個對象equals,hashCode一定相等
    2. HashCode不相等,一定不equals
  5. String,StringBuffer,StringBuilder的區別
    1. String字符串常量,不可變,每次改變相當於生成一個新的對象;
    2. StringBuilder字符串變量,線程不安全,效率高於StringBuffer;
    3. StringBuffer,字符串變量,線程安全;
  6. 內部類
    1. 成員內部類:位於外部類成員位置的類,可以使用外部類中的成員變量和成員方法;
      • class Outer {
      •     private int age = 20;
      •     //成員位置
      •     class Inner {
      •         public void show() {
      •             System.out.println(age);
      •         }
      •     }
      • }
    2. 局部內部類:定義在在方法和作用域中
      • class Outer {
      •     public void method(){
      •         class Inner {
      •         }
      •     }
      • }
    3. 匿名內部類:無構造方法
    4. 靜態內部類:由static修飾的類,不能使用外圍類的非static的變量和方法
    5. 作用:每個內部類都能獨立地繼承一個接口的實現,內部類解決java只能單繼承
  7. 靜態代理和動態代理的區別:
    1. 靜態代理:由程序員創建或者由特定工具自動生成源代碼,在程序運行前,代理類的.class文件就存在;
    2. 在程序運行時,運用反射機制動態創建;
  8. Java反射機制
    1. 在運行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法,對於任意一個對象,都能夠調用它的任意一個屬性和方法;

 

 

  • 集合

  1. HashMap和HashTable的區別
    1. HashMap支持key和value爲null,HashTable不允許,是因爲HashMap對null進行了特殊處理,將null的hashCode值定爲0
    2. hashMap不是線程安全,HashTable是線程安全的;
    3. hashMap實現線程安全的方式爲Collections.synchronized(new HashMap());
    4. HashMap默認長度爲16,擴容爲原先的2倍,HashTable默認長度爲11,擴容爲原來的2n+1;
    5. HashMap繼承AbstractMap,HashTable繼承自Dictionary
  2. HashMap和HashSet的區別
    1. HashMap實現了map接口,hashmap存儲鍵值對;hashset實現了set接口,僅存儲對象;
    2. Hashmap使用put()方法添加,使用鍵對象來計算hashcode值;hashset是使用add()方法將元素放入set中,使用成員對象來計算hashcode值;
    3. Hashmap比較快,因爲是使用唯一的鍵來獲取對象,hashset比較慢,因爲要比較兩個對象是否相同;
  3. Hashmap和Hashset如何判斷元素重複
    1. Hashmap可以判斷key是否相同,也可以判斷value是否相同;
    2. Hashset不能添加重複的元素,當調用add()方法時,首先會計算hashCode值,如果相同就調用equals方法看是否返回true,如果爲true說明元素已經存在;
  4. Arraylist和vector的區別
    1. Vector加入了同步機制,線程安全,arraylist線程不安全;
    2. Vector加入了synchronized同步機制,效率相對慢一點;

 

  • 網絡相關面試題

  1. TCP/IP五層模型:應用層,傳輸層,網絡層,數據鏈路層,物理層
  2. 三次握手
    1. 第一次:建立連接時,客戶端發送syn包(seq=j)到服務器,並進入SYN_SENT狀態,等待服務器確認;
    2. 第二次:服務器收到syn包,必須確認客戶的SYN(ack=j+1),同時自己也發送一個SYN包(seq=k);
    3. 客戶端收到服務器的SYN+ACK包,向服務器發送確認包ACK(ack=k+1),此包發送完畢,客戶端和服務器進入ESTABLISHED狀態,完成三次握手。
    4. 爲什麼是三次而不是兩次:爲了數據傳輸,TCP協議的通信雙方都必須維護一個序列號,三次握手的過程即通信雙方互相告知序列號起始值的過程;
    5. 握手過程中包中不包括數據,握手完畢之後,纔開始傳送數據.
  3. 四次揮手
    1. 第一次:客戶端發送報文告訴服務器沒有數據要發送了;
    2. 第二次:服務器收到,告訴客戶端收到
    3. 第三次:服務端向客戶端發送報文,請求關閉連接;
    4. 第四次:客戶端收到關閉連接的請求,向服務端發送報文,服務端關閉連接;
    5. 爲什麼不是三次:第二次揮手只是確認客戶端的結束報文段,不代表服務端的數據已經傳輸完畢了,這個傳輸完畢的時間不確定,可能會使得客戶端長時間得不到響應,造成資源浪費
  4. TCP和UDP的區別
    1. TCP面向連接,UDP無連接;
    2. TCP提供可靠的服務,UDP不保證可靠交付;
    3. TCP面向字節流,UDP面向報文;
    4. TCP全雙工可靠信道,UDP是不可靠信道;
    5. TCP連接是點到點,UDP是支持一對一,多對多;
  5. http協議
    1. 基於請求和響應模式的無連接,無狀態,應用層協議
    2. 簡單快速:協議簡單,通信速度快;
    3. 靈活:成功傳輸任意類型的數據對象,由Content-Type標記;
    4. 無連接:每次處理一個請求,處理完成即斷開;
    5. 無狀態:對事物處理沒有記憶功能;
    6. http是應用層的協議,底層基於TCP/IP協議
  6. get和post的區別
    1. Get參數通過url傳遞,post是在requset body中傳遞;
    2. Get在url傳遞的參數有長度限制,post沒有;
    3. Get參數會暴露在url上,安全性不如post;
    4. Get只接受ASCII字符,post無限制;
    5. Get回退時無害,post會再次請求;
    6. Get只能進行url編碼,post支持多種編碼方式;
  7. https
    1. 是http的安全版;
    2. 應用層http和傳輸層tcp中間加多了一層TLS/SSL加密套件,https就是應用層將數據給到TLS/SSL,然後將數據加密後,再給到TCP進行傳輸;
  8. 加密算法
    1. 對稱加密:加密和解密是同一個密鑰;(代表:DES)
    2. 非對稱加密:A和B各有兩把鑰匙,一把公鑰,一把私鑰,A用B公鑰進行加密,B用B的私鑰進行解密,反過來一樣;(代表:RSA)
  9. Volley
    1. 2.3之前使用HttpClient,之後使用HttpUrlConnection;
    2. 適合進行數據量不大但通信頻繁的網絡操作;對於大數據量的操作,比如文件下載,表現很糟糕,因爲volley會把返回的流導入內存中,下載大文件會發生內存溢出;
    3. Volley執行的過程:默認情況下,volley會開啓四個網絡調度線程和一個緩存調度線程;首先請求會加入緩存隊列,緩存調度線程如果找到該請求的緩存就直接讀取該緩存並解析,否則,這個請求就加入網絡隊列;

 

    1. Volley爲什麼不適合上傳大文件:適合小且頻率高的?
      • Volley的網絡請求線程池默認大小爲4,可以併發4個請求,大於4個,會排在隊列中,併發量小所以適合數據小頻率高的請求;
      • 下載文件會把流存入內存中,導致內存溢出;
  1. Okhttp
    1. 最大併發量爲64
    2. 使用連接池技術,支持5個併發的socket連接,默認keepAlive時間爲5分鐘,解決tcp握手和揮手的效率問題;
    3. 利用相應緩存避免重複的網絡請求;
    4. 請求失敗,自動重連;
    5. 支持SPDY協議,是一種基於TCP的應用層協議;
    6. Okhttp的缺點:
      • 消息回來需要切到主線程自己去寫;
      • 調用比較複雜,需要進行封裝;
      • 緩存失敗:爲了信息傳輸的安全性,對請求進行加密.可能導致緩存系統失效;
    7. Okhttp用到哪些設計模式:
      • Builder設計模式,如構建對象OkhttpClient,參數類型相同且很多參數可以爲空時,可以用Builder模式完成;
      • 工廠方法模式:如源碼中的接口Call;
      • 單例模式
      • 觀察者模式如EventListener,監聽請求和響應;
      • 策略模式;
      • 責任鏈模式,如攔截器;
  2. Retrofit
    1. Retrofit底層是基於okhttp實現的,使用運行時註解的方式工作;
    2. 通過java接口與註解來描述網絡請求,並用動態代理生成網絡請求的request,然後通過client來調用相應的網絡框架(默認爲okhttp)去發起網絡請求,並將返回的response通過converterFactory轉換爲相應的數據model,最後通過callAdapter轉換成其他數據方式;
    3. 流程:
      • 解析註解->配置網絡請求參數;
      • 動態代理->生成請求對象;
      • 網絡請求適配器->將請求對象進行平臺適配;
      • 網絡請求執行器->發送請求;
      • 數據轉換器->解析返回數據;
      • 回調執行器->切換線程;
      • 主線程->處理結果;
    4. 優點
      • 可以配置不同的http client來實現網絡請求,如okhttp,httpclient;
      • 參數註解可以定製;
      • 支持同步,異步,rxjava;
      • 超級解耦;
      • 可以配置不同的反序列化工具來解析數據,如json,xml;

 

  • 性能優化

  1. 圖片如何三級緩存?
    1. 三級緩存:加載某張圖片時,先去LruCache中尋找圖片,沒有則去SoftReference中取出圖片使用,沒有則去文件系統中尋找,沒有則去網上加載圖片;
    2. Lrucache是存儲最近,最後使用的圖片,最近最少使用的會被移除出去;當被移除的時候,會將圖片添加到softreference中,軟引用不會影響系統運行;
  2. Bitmap如何處理大圖,如何預防OOM?
    1. 調整圖片大小;
      • BitMapFactory的Options參數,通過inSampleSize參數可以對一個圖片進行採樣縮放;
    2. 及時回收不用的圖片資源:將暫時不用的圖片recycle();
    3. 緩存圖片到內存中:LruCache專門處理圖片緩存;
  3. 內存回收機制和GC算法?
    1. 內存判定對象可回收的兩種機制:
      • 引用計數算法:被引用計數加一,引用失效,計數減一,計數器爲0就是不可以再被使用的,難以解決對象之間相互循環引用;
      • 可達性分析法:通過一系列GCRoots的對象作爲起始點,從這些節點向下搜索,剩餘的就是不可達的;
    2. GC回收算法:
      • 分代收集算法:根據對象存活週期,將Java堆分爲新生代和老年代
        1. 新生代:大批對象死去,只有少量存活,使用複製算法只需複製少量存活對象即可;
          1. 複製算法:把可用內存把容量劃分爲大小相同的兩塊,每次只使用其中一塊,當這一塊內存用盡後,把還存活着的對象複製到另一塊,再把這一塊內存空間一次清理掉,
        2. 老年代:對象存活率高,使用標記-清理算法或者標記整理算法,只需標記較少的回收對象即可
          1. 標記-清理算法:首先標記出所有需要回收的對象,然後統一清理;但會導致導致大量的內存碎片;
          2. 標記-整理算法:標記出所有需要回收的對象,然後把所有存活的對象整理到一端,不會產生內存碎片;
  4. 內存溢出和內存泄漏的區別:
    1. 內存溢出:程序在申請內存時,沒有足夠內存空間供其使用,出現out of memory,Android系統爲每一個應用申請到的內存有限;
    2. 內存泄漏:指程序在申請內存後,被某個對象一直持有,無法釋放已經申請的內存空間;內存泄漏的累積後果很嚴重;
  5. 內存溢出的原因
    1. 發生地點:堆內存和java虛擬棧中
    2. 堆內存溢出:
      • 生產者消費者模型,
        1. 如註冊後忘記註銷;
        2. 添加到隊列,忘記控制隊列大小;
      • 循環引用
        1. Fastjson轉json
    3. 棧內存溢出:遞歸
  6. 內存泄漏的原因
    1. 根本原因:對象的生命存活時間不一致
    2. 發生地點:方法區,堆,java虛擬棧
    3. 單例模式
      • 案例:單例構造方法中傳遞的context爲某一個activity,在activity中調用了單例的構造方法;
      • 泄漏原因:activity生命週期比單例類短,無法釋放,導致泄漏;
      • 解決:Context傳遞應用Application的Context,即單例對象的生命週期和Application一樣長,不會出現內存泄漏的問題;
    4. 靜態變量導致的內存泄漏:
      • 案例:一個activity定義了一個靜態變量;
      • 泄漏原因:靜態變量存儲在方法區,生命週期從類加載到整個進程結束,一旦靜態變量初始化後,他所持有的引用,知道進程結束後纔會釋放;
      • 解決方法:在onDestroy中將靜態變量賦值爲null;
    5. 非靜態內部類導致的內存泄漏:
      • 案例:
        1. Handler裏面調用Activity的方法,Handler會被底層的ThreadLocal綁定,所以生命週期比Activity週期長;
        2. activity中開了一個線程去請求數據,然後退出activity ,因爲線程持有activity的引用,導致activity不能及時回收;
      • 泄漏原因:非靜態內部類默認會持有外部類的引用,當非靜態內部類對象的生命週期比外部類對象的生命週期長時,就會導致內存泄漏;
      • 解決方法:Handler提取出來,引用Activity時用WeakReference包裝起來;或者把Handler聲明爲靜態類.因爲靜態內部類不會持有外部類的引用;
    6. 未取消註冊回調導致的內存泄漏
      • 在activity中註冊廣播,在銷燬activity時沒有取消註冊;
      • 泄漏原因:廣播會一直存在系統中,一樣持有activity的引用,導致內存泄漏;
      • 解決方法:及時取消註冊;
    7. 集合中的對象未清理造成內存泄漏:
      • 案例:一個對象被添加到了集合中,該對象是不能被gc回收的;
    8. 資源未關閉導致內存泄漏:
      • 案例:WebView
    9. 沒有有效利用已有的對象,容易造成泄漏,例如,使用過的Bitmap對象沒有調用recycle()方法釋放內存,構造Adapter沒有使用緩存的convertView對象;

 

  1. 哪些工具檢測內存泄漏:
    1. DDMS-Heap
      • 實時查看程序中的內存的使用信息;
    2. MAT分析方式
      • Histogram,列出內存中每個對象的名字,數量和大小;
      • Dominator Tree將所有內存中的對象按大小排序;
  2. 如何優化ListView
    1. 複用convertView
      • 當convertView不爲空時對其進行復用;
    2. 定義存儲控件引用類ViewHolder
      • 在第一次創建時convertView將控件找出,在第二次複用時,直接使用convertView的getTag()獲得這些控件;
    3. 數據的分批和分頁加載
      • 分批加載
      • 分頁加載
    4. 圖片的處理
      • 要用WeakReference來存儲與獲取圖片信息;
      • 獲取到圖片時,對圖片進行壓縮存在內存中;
      • 在getView()方法中做圖片轉換時,產生的中間變量要及時釋放;

 

  • View相關

  1. View的繪製過程:
    1. OnMeasure,測量視圖大小,從頂層父View到子View遞歸調用measure方法,measure又回調onMeasure();
    2. OnLayout():確定View的位置,進行頁面佈局;從頂層父View向子View遞歸調用view.layout方法,即父View根據上一步measure子View所得到的佈局大小和佈局參數,將子View放在合適的位置上;
    3. onDraw():繪製視圖,
      • 繪製背景background.draw(canvas)
      • 繪製自己(onDraw)
      • 繪製children(dispatchDraw)
      • 繪製裝飾(onDrawScrollBars)
  2. View事件分發機制:
    1. DispatchTouchEvent:用於進行事件的分發;如果事件能夠傳遞給當前View,那麼此方法一定會被調用,返回結果受當前View的onTouchEvent和下級View的dispatchTouchEvent的影響,表示是否消耗當前事件;
    2. onInterceptTouchEvent:在上訴方法內部調用,對事件進行攔截,該方法只在ViewGroup中有;一旦攔截,則執行ViewGroup中的onTouchEvent,在ViewGroup中處理事件,而不接着分發View.
    3. onTouchEvent,在dispatchTouchEvent中調用,用來處理點擊事件,返回結果表示是否消耗當前事件;
  3. 如何解決View的事件衝突:
    1. 外部攔截法:點擊事件都要經過父容器的攔截處理,如果父容器需要此事件就攔截,否則不攔截,需要重寫父容器的onInterceptTouchEvent方法,在內部做出相應的攔截;
    2. 內部攔截法:指父容器不攔截任何事件,將所有事件都傳遞給子容器,如果子容器需要就直接消耗,否則交由父容器進行處理,需要配合requestDisallowInterceptTouchEvent方法;
  4. Scroller怎麼實現View的彈性滑動?
    1. 在MotionEvent.ACTION_UP事件觸發時調用startScroll()方法,該方法並沒有進行實際的滑動操作,而是記錄滑動相關量
    2. 接着調用invalidate/postinvalidate()方法,請求view重繪,導致view.draw方法被執行;
    3. 在view重繪後會在draw方法中調用computeScroll方法,而computeScroll又會向Scroller獲取當前的scrollX和scrollY,然後通過scrollTo實現滑動;接着又調用postInvalidate方法進行第二次重繪,和之前一樣,反覆導致View進行小幅度的滑動;
  5. Invadate和postinvalidate的區別:
    1. Invalidate和postinvalidate都用於刷新View,主要區別是:
    2. invalidate在主線程中調用,若在子線程中需要配合handler;
    3. Postinvalidate可在子線程中直接調用;
  6. SurfaceView和View的區別
    1. View要在UI線程進行刷新,SurfaceView可以在子線程中進行刷新;
    2. View適合於主動刷新,Surface適合於被動刷新,如頻繁刷新,而View頻繁刷新可能會阻塞主線程;
    3. SurfaceView底層雙緩衝機制,而View沒有,適合於頻繁刷新,刷新時數據處理量很大的頁面(如視頻播放界面)
  7. 自定義View如何考慮機型適配
    1. 合理使用wrap_content,match_parent
    2. 儘可能使用RelativeLayout
    3. 針對不同的機型,使用不同的佈局文件放在對應的目錄下,android會自動匹配;
    4. 儘量使用.9圖片;
    5. 使用與密度無關的像素單位dp,sp;
    6. 切圖的時候切分辨率大的圖;

 

  • 進程

  1. 如何開啓多進程?
    1. 在AndroidManifest中給四大組件指定屬性,android:process開啓多進程模式;
    2. 在內存允許的條件下可以開啓N個進程;
  2. 爲何需要IPC?多進程通信可能出現的問題
    1. 通過開啓多進程獲取更大內存空間,兩個或多個應用之間共享數據
    2. 造成的問題:
      • 靜態成員和單例模式完全失效;獨立的虛擬機造成;
      • 線程同步機制完全失效;獨立的虛擬機造成;
      • SharePreferences的可靠性下降;Sp不支持兩個進程併發進行讀寫,有一定機率導致數據丟失;
      • Application會多次創建;新進程會分配獨立的虛擬機;
  3. 進程間通信的方式:
    1. Intent:只能傳輸Bundle所支持的數據類型,四大組件之間的通信
    2. AIDL:Android中最常用的,使用稍微複雜,需要注意線程同步;
    3. ContentProvider:進程間的大量數據共享,主要對外提供數據的CRUD操作;
    4. Socket:常用於網絡通信中,只能傳輸原始的字節流;
  4. Binder的優點
    1. 傳輸效率高,可操作性高:傳輸效率影響因素主要是內存拷貝的次數,Binder只需一次拷貝;
    2. 實現C/S架構方便:Server和Client端獨立,穩定性較好;
    3. 安全性較高;

 

  • 其他的補充知識點

  1. Service啓動方式
    1. 通過startService(),會經歷onCreate->onStartCommand,stopService的時候會調用onDestroy,如果是調用者直接退出而沒有調用stopService時,Service會一直在後臺運行,下次調用者起來仍然可以stopService;
    2. 通過bindService,Service只會運行onCreate,這個時候調用者和Service綁定在一起,調用者退出Service也會onUnbind->onDestroy;
    3. 如果先是start,然後bind時就直接onbind
    4. 如果先是bind,再start,就直接startCommand
    5. 兩個同時用,需要先onUnbind -> 然後StopService();
  2. EventBus的理解
    1. EventBus是一款Android優化的發佈/訂閱消息總線,它簡化了組件和組件,組件和後臺線程間的通信
    2. 三個元素:
      • Event:事件
      • Subscriber:事件訂閱者,接收特定的Event事件
      • Publisher:事件發佈者,同於通知Subscriber有事件發生
    3. 實現了觀察者設計模式,優點爲代碼簡潔優雅,使用方便,開銷小,有助於代碼解耦;
  3. 生命週期的執行:
    1. Activity A到Activity B的:A的onPause() -> B 的onCreate() -> onStart() -> onResume() -> A的onStop();
    2. 從B返回A:B的onPause() -> A的onRestart() -> onStart() -> onResume() -> B的onStop() -> onDestroy();
    3. 退出A : onPause() -> onStop() ->onDestroy();
  4. 屬性動畫(Property Animation)和(Tween Animation)的區別:
    1. 補間動畫只是改變View的顯示效果,不會真正改變View的屬性;屬性動畫會改變View的實際屬性值;
    2. 補間動畫只是針對於View,屬性動畫可以不作於View;
  5. ListView和RecyclerView的區別;
    1. ViewHolder:ListView中ViewHolder需要自己定義,也可以不定義;recyclerview中viewholder必須定義;
    2. LayoutManager:R提供了根據了更加豐富的佈局管理,包括linearlayoutmanager支持水平和豎直方向;StaggeredGridLayoutManager支持瀑布流;GridLayoutManager支持網格展示;
    3. ItemAnimator:R中用於添加,刪除,移動的動畫效果;
    4. ItemDecoration:R默認不加間隔符,使用這個來實現間隔符;
  6. Java中的集中變量修飾符
    1. Public修飾的變量爲公有變量,如果公有變量又在一個共有類中,這個變量可以被所有包中的所有類訪問;
    2. Protected保護訪問修飾符:若在一個共有類中,可以被所在類本身,同一個包中的所有類,其他包中該類的子類;
    3. 默認訪問修飾符:同一個包中的所有類;
    4. Private:所在類訪問;

 

  1. ANR
    1. Application Not Responsing ,即應用無響應;
    2. 原因:
      • 當前的事件沒有機會得到處理;
      • 當前事件正在處理,沒有及時完成;
    3. 案例:
      • 點擊事件或者鍵盤輸入事件在5s內無法得到響應;
      • BroadCastReceiver的onReceive()函數運行在主線程中,10s內無法得到處理;
      • 前臺服務在20s無法完成處理,後臺服務200s內沒有執行完畢;
      • ContentProvider的publish在10s內沒有完畢;
    4. 解決:
      • 把io操作放在工作線程中處理,減少耗時操作和錯誤操作,如網絡請求,數據庫操作,Socket操作,文件讀寫等放在子線程;

 

  1. 主線程的Looper.loop()一直無限循環爲什麼不會造成ANR?
    1. looper.loop() 不斷地接收事件、處理事件,每一個點擊觸摸或者說Activity的生命週期都是運行在 Looper.loop() 的控制之下,如果它停止了,應用也就停止了。只能是某一個消息或者說對消息的處理阻塞了 Looper.loop();也就說我們的代碼其實就是在這個循環裏面去執行的,當然不會阻塞了。

 

  1. 一個線程中有幾個Handler,幾個Looper,幾個MessageQueue
    1. 一個線程只能有一個Looper,因爲Thread中使用ThreadLocal<Looper>去存儲當前線程的Looper,ThreadLocal底層是hashmap,key值是線程本身,所以只有一個looper;
    2. 一個messageQueue,因爲一個線程只有一個looper
    3. 一個線程可以存在多個handler,可以在發送消息的時候使用message.setTarget(handler)來設置當前message的target handler;

 

 

  1. 數據庫如何高效插入數據
    1. 在try中開啓事務
    2. 在finally中關閉事務
  2. Activity的狀態保存和恢復
    1. 保存:當Activity A 在前臺時,按下home鍵,切換其他的應用,橫豎屏切換,系統會調用onSavedInstanceState()方法;
    2. 恢復:onRestoreInstanceState()
  3. Fragment的add和remove
    1. Remove是移除fragment,當fragment不加入back stack時,remove會一直調用到onDetach,加入到back stack時,會走到onDestroyView;
    2. 當fragment被另一個fragment調用replace時,並且壓入back stack時,View會銷燬,fragment本身沒有銷燬,也就是調用到了ondestroyView();
    3. Fragment的oncreateview多次執行,需要用一個rootView記錄一下oncreateView返回的View,下一次調用判斷一下rootView是否爲null
  4. Fragment之間數據的傳遞
      •  MainFragment mainFragment =
      •            (MainFragment) getActivity()
      •            .getSupportFragmentManager()
      •            .findFragmentByTag("mainFragment");//另一個fragment的tag
    1. 接口回調
    2. EventBus
      • 引入EventBus:添加依賴
      • 註冊事件接收者,在接收Fragment中進行註冊EventBus.getDefault().register(this);
      • 發送事件: EventBus.getDefault().post(mDatas.get(position));
      • 定義事件類型
      • 接收事件並處理:
        1. @Subscribe
        2. public void onEvent(String data) {
        3.     bt_main.setText(data);
        4. }
      • 註銷事件接收:
        1. @Override
        2. public void onDestroy() {
        3.     super.onDestroy();
        4.     EventBus.getDefault().unregister(this);
        5. }
  5. Activity與Service之間
    1. 通過startService()來啓動服務,不過不好掌控
    2. 使用bindService(),就可以在ServiceConnection中獲取Service的實例,就實現了activity中獲取到service的實例對象,就可以調用service方法;
  6. 對ContentProvider的理解
    1. 結構化方式存放的數據,以相對安全的方式來封裝數據並且提供簡易的處理機制,提供了不同進程間數據交互的標準化接口;
  7. 說說ContentProvider、ContentResolver、ContentObserver 之間的關係
    1. ContentProvider是內容提供者,對其他應用進行數據共享,其他應用可以通過ContentProvider對你應用中的數據進行增刪查改;
    2. ContentResolver內容解析者,作用是按照一定的規則對內容提供者的數據解析;
    3. ContentObserver:內容觀察者,目的是觀察特定uri引起的數據庫的變化,既而做一些相應的處理,類似於數據庫中的觸發器;
  8. 描述一下BroadcastReceiver的理解
    1. 使用了設計模式中的觀察者模式,基於消息的發佈/訂閱事件模型,將廣播的發送者和接收者解耦;
    2. 註冊的方式:
      • 靜態註冊:在AM中註冊,不受任何組件的生命週期影響;
      • 動態註冊:組件結束前,必須註銷;
      • 最好在onresume中註冊,onpause中註銷,否則造成內存泄漏;
    3. 方式廣播:intent通過sendBroadCast發送出去;
    4. 類型:
      • 普通廣播:開發者自身定義intent的廣播
      • 系統廣播:涉及到手機的開機,網絡變化,拍照等都會相應的廣播;
      • 有序廣播:廣播接收者按照先後順序來接收;按照priority屬性大小排序,相同的話就是動態註冊的優先;
      • 本地廣播:安全性高,效率高;exported設置爲false,非本應用的廣播不接收,指定該廣播接收器所在的包名,使用封裝好的LocalBroadcastManager使用方式與全局廣播相同,只是註冊和註銷的context變爲了LocalBroadcastManager的實例;
  9. 如何導入已有的數據庫
    1. 把源數據庫放入res目錄下,建立一個dbmanager,然後通過FileinputStream讀取數據庫,再用FileOutputStream把讀取到的數據寫入到data/data/包名下;
  10. LinearLayout和RelativeLayout的區別:
    1. RelativeLayout比LinearLayout慢是因爲會讓子View調用兩次measure過程,而LinearLayout只需要一次,如果LinearLayout有weight屬性時,也需要兩次;
    2. 不影響層級深度的情況下,使用LinearLayout和FrameLayout而不是Relat..;
    3. 儘量使用padding而不是margin
  11. 屏幕適配的知識點
    1. 屏幕尺寸:指對角線的長度,單位是英寸,一英寸=2.54釐米
    2. 屏幕分辨率:1px=1像素,屏幕分辨率越高,顯示效果越好;
    3. 屏幕像素密度:每英寸的像素點數;計算公式爲豎的分辨率的平方+橫的分辨率的平方開根號然後除以英寸數;
    4. 常見的
      • Mdpi:像素密度:120-160   hdpi 160 -240 xhdpi 240 -320  xxhdpi 320 - 480 xxxdpi 480-640
    5. 常用適配方案:
      • 使用wrap_content,match,weight
      • 自定義像素適配,以美工的設計尺寸爲原始尺寸,根據不同設備的密度來計算出寬和高;
      • 百分比適配
  12. 插值器和估值器
    1. 插值器:Interpolator:一個接口,設置屬性值從初始值到結束值的變化規律,
      • 在動畫效果的XML代碼中設置插值器屬性
      • 在java代碼中設置
    2. 估值器:TypeEvaluator,一個接口,插值器決定值的變化規律,即決定的是變化趨勢,接下來的具體變化數值交給估值器;
      • 屬性動畫特有的屬性;
      • 協助插值器實現非線性運動的動畫效果;
  13. Android的數據存儲方式
    1. SharePreference,SQLite,Content Provider,File,網絡存儲
    2. SharePreference本質是一個xml文件,存儲一些參數設置
    3. SQLite輕量級的數據庫支持SQL語法,Android還提供了一個SQLIteDataBaseHelper的類,提供了一些操作數據庫的api;
    4. Content Provider 實現數據共享;
    5. FIle: IO存儲方式,用於存儲數量大的數據,更新數據很難;
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章