Android面试题总结(三)
一、android 四種更行UI的方式
- 使用handler.post(Runnable)更新UI
- 使用handler發送消息,handleMessage處理消息更新UI
- 使用UI線程runOnUiThread(new Runnable(){})更新UI
- 使用View.post( Runnable)更新UI
- 使用子線程自帶的Looper更新UI:
二、死鎖的四個必要條件以及怎樣處理
http://www.cnblogs.com/jijiji/p/4855581.html
產生死鎖的四個必要條件:
(1) 互斥條件:一個資源每次只能被一個進程使用。
(2) 請求與保持條件:一個進程因請求資源而阻塞時,對已獲得的資源保持不放。
(3) 不剝奪條件:進程已獲得的資源,在末使用完之前,不能強行剝奪。
(4) 循環等待條件:若干進程之間形成一種頭尾相接的循環等待資源關系。
這四個條件是死鎖的必要條件,只要系統發生死鎖,這些條件必然成立,而只要上述條件之一不滿足,就不會發生死鎖。
舉例說明: 資源A,B; 進程C,D
資源A,B都是不可剝奪資源:一個進程申請了之后,不能強制收回,只能進程結束之后自動釋放。內存就是可剝奪資源
進程C申請了資源A,進程D申請了資源B。
接下來C的操作用到資源B,D的資源用到資源A。但是C,D都得不到接下來的資源,那么就引發了死鎖。
死鎖的解除與預防:
理解了死鎖的原因,尤其是產生死鎖的四個必要條件,就可以最大可能地避免、預防和解除死鎖。所以,在系統設計、進程調度等方面注意如何不讓這四個必要條件成立,如何確定資源的合理分配算法,避免進程永久占據系統資源。此外,也要防止進程在處于等待狀態的情況下占用資源。因此,對資源的分配要給予合理的規劃。
三、十個Android Material Design庫
http://blog.csdn.net/tiankong1206/article/details/47057719
四、Android中IntentService與Service的區別
http://blog.csdn.net/matrix_xu/article/details/7974393
Service中提供了一個方法:onStartCommand()
同時IntentService中提供了這么一個方法:onHandleIntent(Intent intent);
IntentService的內部實現:IntentService在執行onCreate的方法的時候,其實開了一個線程HandlerThread,并獲得了當前線程隊列管理的looper,并且在onStart的時候,把消息置入了消息隊列,
在消息被handler接受并且回調的時候,執行了onHandlerIntent方法,該方法的實現是子類去做的。
IntentService是通過Handler looper message的方式實現了一個多線程的操作,同時耗時操作也可以被這個線程管理和執行,同時不會產生ANR的情況。
五、對稱/非對稱加密
對稱加密與非對稱加密
http://www.cnblogs.com/jfzhu/p/4020928.html
對稱加密算法 VS 非對稱加密算法
https://segmentfault.com/a/1190000004461428
白話解釋 OSI模型,TLS/SSL 及 HTTPS
https://segmentfault.com/a/1190000004467714
JAVA加密算法(3)- 對稱加密算法(DES、3DES、AES)
https://segmentfault.com/a/1190000007286619
Java實現非對稱加密
https://segmentfault.com/a/1190000009081239
對稱密鑰加密(英語:Symmetric-key algorithm)又稱為對稱加密、私鑰加密、共享密鑰加密,是密碼學中的一類加密算法。這類算法在加密和解密時使用相同的密鑰,或是使用兩個可以簡單地相互推算的密鑰。實務上,這組密鑰成為在兩個或多個成員間的共同秘密,以便維持專屬的通訊聯系。與公開密鑰加密相比,要求雙方取得相同的密鑰是對稱密鑰加密的主要缺點之一
明文 <-> 密鑰 <-> 密文
常見的對稱加密算法有DES、3DES、AES、Blowfish、IDEA、RC5、RC6。
每個人生成一個“私鑰-公鑰”對,這個私鑰需要每個人自行進行保護!公鑰可以隨便分享,后面詳細說,同時,生成的這個“私鑰-公鑰”對還有個強大的功能就是,使用私鑰加密的信息,只能由該私鑰對應的公鑰才能解密,使用公鑰加密的信息,只能由該公鑰對應的私鑰才能解密!公鑰可以隨意分發,所以即使別人截取了,也只是知道該公鑰而已,但是要是想解密使用該公鑰加密的密文!只有一個人可以辦得到!就是張三! 為什么?李四使用張三的公鑰加密的信息,只有張三的公鑰所對應的私鑰,這里就是“張三私鑰”,該私鑰才可以解密!所以,沒有張三私鑰的第三方即時截取了這些密文,也破解不了!或者更嚴格的說在有限時間內比如說幾千年內是暴力破解不出的!
公開密鑰加密(英語:public-key cryptography,又譯為公開密鑰加密),也稱為非對稱加密(asymmetric cryptography),一種密碼學算法類型,在這種密碼學方法中,需要一對密鑰,一個是私人密鑰,另一個則是公開密鑰。這兩個密鑰是數學相關,用某用戶密鑰加密后所得的信息,只能用該用戶的解密密鑰才能解密。如果知道了其中一個,并不能計算出另外一個。因此如果公開了一對密鑰中的一個,并不會危害到另外一個的秘密性質。稱公開的密鑰為公鑰;不公開的密鑰為私鑰。
這種加密算法應用非常廣泛,SSH, HTTPS, TLS,電子證書,電子簽名,電子身份證等等。
網警可以冒充張三!!!!發送給李四“網警的公鑰”,而不是“張三的公鑰”,那么當李四收到該公鑰的時候,就不假思索的使用該公鑰加密了他的信息,然后毫不猶豫的將加密的密文發了過去,然后網警得意的笑了。
應用層(application layer)
傳輸層(transport layer)
網絡層(network layer)
數據鏈路層(data link layer)
物理層(physical layer)
物理層和數據鏈路層通過無線網傳輸使用的802.2傳輸協議,有線網的Ethernet(以太網)傳輸協議,還有網絡層的IPv4, IPv6協議,傳輸層的TCP, UDP協議,而我們熟悉的HTTP協議其實屬于應用層,所以HTTP是建立在TCP/IPv4或v6/以太網基礎上進一步細化用于傳輸“超文本”信息的協議,比如FTP也屬于應用層,也是在下面各層協議基礎上進行細化,專門用于“文件傳輸”的協議。
TLS/SSL,SSL(secure sockets layer)是TLS(transport layer security)的前身,為什么將他們合起來的,大家可以理解成都屬于同一東西的不同階段吧,比如該協議之前叫SSL后來改名成TLS了。
為什么要有這種協議呢?因為HTTP是使用明文傳輸,隨著網絡的發展,安全性越來越重要,所以大家就要想辦法讓傳輸更加安全,同時使用密碼學的成果,利用“非對稱加密算法”的思想以及OSI模型,來對HTTP的信息進行加密。
信息從HTTP經過TLS/SSL非對稱加密后傳出去,而在接收方,接收到信息是需要一層層向上進行,經過每層的“解包/解密”,最終通過HTTP轉換成超文本信息。
HTTPS 就是 “HTTP內容向下傳輸的時候加了一層TLS/SSL加密”
但是同樣的問題,就是我們怎么知道我們使用的公鑰就是銀行給我們的呢?即使我們所訪問的域名和銀行的域名一致,因為黑客完全可以通過修改我們本地的hosts文件,或者入侵dns,將域名映射到黑客的服務器。
所以,這就是CA(certificate authority),數字證書,數字簽名,公鑰基礎設施(PKI)等等名詞的來歷。
HTTP協議如何使用 TCP 連接:
HTTP對 TCP 連接的使用,分為兩種方式:俗稱“短連接”和“長連接”(“長連接”又稱“持久連接”,叫做“Keep-Alive”或“Persistent Connection”)
SSL/TLS協議的基本運行過程
SSL/TLS協議的基本思路是采用公鑰加密法,也就是說,客戶端先向服務器端索要公鑰,然后用公鑰加密信息,服務器收到密文后,用自己的私鑰解密,但是這里有兩個問題:
(1)如何保證公鑰不被篡改?
解決方法:將公鑰放在數字證書中,只要證書是可信的,公鑰就是可信的。
(2)公鑰加密計算量太大,如何減少耗用的時間?
解決方法:每一次對話(session),客戶端和服務器端都生成一個”對話密鑰”(session key),用它來加密信息。由于”對話密鑰”是對稱加密,所以運算速度非常快,而服務器公鑰只用于加密”對話密鑰”本身,這樣就減少了加密運算的消耗時間。
因此,SSL/TLS協議的基本過程是這樣的:
(1)客戶端向服務器端索要并驗證公鑰。
(2)雙方協商生成“對話密鑰”。
(3)雙方采用“對話密鑰”進行加密通信。
上面過程的前兩步,又稱為“握手階段”(handshake)。
以上圖片就是“握手階段”涉及四次通信,需要注意的是,“握手階段”的所有通信都是明文的。
SSL是Netscape公司所提出的安全保密協議,在瀏覽器(如Internet Explorer、Netscape Navigator)和Web服務器(如Netscape的Netscape Enterprise Server、ColdFusion Server等等)之間構造安全通道來進行數據傳輸,SSL運行在TCP/IP層之上、應用層之下,為應用程序提供加密數據通道,它采用了RC4、MD5 以及RSA等加密算法,使用40位的密鑰,適用于商業信息的加密。
HTTPS實際上就是SSL over HTTP,它使用默認端口443,而不是像HTTP那樣使用端口80來和TCP/IP進行通信。HTTPS協議使用SSL在發送方把原始數據進行加密,然后在接受方進行解密,加密和解密需要發送方和接受方通過交換共知的密鑰來實現。
HTTPS協議的需求是什么?
一般來說,HTTPS和HTTP的區別主要為以下四點:
(1)、https協議需要到ca申請證書,一般免費證書很少,需要交費。
(2)、http是超文本傳輸協議,信息是明文傳輸,https則是具有安全性的ssl加密傳輸協議。
(3)、http和https使用的是完全不同的連接方式,用的端口也不一樣,前者是80,后者是443。
(4)、http的連接很簡單,是無狀態的;HTTPS協議是由SSL+HTTP協議構建的可進行加密傳輸、身份認證的網絡協議,比http協議安全
六、熱修復、插件化技術
熱修復 有demo
http://blog.csdn.net/yangxi_pekin/article/details/54929740
Android 熱補丁動態修復框架小結
http://blog.csdn.net/lmj623565791/article/details/49883661
Android插件化
http://www.infoq.com/cn/articles/android-plug-ins-from-entry-to-give-up
輕量級插件化框架——Small
http://www.jianshu.com/p/7990714d10cb
Android組件化和插件化開發
http://www.cnblogs.com/android-blogs/p/5703355.html
從模塊化到組件化再到插件化
http://blog.csdn.net/u011486491/article/details/70216666
插件化需要掌握的知識:
- 學習Binder的最好方式就是AIDL
- 其次,是App打包的流程。
- 第三,App在手機上的安裝流程也很重要
- 第四,是App的啟動流程。
- 第五,插件Dex的加載,如何把插件Dex中的類加載到內存;資源加載的問題。一種是是重寫Context的getAsset、getResource之類的方法,偷換概念,讓插件讀取插件里的資源,但缺點就是宿主和插件的資源id會沖突,需要重寫AAPT。另一種是重寫AMS中保存的插件列表,從而讓宿主和插件分別去加載各自的資源而不會沖突。第三種方法,就是打包后,執行一個腳本,修改生成包中資源id。
- 第六點,在實施插件化后,如何解決不同插件的開發人員的工作區問題。就要用到Gradle腳本了,每個項目分別有各自的倉庫,有各自不同的打包腳本,只需要把自己的插件跟宿主項目一起打包運行起來,而不用引入其他插件,還有更厲害的是,也可以把自己的插件當作一個App來打包并運行。
技術流派,目前分三種
- 第一種是動態替換,也就是Hook。可以直接在Activity里做Hook,重寫getAsset的幾個方法,從而使用自己的ResourceManager和AssetPath;也可以在更抽象的層面,也就是在startActivity方法的位置做Hook,涉及的類包括ActivityThread、Instrumentation等;最高層次則是在AMS上做修改,也就是張勇的解決方案,這里需要修改的類非常多,AMS、PMS等都需要改動。
- 第二種是靜態代理,這是任玉剛的框架采取的思路。寫一個PluginActivity繼承自Activity基類,把Activity基類里面涉及生命周期的方法全都重寫一遍,插件中的Activity是沒有生命周期的,所以要讓插件中的Activity都繼承自PluginActivity,這樣就有生命周期了。
- Dex合并就是Android熱修復的思想。剛才說到了兩個項目——AndFix和Nuwa,它們的思想是相同的。原生Apk自帶的Dex是通過PathClassLoader來加載的,而插件Dex則是通過DexClassLoader來加載的。但有一個順序問題,是由Davlik的機制決定的,如果宿主Dex和插件Dex都有一個相同命名空間的類的方法,那么先加載哪個Dex,哪個Dex中的這個類的方法將會占山為王,后面其他同名方法都替換了。所以,AndFix熱修復就是優先加載插件包中的Dex,從而實現熱修復。由于熱修復的插件包通常只包括一個類的方法,體量很小,和正常的插件不是一個數量級的,所以只稱為熱修復補丁包,而不是插件。
技術周邊
- 首先是AAPT,資源沖突,就是說默認App應用,插件里的資源和數據資源沖突,如果不引入這個資源,相安無事。很多時候就算有沖突也無所謂,問題就出在插件引用資源的時候有沖突了,無法解決,怎么辦?那就要立刻改寫App。有一個關于打包的App,可以加當前的前綴,改成你想要的。比如,火車票和酒店分別取名,這樣就可以指定前綴、打包,插進一個模塊,資源的前綴都不一樣。小米也承認,會占用0x11這個前綴。這是需要關注的一個點。
- 第二是增量更新。360目前最牛逼的地方是,把所有數據跟之前一個版本差,產生增量的數據。他們當然也更新了插件化。360的劉存棟做了一個增量更新的框架。可以在后臺服務器把兩個版本的Android App做拆分,然后把增量包下載到本地,再跟本地進行合并,提供一個STK,再合在一起,這就是增量更新。
- 第三是插件管理平臺,要管理每個版本的差異、每個插件最低數據的版本號。
七、JNI中C調用Java方法
http://blog.csdn.net/xyang81/article/details/42582213
第一步:調用FindClass函數,傳入一個Class描述符,JVM會從classpath路徑下搜索該類,并返回jclass類型(用于存儲Class對象的引用)。注意ClassMethod的Class描述符為com/study/jnilearn/ClassMethod,要將.(點)全部換成/(反斜杠);
第二步:調用GetStaticMethodID函數,從ClassMethod類中獲取callStaticMethod方法ID,返回jmethodID類型(用于存儲方法的引用)。實參clazz是第一步找到的jclass對象,實參”callStaticMethod”為方法名稱,實參“(Ljava/lang/String;I)V”為方法的簽名
第三步:調用CallStaticVoidMethod函數,執行ClassMethod.callStaticMethod方法調用。str_arg和100是callStaticMethod方法的實參。
第四步、釋放局部變量
八、以操作系統的角度述說線程與進程
http://blog.csdn.net/luoweifu/article/details/46595285
大部分操作系統(如Windows、Linux)的任務調度是采用時間片輪轉的搶占式調度方式,也就是說一個任務執行一小段時間后強制暫停去執行下一個任務,每個任務輪流執行。任務執行的一小段時間叫做時間片,任務正在執行時的狀態叫運行狀態,任務執行一段時間后強制暫停去執行下一個任務,被暫停的任務就處于就緒狀態等待下一個屬于它的時間片的到來。這樣每個任務都能得到執行,由于CPU的執行效率非常高,時間片非常短,在各個任務之間快速地切換,給人的感覺就是多個任務在“同時進行”,這也就是我們所說的并發(別覺得并發有多高深,它的實現很復雜,但它的概念很簡單,就是一句話:多個任務同時執行)。
進程
進程是一個具有一定獨立功能的程序在一個數據集上的一次動態執行的過程,是操作系統進行資源分配和調度的一個獨立單位,是應用程序運行的載體。進程是一種抽象的概念,從來沒有統一的標準定義。進程一般由程序、數據集合和進程控制塊三部分組成。
進程具有的特征:
動態性:進程是程序的一次執行過程,是臨時的,有生命期的,是動態產生,動態消亡的;
并發性:任何進程都可以同其他進程一起并發執行;
獨立性:進程是系統進行資源分配和調度的一個獨立單位;
結構性:進程由程序、數據和進程控制塊三部分組成。
線程
線程是程序執行中一個單一的順序控制流程,是程序執行流的最小單元,是處理器調度和分派的基本單位。一個進程可以有一個或多個線程,各個線程之間共享程序的內存空間(也就是所在進程的內存空間)。一個標準的線程由線程ID、當前指令指針(PC)、寄存器和堆棧組成。而進程由內存空間(代碼、數據、進程空間、打開的文件)和一個或多個線程組成。
九、synchronized用法,volatile用法
synchronized是Java中的關鍵字,是一種同步鎖。它修飾的對象有以下幾種:
1. 修飾一個代碼塊,被修飾的代碼塊稱為同步語句塊,其作用的范圍是大括號{}括起來的代碼,作用的對象是調用這個代碼塊的對象;
2. 修飾一個方法,被修飾的方法稱為同步方法,其作用的范圍是整個方法,作用的對象是調用這個方法的對象;
3. 修飾一個靜態的方法,其作用的范圍是整個靜態方法,作用的對象是這個類的所有對象;
4. 修飾一個類,其作用的范圍是synchronized后面括號括起來的部分,作用的對象是這個類的所有對象。
一個線程訪問一個對象中的synchronized(this)同步代碼塊時,其他試圖訪問該對象的線程將被阻塞。誰拿到那個鎖誰就可以運行它所控制的那段代碼。
修飾方法范圍是整個函數。
public synchronized void method()
{
// todo
}
public void method()
{
synchronized(this) {
// todo
}
}
寫法一修飾的是一個方法,寫法二修飾的是一個代碼塊,但寫法一與寫法二是等價的,都是鎖定了整個方法時的內容。
A. 無論synchronized關鍵字加在方法上還是對象上,如果它作用的對象是非靜態的,則它取得的鎖是對象;如果synchronized作用的對象是一個靜態方法或一個類,則它取得的鎖是對類,該類所有的對象同一把鎖。
B. 每個對象只有一個鎖(lock)與之相關聯,誰拿到這個鎖誰就可以運行它所控制的那段代碼。
C. 實現同步是要很大的系統開銷作為代價的,甚至可能造成死鎖,所以盡量避免無謂的同步控制。
Java中Volatile關鍵字詳解
http://www.cnblogs.com/zhengbin/p/6407137.html
Java 內存模型中的可見性、原子性和有序性。
- 可見性,是指線程之間的可見性,一個線程修改的狀態對另一個線程是可見的。也就是一個線程修改的結果。另一個線程馬上就能看到。比如:用volatile修飾的變量,就會具有可見性。volatile修飾的變量不允許線程內部緩存和重排序,即直接修改內存。所以對其他線程是可見的。但是這里需要注意一個問題,volatile只能讓被他修飾內容具有可見性,但不能保證它具有原子性。比如 volatile int a = 0;之后有一個操作 a++;這個變量a具有可見性,但是a++ 依然是一個非原子操作,也就是這個操作同樣存在線程安全問題。volatile、synchronized 和 final 實現可見性。
- 原子是世界上的最小單位,具有不可分割性。比如 a=0;(a非long和double類型) 這個操作是不可分割的,那么我們說這個操作時原子操作。再比如:a++; 這個操作實際是a = a + 1;是可分割的,所以他不是一個原子操作。非原子操作都會存在線程安全問題,需要我們使用同步技術(sychronized)來讓它變成一個原子操作。一個操作是原子操作,那么我們稱它具有原子性。java的concurrent包下提供了一些原子類,我們可以通過閱讀API來了解這些原子類的用法。比如:AtomicInteger、AtomicLong、AtomicReference等。 synchronized 和在 lock、unlock 中操作保證原子性。
- volatile 和 synchronized 兩個關鍵字來保證線程之間操作的有序性,volatile 是因為其本身包含“禁止指令重排序”的語義,synchronized 是由“一個變量在同一個時刻只允許一條線程對其進行 lock 操作”這條規則獲得的,此規則決定了持有同一個對象鎖的兩個同步塊只能串行執行。
Volatile原理
- 用來確保將變量的更新操作通知到其他線程。當把變量聲明為volatile類型后,編譯器與運行時都會注意到這個變量是共享的,因此不會將該變量上的操作與其他內存操作一起重排序。volatile變量不會被緩存在寄存器或者對其他處理器不可見的地方,因此在讀取volatile類型的變量時總會返回最新寫入的值。
- 在訪問volatile變量時不會執行加鎖操作,因此也就不會使執行線程阻塞,因此volatile變量是一種比sychronized關鍵字更輕量級的同步機制。
- 聲明變量是 volatile 的,JVM 保證了每次讀變量都從內存中讀,跳過 CPU cache 這一步。
- volatile 的讀性能消耗與普通變量幾乎相同,但是寫操作稍慢,因為它需要在本地代碼中插入許多內存屏障指令來保證處理器不發生亂序執行。
http://www.cnblogs.com/zhengbin/category/787240.html
十、網絡請求緩存處理
HTTP請求信息由3部分組成:
l 請求方法URI協議/版本
l 請求頭(Request Header)
l 請求正文
HTTP響應
HTTP應答與HTTP請求相似,HTTP響應也由3個部分構成,分別是:
l 狀態行
l 響應頭(Response Header)
l 響應正文
在接收和解釋請求消息后,服務器會返回一個HTTP響應消息。
狀態行由協議版本、數字形式的狀態代碼、及相應的狀態描述,各元素之間以空格分隔。
格式: HTTP-Version Status-Code Reason-Phrase CRLF
詳細解讀LruCache類
http://www.cnblogs.com/tianzhijiexian/p/4248677.html
緩存處理可以把請求到的結果寫到一定大小的內存緩存中,可以使用L ruCache 也可以自己實現最近最少使用算法,將文件存入LinkedHashMap (加同步鎖)或者Collections.synchronizedMap(new HashMap
okhttp如何處理網絡緩存的
十一、動態權限適配方案,權限組的概念
http://blog.csdn.net/xc765926174/article/details/49103483
十二、圖片加載庫相關
Glide 與Picasso 對比
https://inthecheesefactory.com/blog/get-to-know-glide-recommended-by-google/en
https://www.zhihu.com/question/40028112
bitmap如何處理大圖,如一張30M的大圖,如何預防OOM
http://blog.csdn.net/hello_12413/article/details/48261503
讀取Bitmap尺寸和類型,設置inJustDecodeBounds 為true,解碼的時候會避免內存的分配,返回的bitmap對象為空,但是卻可以得到 outWidth, outHeight 和outMimeType。
加載一個按比例縮小版本到內存中
告訴解碼器對Image進行采樣,加載一個較小版本圖片到內存中,設置BitmapFactory.Options 對象inSampleSize為true。比如一個2048*1536密度的圖片,inSampleSize為4生成的樣品圖就是512*384。
設置inJustDecodeBounds = true,然后通過新的inSampleSize解碼,最后設置inJustDecodeBounds = false。
Android bitmap圖片處理
http://www.cnblogs.com/an-ly/p/5333622.html
十三 、進程保活
http://blog.csdn.net/u013263323/article/details/56285475
空進程都被殺光了,現在要殺后臺進程,進程是有它的優先級的,這個優先級通過進程的adj值來反映,它是linux內核分配給每個系統進程的一個值,代表進程的優先級,進程回收機制就是根據這個優先級來決定是否進行回收,adj值定義在com.android.server.am.ProcessList類中,這個類路徑是${android-sdk-path}\sources\android-23\com\android\server\am\ProcessList.java。oom_adj的值越小,進程的優先級越高,普通進程oom_adj值是大于等于0的,而系統進程oom_adj的值是小于0的,我們可以通過cat /proc/進程id/oom_adj可以看到當前進程的adj值。
oom_adj越大,占用物理內存越多會被最先kill掉,OK,那么現在對于進程如何保活這個問題就轉化成,如何降低oom_adj的值,以及如何使得我們應用占的內存最少。
一、進程保活方案
1、開啟一個像素的Activity
據說這個是手Q的進程保活方案,基本思想,系統一般是不會殺死前臺進程的。所以要使得進程常駐,我們只需要在鎖屏的時候在本進程開啟一個Activity,為了欺騙用戶,讓這個Activity的大小是1像素,并且透明無切換動畫,在開屏幕的時候,把這個Activity關閉掉,所以這個就需要監聽系統鎖屏廣播,
在屏幕關閉的時候把LiveActivity啟動起來,在開屏的時候把LiveActivity 關閉掉,所以要監聽系統鎖屏廣播,以接口的形式通知MainActivity啟動或者關閉LiveActivity。
但是還有一個問題,內存也是一個考慮的因素,內存越多會被最先kill掉,所以把上面的業務邏輯放到Service中,而Service是在另外一個 進程中,在MainActivity開啟這個服務就行了,這樣這個進程就更加的輕量,通過上面的操作,我們的應用就始終和前臺進程是一樣的優先級了,為了省電,系統檢測到鎖屏事件后一段時間內會殺死后臺進程,如果采取這種方案,就可以避免了這個問題。但是還是有被殺掉的可能,所以我們還需要做雙進程守護,關于雙進程守護,比較適合的就是aidl的那種方式,但是這個不是完全的靠譜,原理是A進程死的時候,B還在活著,B可以將A進程拉起來,反之,B進程死的時候,A還活著,A可以將B拉起來。所以雙進程守護的前提是,系統殺進程只能一個個的去殺,如果一次性殺兩個,這種方法也是不OK的。
2、前臺服務
原理如下
對于 API level < 18 :調用startForeground(ID, new Notification()),發送空的Notification ,圖標則不會顯示。
對于 API level >= 18:在需要提優先級的service A啟動一個InnerService,兩個服務同時startForeground,且綁定同樣的 ID。Stop 掉InnerService ,這樣通知欄圖標即被移除。
3、相互喚醒
假如你手機里裝了支付寶、淘寶、天貓、UC等阿里系的app,那么你打開任意一個阿里系的app后,有可能就順便把其他阿里系的app給喚醒了。
4、JobSheduler
JobSheduler是作為進程死后復活的一種手段,native進程方式最大缺點是費電, Native 進程費電的原因是感知主進程是否存活有兩種實現方式,在 Native 進程中通過死循環或定時器,輪訓判斷主進程是否存活,當主進程不存活時進行拉活。其次5.0以上系統不支持。 但是JobSheduler可以替代在Android5.0以上native進程方式,這種方式即使用戶強制關閉,也能被拉起來
5、粘性服務&與系統服務捆綁
這個是系統自帶的,onStartCommand方法必須具有一個整形的返回值,這個整形的返回值用來告訴系統在服務啟動完畢后,如果被Kill,系統將如何操作,這種方案雖然可以,但是在某些情況or某些定制ROM上可能失效,我認為可以多做一種保保守方案。
NotificationListenerService,NotificationListenerService就是一個監聽通知的服務,只要手機收到了通知,NotificationListenerService都能監聽到,即時用戶把進程殺死,也能重啟
十四、listview圖片加載錯亂的原理和解決方案
產生圖片錯位的原理:
如果我們只是簡單顯示list中數據,而沒用convertview的復用機制和異步操作,就不會產生圖片錯位;重用convertview但沒用異步,也不會有錯位現象。但我們的項目中list一般都會用,不然會很卡。
我們能看到listview中整屏剛好顯示7個item,當向下滑動時,顯示出item8,而item8是重用的item1,如果此時異步網絡請求item8的圖片,比item1的圖片慢,那么item8就會顯示item1的image。當item8下載完成,此時用戶向上滑顯示item1時,又復用了item8的image,這樣就導致了圖片錯位現象(item1和item8是用的同一塊內存哦)
解決方法:
對imageview設置tag,并預設一張圖片。
向下滑動后,item8顯示,item1隱藏。但由于item1是第一次進來就顯示,所以一般情況下,item1都會比item8先下載完,但由于此時可見的item8的tag,和隱藏了的item1的url不匹配,所以就算item1的圖片下載完也不會顯示到item8中,因為tag標識的永遠是可見圖片中的url。
// 給 ImageView 設置一個 tag
holder.img.setTag(imgUrl);
// 預設一個圖片
holder.img.setImageResource(R.drawable.ic_launcher);
// 通過 tag 來防止圖片錯位
if (imageView.getTag() != null && imageView.getTag().equals(imageUrl)) {
imageView.setImageBitmap(result);
}
Android ListView異步加載圖片亂序問題,原因分析及解決方案
http://blog.csdn.net/guolin_blog/article/details/45586553
ListView在借助RecycleBin機制的幫助下,實現了一個生產者和消費者的模式,不管有任意多條數據需要顯示,ListView中的子View其實來來回回就那么幾個,移出屏幕的子View會很快被移入屏幕的數據重新利用起來。
ImageView控件的個數其實就比一屏能顯示的圖片數量稍微多一點而已,移出屏幕的ImageView控件會進入到RecycleBin當中,而新進入屏幕的元素則會從RecycleBin中獲取ImageView控件。
每當有新的元素進入界面時就會回調getView()方法,而在getView()方法中會開啟異步請求從網絡上獲取圖片,注意網絡操作都是比較耗時的,也就是說當我們快速滑動ListView的時候就很有可能出現這樣一種情況,某一個位置上的元素進入屏幕后開始從網絡上請求圖片,但是還沒等圖片下載完成,它就又被移出了屏幕。這種情況下會產生什么樣的現象呢?根據ListView的工作原理,被移出屏幕的控件將會很快被新進入屏幕的元素重新利用起來,而如果在這個時候剛好前面發起的圖片請求有了響應,就會將剛才位置上的圖片顯示到當前位置上,因為雖然它們位置不同,但都是共用的同一個ImageView實例,這樣就出現了圖片亂序的情況。
但是還沒完,新進入屏幕的元素它也會發起一條網絡請求來獲取當前位置的圖片,等到圖片下載完的時候會設置到同樣的ImageView上面,因此就會出現先顯示一張圖片,然后又變成了另外一張圖片的情況,那么剛才我們看到的圖片會自動變來變去的情況也就得到了解釋。
解決方案一 使用findViewWithTag
定義一個全局變量mListView,然后在getView()方法中判斷它是否為空,如果為空就把parent這個參數賦值給它。在getView()方法中我們還做了一個操作,就是調用了ImageView的setTag()方法,并把當前位置圖片的URL地址作為參數傳了進去,這個是為后續的findViewWithTag()方法做準備。異步下載成功后,ListView的findVIewWithTag()方法來去獲取ImageView控件的實例。
解決方案二 使用弱引用關聯
ImageView和BitmapWorkerTask之間建立一個雙向關聯,互相持有對方的引用,再通過適當的邏輯判斷來解決圖片亂序問題,然后為了防止出現內存泄漏的情況,雙向關聯要使用弱引用的方式建立。相比于第一種解決方案,第二種解決方案要明顯復雜不少,但在性能和效率方面都會有更好的表現。
cancelPotentialWork()取消掉后臺的潛在任務,當認為當前ImageView存在著一個另外圖片請求任務時 ,則把它取消掉并返回true,否則返回false。
這個雙向弱引用關聯是怎么建立的。BitmapWorkerTask指向ImageView的弱引用關聯比較簡單,就是在BitmapWorkerTask中加入一個構造函數,并在構造函數中要求傳入ImageView這個參數。不過我們不再直接持有ImageView的引用,而是使用WeakReference對ImageView進行了一層包裝
解決方案三 使用NetworkImageView
NetworkImageView是Volley當中提供的控件不需要自己再去寫一個BitmapWorkerTask來處理圖片的下載和顯示,也不需要自己再去管理LruCache的邏輯,一切NetworkImageView都幫我們做好了。調用cancelRequest()方法把請求取消掉就可以了,這主要是得益于Volley的出色設計。Volley只是保證取消掉的請求不會進行回調而已,但并沒有說可以中斷任何請求。由此可見即使是Volley也無法做到中斷一個正在執行的線程,如果有一個線程正在執行,Volley只會保證在它執行完之后不會進行回調,但在調用者看來,就好像是這個請求就被取消掉了一樣。
十五、https相關,如何驗證證書的合法性,https中哪里用了對稱加密,哪里用了非對稱加密,對加密算法(如RSA)等是否有了解
RSA性能是非常低的,原因在于尋找大素數、大數計算、數據分割需要耗費很多的CPU周期,所以一般的HTTPS連接只在第一次握手時使用非對稱加密,
(之前步驟的1-4)通過握手交換對稱加密密鑰(之前步驟的5-6),在之后的通信走對稱加密(之前步驟的7-8)。
客戶端發起HTTPS請求
用戶在瀏覽器里輸入一個https網址,然后連接到server的443端口。
服務端的配置
采用HTTPS協議的服務器必須要有一套數字證書,可以自己制作,也可以向組織申請。區別就是自己頒發的證書需要客戶端驗證通過,才可以繼續訪問,而使用受信任的公司申請的證書則不會彈出提示頁面(startssl就是個不錯的選擇,有1年的免費服務)。這套證書其實就是非對稱加密中的公鑰和私鑰。
傳送證書
下發的證書其實就是公鑰,只是包含了很多信息,如證書的頒發機構,過期時間等等。
客戶端解析證書
這部分工作是由客戶端的TLS來完成的,首先會驗證公鑰是否有效,比如頒發機構,過期時間等等,如果發現異常,則會彈出一個警告框,提示證書存在問題。如果證書沒有問題,那么就生成一個隨即值(后續對稱加密中用的私匙)然后用證書(客戶端下發的公匙)對該隨機值(客戶端生成的私匙)進行加密。
傳送加密信息
傳送的是用證書加密后的隨機值(客戶端私匙),目的就是讓服務端得到客戶端生成的私匙,以后客戶端和服務端的通信就可以走對稱加密流程了,也就是通過這個客戶端產生的私匙來進行加密解密了。
服務段解密信息
服務端用私鑰(這個是第2步中和公匙對應的非對稱加密的私匙)解密后,得到了客戶端傳過來的隨機值(對稱加密的私鑰),然后把內容通過該值進行對稱加密。所謂對稱加密就是,將信息和私鑰通過某種算法混合在一起,這樣除非知道私鑰,不然無法獲取內容,而正好客戶端和服務端都知道這個私鑰,所以只要加密算法夠彪悍,私鑰夠復雜,數據就夠安全。
傳輸加密后的信息
這部分信息是服務段用對稱加密私鑰加密后的信息,可以在客戶端被還原
客戶端解密信息
客戶端用之前生成的私鑰解密服務段傳過來的信息,于是獲取了解密后的內容。整個過程第三方即使監聽到了數據,也束手無策。
https相關,如何驗證證書的合法性
客戶端內置真正的公鑰,當代理服務器把它自己的證書傳過來的時候,客戶端用內置的公鑰去解密證書中的簽名,因為不是真正的私鑰加密的所以解密失敗,校驗也就失敗,連接中斷。
try {//載入證書SSLSocketFactory factory = setCertificates(getAssets().open("https.cer"));if (factory != null) {httpClientBuilder.sslSocketFactory(factory);}} catch (IOException e) {e.printStackTrace();} /*** 載入證書*/private SSLSocketFactory setCertificates(InputStream... certificates) {try {CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());keyStore.load(null);int index = 0;for (InputStream certificate : certificates) {String certificateAlias = Integer.toString(index++);keyStore.setCertificateEntry(certificateAlias, certificateFactory.generateCertificate(certificate));try {if (certificate != null) {certificate.close();}} catch (IOException e) {e.printStackTrace();}}SSLContext sslContext = SSLContext.getInstance("TLS");TrustManagerFactory trustManagerFactory =TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());trustManagerFactory.init(keyStore);sslContext.init(null,trustManagerFactory.getTrustManagers(),new SecureRandom());return sslContext.getSocketFactory();} catch (Exception e) {e.printStackTrace();return null;}}十六、APK 瘦身
http://blog.csdn.net/mynameishuangshuai/article/details/51752832
http://blog.csdn.net/mynameishuangshuai/article/details/51766185
http://www.cnblogs.com/qianxudetianxia/p/5230154.html
圖片資源瘦身
項目結構瘦身
代碼瘦身
總結
以上是生活随笔為你收集整理的Android面试题总结(三)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 转载:流形学习
- 下一篇: LeetCode数据库SQL题目记录(难