Android基本知識

1、Android的Handler運行機制

1. Message

Message消息,理解為線程間交流的信息,處理數(shù)據(jù)后臺線程需要更新UI,則發(fā)送Message內(nèi)含一些數(shù)據(jù)給UI線程。

2. Handler

Handler處理者,是Message的主要處理者,負責Message的發(fā)送,Message內(nèi)容的執(zhí)行處理。后臺線程就是通過傳進來的 Handler對象引用來sendMessage(Message)。而使用Handler,需要implement 該類的 handleMessage(Message)方法,它是處理這些Message的操作內(nèi)容,例如Update UI。通常需要子類化Handler來實現(xiàn)handleMessage方法。

3. Message Queue

Message Queue消息隊列,用來存放通過Handler發(fā)布的消息,按照先進先出執(zhí)行。

在單線程模型下,為了線程通信問題,Android設(shè)計了一個Message Queue(消息隊列), 線程間可以通過該Message Queue并結(jié)合Handler和Looper組件進行信息交換。

每個message queue都會有一個對應(yīng)的Handler。Handler會向message queue通過兩種方法發(fā)送消息:sendMessage或post。這兩種消息都會插在message queue隊尾并按先進先出執(zhí)行。但通過這兩種方法發(fā)送的消息執(zhí)行的方式略有不同:通過sendMessage發(fā)送的是一個message對象,會被 Handler的handleMessage()函數(shù)處理;而通過post方法發(fā)送的是一個runnable對象,則會自己執(zhí)行。

4. Looper

Looper是每條線程里的Message Queue的管家。Android沒有Global的Message Queue,而Android會自動替主線程(UI線程)建立Message Queue,但在子線程里并沒有建立Message Queue。所以調(diào)用Looper.getMainLooper()得到的主線程的Looper不為NULL,但調(diào)用Looper.myLooper() 得到當前線程的Looper就有可能為NULL。


2、面向?qū)ο蟮奶卣?/b>

對象唯一性。

每個對象都有自身唯一的標識,通過這種標識,可找到相應(yīng)的對象。在對象的整個生命期中,它的標識都不改變,不同的對象不能有相同的標識。?[2]

抽象性。

抽象性是指將具有一致的數(shù)據(jù)結(jié)構(gòu)(屬性)和行為(操作)的對象抽象成類。一個類就是這樣一種抽象,它反映了與應(yīng)用有關(guān)的重要性質(zhì),而忽略其他一些無關(guān)內(nèi)容。任何類的劃分都是主觀的,但必須與具體的應(yīng)用有關(guān)。?[2]

繼承性

繼承性是子類自動共享父類數(shù)據(jù)結(jié)構(gòu)和方法的機制,這是類之間的一種關(guān)系。在定義和實現(xiàn)一個類的時候,可以在一個已經(jīng)存在的類的基礎(chǔ)之上來進行,把這個已經(jīng)存在的類所定義的內(nèi)容作為自己的內(nèi)容,并加入若干新的內(nèi)容。?[2]

繼承性是面向?qū)ο蟪绦蛟O(shè)計語言不同于其它語言的最重要的特點,是其他語言所沒有的。

在類層次中,子類只繼承一個父類的數(shù)據(jù)結(jié)構(gòu)和方法,則稱為單重繼承。

在類層次中,子類繼承了多個父類的數(shù)據(jù)結(jié)構(gòu)和方法,則稱為多重繼承。

多重繼承,JAVA、VB、NET、Objective-C均僅支持單繼承,注意在C++多重繼承時,需小心二義性。

軟件開發(fā)中,類的繼承性使所建立的軟件具有開放性、可擴充性,這是信息組織與分類的行之有效的方法,它簡化了對象、類的創(chuàng)建工作量,增加了代碼的可重用性。

采用繼承性,提供了類的規(guī)范的等級結(jié)構(gòu)。通過類的繼承關(guān)系,使公共的特性能夠共享,提高了軟件的重用性。?[2]

多態(tài)性(多形性)

多態(tài)性是指相同的操作或函數(shù)、過程可作用于多種類型的對象上并獲得不同的結(jié)果。不同的對象,收到同一消息可以產(chǎn)生不同的結(jié)果,這種現(xiàn)象稱為多態(tài)性

多態(tài)性允許每個對象以適合自身的方式去響應(yīng)共同的消息。

多態(tài)性增強了軟件的靈活性和重用性。



3、性能優(yōu)化總結(jié)2:leakcanary的使用(li)

1、引入庫

2、操作APP,分析結(jié)果

3、如果是復(fù)雜的問題可以導(dǎo)出hprof文件到android studio 中繼續(xù)分析

我們啟動app,當檢測到內(nèi)存泄漏的時候,會出現(xiàn)一個彈窗,然后手機桌面會出現(xiàn)一個Leaks的圖標

點擊即可看到內(nèi)存泄漏的原因:


4、Serializable和Parcelable的區(qū)別

在使用內(nèi)存的時候,Parcelable 類比Serializable性能高,所以推薦使用Parcelable類。

1.Serializable在序列化的時候會產(chǎn)生大量的臨時變量,從而引起頻繁的GC。

2.Parcelable不能使用在要將數(shù)據(jù)存儲在磁盤上的情況。盡管Serializable效率低點,但在這種情況下,還是建議你用Serializable 。

實現(xiàn):

1.Serializable 的實現(xiàn),只需要繼承 Serializable 即可。這只是給對象打了一個標記,系統(tǒng)會自動將其序列化。

2.Parcelabel 的實現(xiàn),需要在類中添加一個靜態(tài)成員變量 CREATOR,這個變量需要繼承Parcelable.Creator 接口。

public class MyParcelable implements Parcelable {

? ? private int mData;

? ? public int describeContents() {

? ? ? ? return 0;

? ? }

? ? public void writeToParcel(Parcel out, int flags) {

? ? ? ? out.writeInt(mData);

? ? }

? ? public static final Parcelable.Creator<MyParcelable> CREATOR = new Parcelable.Creator<MyParcelable>() {

? ? ? ? public MyParcelable createFromParcel(Parcel in) {

? ? ? ? ? ? return new MyParcelable(in);

? ? ? ? }

? ? ? ? public MyParcelable[] newArray(int size) {

? ? ? ? ? ? return new MyParcelable[size];

? ? ? ? }

? ? };

? ? private MyParcelable(Parcel in) {

? ? ? ? mData = in.readInt();

? ? }

}

5,什么是內(nèi)存泄漏,android在什么情況下容易產(chǎn)生內(nèi)存泄漏

說到內(nèi)存泄漏就不得不提內(nèi)存溢出。

內(nèi)存溢出 out of memory,是指程序在申請內(nèi)存時,沒有足夠的內(nèi)存空間供其使用,出現(xiàn)out of memory;比如申請了一個integer,但給它存了long才能存下的數(shù),那就是內(nèi)存溢出。

內(nèi)存泄露 memory leak,是指程序在申請內(nèi)存后,無法釋放已申請的內(nèi)存空間,一次內(nèi)存泄露危害可以忽略,但內(nèi)存泄露堆積后果很嚴重。內(nèi)存溢出導(dǎo)致了內(nèi)存泄漏。

在Android中常見的內(nèi)存泄漏原因:

1. 資源釋放問題

程序代碼的問題,長期保持某些資源,如Context、Cursor、IO流的引用,資源得不到釋放造成內(nèi)存泄露。

2. 對象內(nèi)存過大問題

保存了多個耗用內(nèi)存過大的對象(如Bitmap、XML文件),造成內(nèi)存超出限制。

3. static關(guān)鍵字的使用問題

static是Java中的一個關(guān)鍵字,當用它來修飾成員變量時,那么該變量就屬于該類,而不是該類的實例。所以用static修飾的變量,它的生命周期是很長的,如果用它來引用一些資源耗費過多的實例(Context的情況最多),這時就要謹慎對待了。

4. 線程導(dǎo)致內(nèi)存溢出

線程產(chǎn)生內(nèi)存泄露的主要原因在于線程生命周期的不可控。

5,數(shù)據(jù)庫游標忘記回收等

那么針對上面的問題我們怎么避免呢

1)圖片過大導(dǎo)致OOM

Android 中用bitmap時很容易內(nèi)存溢出,比如報如下錯誤:Java.lang.OutOfMemoryError :

bitmap size exceeds VM budget。

解決方法:

方法1: 等比例縮小圖片

方法2:對圖片采用軟引用,及時地進行recyle()操作

SoftReference<Bitmap> bitmap = new SoftReference<Bitmap>(pBitmap);

2)查詢數(shù)據(jù)庫沒有關(guān)閉游標

程序中經(jīng)常會進行查詢數(shù)據(jù)庫的操作,但是經(jīng)常會有使用完畢Cursor后沒有關(guān)閉的情況。如果我們的查詢結(jié)果集比較小,對內(nèi)存的消耗不容易被發(fā)現(xiàn),只有在常時間大量操作的情況下才會出現(xiàn)內(nèi)

存問題,這樣就會給以后的測試和問題排查帶來困難和風險。

3)構(gòu)造Adapter時,沒有使用緩存的 convertView

在使用ListView的時候通常會使用Adapter,那么我們應(yīng)該盡可能的使用ConvertView。為什么要使用convertView?(con what)

當convertView為空時,用setTag()方法為每個View綁定一個存放控件的ViewHolder對象。當 convertView 不為空,重復(fù)利用已經(jīng)創(chuàng)建的 view 的時候,使用 getTag()方法獲取綁定的ViewHolder對象,這樣就避免了findViewById對控件的層層查詢,而是快速定位到控件。

4)Bitmap對象不再使用時調(diào)用recycle()釋放內(nèi)存

有時我們會手工的操作Bitmap對象,如果一個Bitmap對象比較占內(nèi)存,當它不再被使用的時

候,可以調(diào)用Bitmap.recycle()方法回收此對象的像素所占用的內(nèi)存,但這不是必須的,視情況而定。

6、 簡述下Android JNI調(diào)用過程

1)安裝和下載Cygwin,下載AndroidNDK

2)在ndk項目中JNI接口的設(shè)計

3)使用C/C++實現(xiàn)本地方法

4)JNI生成動態(tài)鏈接庫.so文件

5)將動態(tài)鏈接庫復(fù)制到j(luò)ava工程,在java工程中調(diào)用,運行java工程即可


7、插件化、熱修復(fù) 、熱更新的理解

插件化 – apk 分為宿主和插件部分,插件在需要的時候才加載進來

熱修復(fù) – 更新的類或者插件粒度較小的時候,我們會稱之為熱修復(fù),一般用于修復(fù)bug

熱更新 – 2016 Google 的 Android Studio 推出了Instant Run 功能 同時提出了3個名詞

“ 熱部署” – 方法內(nèi)的簡單修改,無需重啟app和Activity。

“暖部署” – app無需重啟,但是activity需要重啟,比如資源的修改。

“冷部署” – app需要重啟,比如繼承關(guān)系的改變或方法的簽名變化等。

站在app開發(fā)者角度的“熱”是指在不發(fā)版的情況來實現(xiàn)更新

而Google提出的“熱”是指值是否需要重新啟動。 - 同時在開發(fā)插件化的時候也有兩種情景

一種是插件與宿主apk沒有交互,只是在用戶使用到的時候進行一次吊起

還有一種是與宿主有很多的交互

你認為android熱更新框架哪個好:

1.阿里的熱更新框架已經(jīng)開源 了。但已經(jīng)很久沒有更新過新版本了。當前的版本只支持到了 Android 4.4。由于 5.0 起新的 ART 虛擬機、更嚴格的 SELinux 策略以及對 64 位的支持之類的事,使得 Xposed 都在開發(fā)上做了很多調(diào)整。我不知道 Dexposed 現(xiàn)在是否支持,但至少阿里沒有開源。

2.在本地動態(tài)執(zhí)行遠端下發(fā)的代碼是極度危險的行為。利用此方法執(zhí)行非法代碼等或用于繞過 Google Play 等市場的審查是違反相關(guān)協(xié)議的,也是對用戶極度不負責任的行為。

3.在一些訪問非常密集的地方使用熱更新可能會對效率產(chǎn)生相對比較大的影響,應(yīng)該避免使用.

4.我們可以對 Java 的 ScriptEngine 進行一些封裝成為一個 HotPatch 類使得它更適合做熱更新的工作。

5.首先,檢查熱更新補丁的管道一定要建立在 https 上,因為下發(fā)代碼是極其危險的,如果被劫持,后果是無法想象的。其次,請求時最好自動帶上 Android 版本、手機型號、地區(qū)、版本號等信息,以方便更精確地下發(fā),千萬不能下發(fā)錯。

6.Java在運行時加載對應(yīng)的類是通過ClassLoader來實現(xiàn)的,ClassLoader本身是一個抽象來,Android中使用PathClassLoader類作為Android的默認的類加載器

7.我們的如果想做hotpatch,一定要保證我們的hotpacth dex文件出現(xiàn)在dexElements列表的前面。

二.常用的熱更新技術(shù)框架:

基于QQ空間的HotFix →→ 要使用到android dex分包方案→拆分dex的項目的話,可以參考一下谷歌的multidex方案實現(xiàn).

大眾點評的NuWa←項目補丁自動化做的很完整

alibaba/AndFix

阿里巴巴的DexPosed

dalvik_patch實現(xiàn)multidex

使用React-Native實現(xiàn)app熱部署的一次實踐

alibaba/AndFix


7、activity生命周期圖解

鎖定屏與解鎖屏幕 只會調(diào)用onPause(),而不會調(diào)用onStop方法,開屏后則調(diào)用onResume()。在實際操作中會有所出入,比如在三星手機測試的時候鎖定手機調(diào)用了onPause()和onStop()方法,解鎖時候調(diào)用的是:onRestart(),onStart()和 onResume()方法。

介紹不同場景下Activity生命周期的變化過程

啟動Activity:

onCreate()—>onStart()—>onResume(),Activity進入運行狀態(tài)。

Activity退居后臺:

當前Activity轉(zhuǎn)到新的Activity界面或按Home鍵回到主屏: onPause()—>onStop(),進入停滯狀態(tài)。

Activity返回前臺:

onRestart()—>onStart()—>onResume(),再次回到運行狀態(tài)。

Activity退居后臺,且系統(tǒng)內(nèi)存不足,

系統(tǒng)會殺死這個后臺狀態(tài)的Activity,若再次回到這個Activity,則會走onCreate()–>onStart()—>onResume()

鎖定屏與解鎖屏幕

只會調(diào)用onPause(),而不會調(diào)用onStop方法,開屏后則調(diào)用onResume()

Activity銷毀但Task如果沒有銷毀掉,當Activity重啟時這個AsyncTask該如何解決?

比如屏幕旋轉(zhuǎn)這個例子,在重建Activity的時候,會回調(diào)

Activity.onRetainNonConfigurationInstance()

重新傳遞一個新的對象給AsyncTask,完成引用的更新

若Activity已經(jīng)銷毀,此時AsynTask執(zhí)行完并返回結(jié)果,會報異常么?

當一個App旋轉(zhuǎn)時,整個Activity會被銷毀和重建。

當Activity重啟時,AsyncTask中對該Activity的引用是無效的,因此onPostExecute()就不會起作用

若AsynTask正在執(zhí)行,折會報 view not attached to window manager 異常

同樣也是生命周期的問題,在 Activity 的onDestory()方法中調(diào)用Asyntask.cancal方法,讓二者的生命周期同步

內(nèi)存不足時,系統(tǒng)會殺死后臺的Activity,如果需要進行一些臨時狀態(tài)的保存,在哪個方法進行

Activity的 onSaveInstanceState() 和 onRestoreInstanceState()并不是生命周期方法,不同于 onCreate()、onPause()等生命周期方法,它們并不一定會被觸發(fā)。

當應(yīng)用遇到意外情況(如:內(nèi)存不足、用戶直接按Home鍵)由系統(tǒng)銷毀一個Activity,onSaveInstanceState() 會被調(diào)用。

但是當用戶主動去銷毀一個Activity時,例如在應(yīng)用中按返回鍵,onSaveInstanceState()就不會被調(diào)用。除非該activity是被用戶主動銷毀的

通常onSaveInstanceState()只適合用于保存一些臨時性的狀態(tài),而onPause()適合用于數(shù)據(jù)的持久化保存。


8、介紹Activity 四中l(wèi)aunchMode:

我們可以在AndroidManifest.xml配置的android:launchMode屬性為以下四種之一。

1、standard

standard模式是默認的啟動模式,不用為配置android:launchMode屬性即可,當然也可以指定值為standard。standard啟動模式,不管有沒有已存在的實例,都生成新的實例。

2、 singleTop

我們在上面的基礎(chǔ)上為指定屬性android:launchMode=”singleTop”,系統(tǒng)就會按照singleTop啟動模式處理跳轉(zhuǎn)行為。跳轉(zhuǎn)時系統(tǒng)會先在棧結(jié)構(gòu)中尋找是否有一個Activity實例正位于棧頂,如果有則不再生成新的,而是直接使用。如果系統(tǒng)發(fā)現(xiàn)存在有Activity實例,但不是位于棧頂,重新生成一個實例。 這就是singleTop啟動模式,如果發(fā)現(xiàn)有對應(yīng)的Activity實例正位于棧頂,則重復(fù)利用,不再生成新的實例。

3、 singleTask

如果發(fā)現(xiàn)有對應(yīng)的Activity實例,則使此Activity實例之上的其他Activity實例統(tǒng)統(tǒng)出棧,使此Activity實例成為棧頂對象,顯示到幕前。

4、singleInstance

這種啟動模式比較特殊,因為它會啟用一個新的棧結(jié)構(gòu),將Acitvity放置于這個新的棧結(jié)構(gòu)中,并保證不再有其他Activity實例進入。

LaunchMode使用場景

singleTop適合接收通知啟動的內(nèi)容顯示頁面。

例如,某個新聞客戶端的新聞內(nèi)容頁面,如果收到10個新聞推送,每次都打開一個新聞內(nèi)容頁面是很煩人的。

singleTask適合作為程序入口點。

例如瀏覽器的主界面。不管從多少個應(yīng)用啟動瀏覽器,只會啟動主界面一次,其余情況都會走onNewIntent,并且會清空主界面上面的其他頁面。

singleInstance應(yīng)用場景:

鬧鈴的響鈴界面。 你以前設(shè)置了一個鬧鈴:上午6點。在上午5點58分,你啟動了鬧鈴設(shè)置界面,并按 Home 鍵回桌面;在上午5點59分時,你在微信和朋友聊天;在6點時,鬧鈴響了,并且彈出了一個對話框形式的 Activity(名為 AlarmAlertActivity) 提示你到6點了(這個 Activity 就是以

SingleInstance

加載模式打開的),你按返回鍵,回到的是微信的聊天界面,這是因為 AlarmAlertActivity 所在的 Task 的棧只有他一個元素, 因此退出之后這個 Task 的??樟?。如果是以 SingleTask 打開 AlarmAlertActivity,那么當鬧鈴響了的時候,按返回鍵應(yīng)該進入鬧鈴設(shè)置界面。


9、Activity啟動Service的兩種方式

startService:生命周期和調(diào)用者不同.啟動后若調(diào)用者未調(diào)用stopService而直接退出,Service仍會運行

bindService:生命周期與調(diào)用者綁定,調(diào)用者一旦退出,Service就會調(diào)用unBind->onDestory


10、Fragment是什么?你曾經(jīng)遇到哪些有關(guān)Fragment的問題?

Fragment可以作為Activity界面的一部分組成出現(xiàn)

其作用是:碎片整理,局部刷新。

一個Activity中可以同時出現(xiàn)多個Fragment,并一個Fragment也可以在多個Activity中使用.在Activity中可以添加,刪除,替換Fragment.Fragment可以響應(yīng)自己的輸入時間,并且有自己的生命周期,但其生命周期受Activity影響.

Fragment生命周期

onAttach():執(zhí)行該方法時,F(xiàn)ragment與Activity已經(jīng)完成綁定,該方法有一個Activity類型的參數(shù),代表綁定的Activity,這時候你可以執(zhí)行諸如mActivity = activity的操作。

onCreate():初始化Fragment??赏ㄟ^參數(shù)savedInstanceState獲取之前保存的值。

onCreateView():初始化Fragment的布局。加載布局和findViewById的操作通常在此函數(shù)內(nèi)完成,但是不建議執(zhí)行耗時的操作,比如讀取數(shù)據(jù)庫數(shù)據(jù)列表。

onActivityCreated():執(zhí)行該方法時,與Fragment綁定的Activity的onCreate方法已經(jīng)執(zhí)行完成并返回,在該方法內(nèi)可以進行與Activity交互的UI操作,所以在該方法之前Activity的onCreate方法并未執(zhí)行完成,如果提前進行交互操作,會引發(fā)空指針異常。

onStart():執(zhí)行該方法時,F(xiàn)ragment由不可見變?yōu)榭梢姞顟B(tài)。

onResume():執(zhí)行該方法時,F(xiàn)ragment處于活動狀態(tài),用戶可與之交互。

onPause():執(zhí)行該方法時,F(xiàn)ragment處于暫停狀態(tài),但依然可見,用戶不能與之交互。

onSaveInstanceState():保存當前Fragment的狀態(tài)。該方法會自動保存Fragment的狀態(tài),比如EditText鍵入的文本,即使Fragment被回收又重新創(chuàng)建,一樣能恢復(fù)EditText之前鍵入的文本。

onStop():執(zhí)行該方法時,F(xiàn)ragment完全不可見。

onDestroyView():銷毀與Fragment有關(guān)的視圖,但未與Activity解除綁定,依然可以通過onCreateView方法重新創(chuàng)建視圖。通常在ViewPager+Fragment的方式下會調(diào)用此方法。

onDestroy():銷毀Fragment。通常按Back鍵退出或者Fragment被回收時調(diào)用此方法。

onDetach():解除與Activity的綁定。在onDestroy方法之后調(diào)用。


11、是否使用過本地廣播,和全局廣播有什么區(qū)別?

本地廣播在本應(yīng)用范圍內(nèi)傳播,不用擔心隱私數(shù)據(jù)泄露,不用擔心別的應(yīng)用偽造廣播.相比全局廣播,本地廣播更高效.

注冊廣播的幾種方法?

1.靜態(tài)注冊:在清單文件中注冊, 常見的有監(jiān)聽設(shè)備啟動,常駐注冊不會隨程序生命周期改變

2.動態(tài)注冊:在代碼中注冊,隨著程序的結(jié)束,也就停止接受廣播了

補充一點:有些廣播只能通過動態(tài)方式注冊,比如時間變化事件、屏幕亮滅事件、電量變更事件,因為這些事件觸發(fā)頻率通常很高,如果允許后臺監(jiān)聽,會導(dǎo)致進程頻繁創(chuàng)建和銷毀,從而影響系統(tǒng)整體性能

為什么Android引入廣播機制?

a:從MVC的角度考慮(應(yīng)用程序內(nèi)) 其實回答這個問題的時候還可以這樣問,android為什么要有那4大組件,現(xiàn)在的移動開發(fā)模型基本上也是照搬的web那一套MVC架構(gòu),只不過是改了點嫁妝而已。

android的四大組件本質(zhì)上就是為了實現(xiàn)移動或者說嵌入式設(shè)備上的MVC架構(gòu)

它們之間有時候是一種相互依存的關(guān)系,有時候又是一種補充關(guān)系,引入廣播機制可以方便幾大組件的信息和數(shù)據(jù)交互。

b:程序間互通消息(例如在自己的應(yīng)用程序內(nèi)監(jiān)聽系統(tǒng)來電)

c:效率上(參考UDP的廣播協(xié)議在局域網(wǎng)的方便性)

d:設(shè)計模式上(反轉(zhuǎn)控制的一種應(yīng)用,類似監(jiān)聽者模式)

12、了解IntentServices嗎?

IntentService是Service的子類,是一個異步的,會自動停止的服務(wù),很好解決了傳統(tǒng)的Service中處理完耗時操作忘記停止并銷毀Service的問題

生成一個默認的且與線程相互獨立的工作線程執(zhí)行所有發(fā)送到onStartCommand()方法的Intent,可以在onHandleIntent()中處理.

串行隊列,每次只運行一個任務(wù),不存在線程安全問題,所有任務(wù)執(zhí)行完后自動停止服務(wù),不需要自己手動調(diào)用stopSelf()來停止.


13、如何提升Service進程優(yōu)先級

在AndroidManifest.xml文件中對于intent-filter可以通過android:priority = “1000”這個屬性設(shè)置最高優(yōu)先級,1000是最高值,如果數(shù)字越小則優(yōu)先級越低,同時適用于廣播。

14、數(shù)據(jù)存儲相關(guān)

ContentProvider的主要還是用于數(shù)據(jù)共享,其可以對Sqlite,SharePreferences,F(xiàn)ile等進行數(shù)據(jù)操作用來共享數(shù)據(jù)。而sql的可以理解為數(shù)據(jù)庫的一門語言,可以使用它完成CRUD等一系列的操作

文件存儲:

通過Java.io.FileInputStream和java.io.FileOutputStream這兩個類來實現(xiàn)對文件的讀寫,java.io.File類則用來構(gòu)造一個具體指向某個文件或者文件夾的對象。

SharedPreferences:

SharedPreferences是一種輕量級的數(shù)據(jù)存儲機制,他將一些簡單的數(shù)據(jù)類型的數(shù)據(jù),包括boolean類型,int類型,float類型,long類型以及String類型的數(shù)據(jù),以鍵值對的形式存儲在應(yīng)用程序的私有Preferences目錄(/data/data/<包名>/shared_prefs/)中,這種Preferences機制廣泛應(yīng)用于存儲應(yīng)用程序中的配置信息。

SQLite數(shù)據(jù)庫:

當應(yīng)用程序需要處理的數(shù)據(jù)量比較大時,為了更加合理地存儲、管理、查詢數(shù)據(jù),我們往往使用關(guān)系數(shù)據(jù)庫來存儲數(shù)據(jù)。Android系統(tǒng)的很多用戶數(shù)據(jù),如聯(lián)系人信息,通話記錄,短信息等,都是存儲在SQLite數(shù)據(jù)庫當中的,所以利用操作SQLite數(shù)據(jù)庫的API可以同樣方便的訪問和修改這些數(shù)據(jù)。

ContentProvider:

主要用于在不同的應(yīng)用程序之間實現(xiàn)數(shù)據(jù)共享的功能,不同于sharepreference和文件存儲中的兩種全局可讀寫操作模式,內(nèi)容提供其可以選擇只對哪一部分數(shù)據(jù)進行共享,從而保證我們程序中的隱私數(shù)據(jù)不會有泄漏的風險

如何將打開res aw目錄中的數(shù)據(jù)庫文件?

復(fù)制的基本方法是使用getResources().openRawResource方法獲得res aw目錄中資源的 InputStream對象,然后將該InputStream對象中的數(shù)據(jù)寫入其他的目錄中相應(yīng)文件中。

在Android SDK中可以使用SQLiteDatabase.openOrCreateDatabase方法來打開任意目錄中的SQLite數(shù)據(jù)庫文件。


15、如何將SQLite數(shù)據(jù)庫(dictionary.db文件)與apk文件一起發(fā)布?

可以將dictionary.db文件復(fù)制到Eclipse Android工程中的res aw目錄中。所有在res aw目錄中的文件不會被壓縮,這樣可以直接提取該目錄中的文件??梢詫ictionary.db文件復(fù)制到res -> raw目錄中


16、如何保證Service在后臺不被kill

Service設(shè)置成START_STICKY kill 后會被重啟(等待5秒左右),重傳Intent,保持與重啟前一樣

通過 startForeground將進程設(shè)置為前臺進程, 做前臺服務(wù),優(yōu)先級和前臺應(yīng)用一個級別?,除非在系統(tǒng)內(nèi)存非常缺,否則此進程不會被 kill

雙進程Service: 讓2個進程互相保護**,其中一個Service被清理后,另外沒被清理的進程可以立即重啟進程

QQ黑科技: 在應(yīng)用退到后臺后,另起一個只有 1 像素的頁面停留在桌面上,讓自己保持前臺狀態(tài),保護自己不被后臺清理工具殺死

在已經(jīng)root的設(shè)備下,修改相應(yīng)的權(quán)限文件,將App偽裝成系統(tǒng)級的應(yīng)用 Android4.0系列的一個漏洞,已經(jīng)確認可行

用C編寫守護進程(即子進程) : Android系統(tǒng)中當前進程(Process)fork出來的子進程,被系統(tǒng)認為是兩個不同的進程。當父進程被殺死的時候,子進程仍然可以存活,并不受影響。*鑒于目前提到的在Android->- Service層做雙守護都會失敗*,我們可以fork出c進程,多進程守護。死循環(huán)在那檢查是否還存在,具體的思路如下(Android5.0以上的版本不可行)

用C編寫守護進程(即子進程),守護進程做的事情就是循環(huán)檢查目標進程是否存在,不存在則啟動它。

在NDK環(huán)境中將1中編寫的C代碼編譯打包成可執(zhí)行文件(BUILD_EXECUTABLE)。主進程啟動時將守護進程放入私有目錄下,賦予可執(zhí)行權(quán)限,啟動它即可。

聯(lián)系廠商,加入白名單


17、mipmap文件夾和drawable文件夾的區(qū)別

它只是用來放啟動圖標的,好處就是,你只用放一個mipmap圖標,它就會給你各種版本(比如平板,手機)的apk自動生成相應(yīng)分辨率的圖標,以節(jié)約空間。


18、ListView卡頓的原因以及優(yōu)化策略

重用converView: 通過復(fù)用converview來減少不必要的view的創(chuàng)建,另外Infalte操作會把xml文件實例化成相應(yīng)的View實例,屬于IO操作,是耗時操作。

減少findViewById()操作: 將xml文件中的元素封裝成viewholder靜態(tài)類,通過converview的setTag和getTag方法將view與相應(yīng)的holder對象綁定在一起,避免不必要的findviewbyid操作

避免在 getView 方法中做耗時的操作: 例如加載本地 Image 需要載入內(nèi)存以及解析 Bitmap ,都是比較耗時的操作,如果用戶快速滑動listview,會因為getview邏輯過于復(fù)雜耗時而造成滑動卡頓現(xiàn)象。用戶滑動時候不要加載圖片,待滑動完成再加載,可以使用這個第三方庫glide

Item的布局層次結(jié)構(gòu)盡量簡單,避免布局太深或者不必要的重繪

盡量能保證 Adapter 的 hasStableIds() 返回 true 這樣在 notifyDataSetChanged() 的時候,如果item內(nèi)容并沒有變化,ListView 將不會重新繪制這個 View,達到優(yōu)化的目的

在一些場景中,ScollView內(nèi)會包含多個ListView,可以把listview的高度寫死固定下來。 由于ScollView在快速滑動過程中需要大量計算每一個listview的高度,阻塞了UI線程導(dǎo)致卡頓現(xiàn)象出現(xiàn),如果我們每一個item的高度都是均勻的,可以通過計算把listview的高度確定下來,避免卡頓現(xiàn)象出現(xiàn)

使用 RecycleView 代替listview: 每個item內(nèi)容的變動,listview都需要去調(diào)用notifyDataSetChanged來更新全部的item,太浪費性能了。RecycleView可以實現(xiàn)當個item的局部刷新,并且引入了增加和刪除的動態(tài)效果,在性能上和定制上都有很大的改善

ListView 中元素避免半透明: 半透明繪制需要大量乘法計算,在滑動時不停重繪會造成大量的計算,在比較差的機子上會比較卡。 在設(shè)計上能不半透明就不不半透明。實在要弄就把在滑動的時候把半透明設(shè)置成不透明,滑動完再重新設(shè)置成半透明。

盡量開啟硬件加速: 硬件加速提升巨大,避免使用一些不支持的函數(shù)導(dǎo)致含淚關(guān)閉某個地方的硬件加速。當然這一條不只是對 ListView。

ViewHolder為什么要被聲明成靜態(tài)內(nèi)部類

這個是考靜態(tài)內(nèi)部類和非靜態(tài)內(nèi)部類的主要區(qū)別之一。非靜態(tài)內(nèi)部類會隱式持有外部類的引用,就像大家經(jīng)常將自定義的adapter在Activity類里,然后在adapter類里面是可以隨意調(diào)用外部activity的方法的。

當你將內(nèi)部類定義為static時,你就調(diào)用不了外部類的實例方法了,因為這時候靜態(tài)內(nèi)部類是不持有外部類的引用的。聲明ViewHolder靜態(tài)內(nèi)部類,可以將ViewHolder和外部類解引用。

大家會說一般ViewHolder都很簡單,不定義為static也沒事吧。確實如此,但是如果你將它定義為static的,說明你懂這些含義。萬一有一天你在這個ViewHolder加入一些復(fù)雜邏輯,做了一些耗時工作,那么如果ViewHolder是非靜態(tài)內(nèi)部類的話,就很容易出現(xiàn)內(nèi)存泄露。

如果是靜態(tài)的話,你就不能直接引用外部類,迫使你關(guān)注如何避免相互引用。 所以將 ViewHolder內(nèi)部類 定義為靜態(tài)的,是一種好習慣


19、Android中的動畫有哪些?

逐幀動畫(Drawable Animation):

加載一系列Drawable資源來創(chuàng)建動畫,簡單來說就是播放一系列的圖片來實現(xiàn)動畫效果,可以自定義每張圖片的持續(xù)時間

補間動畫(Tween Animation):

Tween可以對View對象實現(xiàn)一系列簡單的動畫效果,比如位移,縮放,旋轉(zhuǎn),透明度等等。但是它并不會改變View屬性的值,只是改變了View的繪制的位置,比如,一個按鈕在動畫過后,不在原來的位置,但是觸發(fā)點擊事件的仍然是原來的坐標。

屬性動畫(Property Animation):

動畫的對象除了傳統(tǒng)的View對象,還可以是Object對象,動畫結(jié)束后,Object對象的屬性值被實實在在的改變了

Android動畫原理

Animation框架定義了透明度,旋轉(zhuǎn),縮放和位移幾種常見的動畫,而且控制的是整個View

實現(xiàn)原理是每次繪制視圖時View所在的ViewGroup中的drawChild函數(shù)獲取該View的Animation的Transformation值

然后調(diào)用canvas.concat(transformToApply.getMatrix()),通過矩陣運算完成動畫幀,如果動畫沒有完成,繼續(xù)調(diào)用invalidate()函數(shù),啟動下次繪制來驅(qū)動動畫

動畫過程中的幀之間間隙時間是繪制函數(shù)所消耗的時間,可能會導(dǎo)致動畫消耗比較多的CPU資源,最重要的是,動畫改變的只是顯示,并不能相應(yīng)事件


20、View繪制相關(guān)

SurfaceView和View的區(qū)別

SurfaceView中采用了雙緩存技術(shù),在單獨的線程中更新界面

View在UI線程中更新界面

介紹下自定義view的基本流程

1、 明確需求,確定你想實現(xiàn)的效果

2、確定是使用組合控件的形式還是全新自定義的形式,組合控件即使用多個系統(tǒng)控件來合成一個新控件,你比如titilebar,這種形式相對簡單,參考

3、如果是完全自定義一個view的話,你首先需要考慮繼承哪個類,是View呢,還是ImageView等子類。

4、根據(jù)需要去復(fù)寫View#onDraw、View#onMeasure、View#onLayout方法

5.根據(jù)需要去復(fù)寫dispatchTouchEvent、onTouchEvent方法

6、根據(jù)需要為你的自定義view提供自定義屬性,即編寫attr.xml,然后在代碼中通過TypedArray等類獲取到自定義屬性值

7、需要處理滑動沖突、像素轉(zhuǎn)換等問題


21、談?wù)刅iew的繪制流程

measure()方法,layout(),draw()三個方法主要存放了一些標識符,來判斷每個View是否需要再重新測量,布局或者繪制,主要的繪制過程還是在onMeasure,onLayout,onDraw這個三個方法中

1.onMesarue() 為整個View樹計算實際的大小,即設(shè)置實際的高(對應(yīng)屬性:mMeasuredHeight)和寬(對應(yīng)屬性: mMeasureWidth),每個View的控件的實際寬高都是由父視圖和本身視圖決定的。

2.onLayout() 為將整個根據(jù)子視圖的大小以及布局參數(shù)將View樹放到合適的位置上。

3.onDraw() 開始繪制圖像,繪制的流程如下

首先繪制該View的背景

調(diào)用onDraw()方法繪制視圖本身 (每個View都需要重載該方法,ViewGroup不需要實現(xiàn)該方法)

如果該View是ViewGroup,調(diào)用dispatchDraw ()方法繪制子視圖

繪制滾動條

自定義View執(zhí)行invalidate()方法,為什么有時候不會回調(diào)onDraw()

自定義一個view時,重寫onDraw。調(diào)用view.invalidate(),會觸發(fā)onDraw和computeScroll()。前提是該view被附加在當前窗口.

view.postInvalidate(); //是在非UI線程上調(diào)用的

自定義一個ViewGroup,重寫onDraw。onDraw可能不會被調(diào)用,原因是需要先設(shè)置一個背景(顏色或圖)。表示這個group有東西需要繪制了,才會觸發(fā)draw,之后是onDraw。因此,一般直接重寫dispatchDraw來繪制viewGroup.自定義一個ViewGroup,dispatchDraw會調(diào)用drawChild.


22、事件傳遞機制

談?wù)則ouch事件的傳遞流程

所有Touch事件都被封裝成了MotionEvent對象,包括Touch的位置、時間、歷史記錄以及第幾個手指(多指觸摸)等。

事件類型分為ACTION_DOWN, ACTION_UP, ACTION_MOVE, ACTION_POINTER_DOWN, ACTION_POINTER_UP, ACTION_CANCEL,每個事件都是以ACTION_DOWN開始ACTION_UP結(jié)束。

對事件的處理包括三類,分別為傳遞——dispatchTouchEvent()函數(shù)、攔截——onInterceptTouchEvent()函數(shù)、消費——onTouchEvent()函數(shù)和OnTouchListener()

簡單來說:

事件從Activity.dispatchTouchEvent()開始傳遞,只要沒有被停止或攔截,從最上層的View(ViewGroup)開始一直往下(子View)傳遞。子View可以通過onTouchEvent()對事件進行處理。

事件由父View(ViewGroup)傳遞給子View,ViewGroup可以通過onInterceptTouchEvent()對事件做攔截,停止其往下傳遞。

如果事件從上往下傳遞過程中一直沒有被停止,且最底層子View沒有消費事件,事件會反向往上傳遞,這時父View(ViewGroup)可以進行消費,如果還是沒有被消費的話,最后會到Activity的onTouchEvent()函數(shù)。

如果View沒有對ACTION_DOWN進行消費,之后的其他事件不會傳遞過來。

= OnTouchListener優(yōu)先于onTouchEvent()對事件進行消費。

上面的消費即表示相應(yīng)函數(shù)返回值為true。

View中setOnTouchListener中的onTouch,onTouchEvent,onClick的執(zhí)行順序

onTouch優(yōu)于onTouchEvent,onTouchEvent優(yōu)于onClick


23、什么是Dalvik虛擬機

Dalvik虛擬機是Android平臺的核心。

它可以支持.dex格式的程序的運行

.dex格式是專為Dalvik設(shè)計的一種壓縮格式

可以減少整體文件尺寸

提高I/O操作的速度

適合內(nèi)存和處理器速度有限的系統(tǒng)

Dalvik虛擬機和JVM有什么區(qū)別

Dalvik 基于寄存器,而 JVM 基于棧。基于寄存器的虛擬機對于更大的程序來說,在它們編譯的時候,花費的時間更短。

Dalvik執(zhí)行.dex格式的字節(jié)碼,而JVM執(zhí)行.class格式的字節(jié)碼

Android為每個應(yīng)用程序分配的內(nèi)存大小是多少

一般是16m或者24m,但是可以通過android:largeHeap申請更多內(nèi)存

Dalvik?

  Android4.4及以前使用的都是Dalvik虛擬機,我們知道Apk在打包的過程中會先將java等源碼通過javac編譯成.class文件,但是我們的Dalvik虛擬機只會執(zhí)行.dex文件,這個時候dx會將.class文件轉(zhuǎn)換成Dalvik虛擬機執(zhí)行的.dex文件。Dalvik虛擬機在啟動的時候會先將.dex文件轉(zhuǎn)換成快速運行的機器碼,又因為65535這個問題,導(dǎo)致我們在應(yīng)用冷啟動的時候有一個合包的過程,最后導(dǎo)致的一個結(jié)果就是我們的app啟動慢,這就是Dalvik虛擬機的JIT特性(Just In Time)。

ART?

  ART虛擬機是在Android5.0才開始使用的Android虛擬機,ART虛擬機必須要兼容Dalvik虛擬機的特性,但是ART有一個很好的特性AOT(ahead of time),這個特性就是我們在安裝APK的時候就將dex直接處理成可直接供ART虛擬機使用的機器碼,ART虛擬機將.dex文件轉(zhuǎn)換成可直接運行的.oat文件,ART虛擬機天生支持多dex,所以也不會有一個合包的過程,所以ART虛擬機會很大的提升APP冷啟動速度。

3.總結(jié)

Dalvik虛擬機執(zhí)行的是dex字節(jié)碼,ART虛擬機執(zhí)行的是本地機器碼

ART優(yōu)點:

  加快APP冷啟動速度

  提升GC速度

  提供功能全面的Debug特性

ART缺點:

  APP安裝速度慢,因為在APK安裝的時候要生成可運行.oat文件

  APK占用空間大,因為在APK安裝的時候要生成可運行.oat文件


24、如何解決方法數(shù)65k問題?

使用Android Studio 的gradle 可以構(gòu)建MutilDex


25、Android Binder機制原理

Binder是Android系統(tǒng)進程間通信(IPC)方式之一,Binder框架定義了四個角色:Server,Client,ServiceManager(以后簡稱SMgr)以及Binder驅(qū)動。

其中Server,Client,SMgr運行于用戶空間,驅(qū)動運行于內(nèi)核空間。這四個角色的關(guān)系和互聯(lián)網(wǎng)類似:Server是服務(wù)器,Client是客戶終端,SMgr是域名服務(wù)器(DNS),驅(qū)動是路由器。


26、AMS與WMS

Android的framework層主要是由WMS、AMS還有View所構(gòu)成,AMS和WMS都屬于Android中的系統(tǒng)服務(wù)

AMS統(tǒng)一調(diào)度所有應(yīng)用程序的Activity

WMS控制所有Window的顯示與隱藏以及要顯示的位置

AMS

基礎(chǔ)了解

作用

統(tǒng)一調(diào)度所有應(yīng)用程序的Activity的生命周期

啟動或殺死應(yīng)用程序的進程

啟動并調(diào)度Service的生命周期

注冊BroadcastReceiver,并接收和分發(fā)Broadcast

啟動并發(fā)布ContentProvider

調(diào)度task

處理應(yīng)用程序的Crash

查詢系統(tǒng)當前運行狀態(tài)



WMS

基礎(chǔ)了解

WindowManagerService服務(wù)的實現(xiàn)是相當復(fù)雜的,畢竟它要管理的整個系統(tǒng)所有窗口的UI,而在任何一個系統(tǒng)中,窗口管理子系統(tǒng)都是極其復(fù)雜的。

作用

為所有窗口分配Surface??蛻舳讼騑MS添加一個窗口的過程,其實就是WMS為其分配一塊Suiface的過程,一塊塊Surface在WMS的管理下有序的排布在屏幕上。Window的本質(zhì)就是Surface。

管理Surface的顯示順序、尺寸、位置

管理窗口動畫

輸入系統(tǒng)相關(guān):WMS是派發(fā)系統(tǒng)按鍵和觸摸消息的最佳人選,當接收到一個觸摸事件,它需要尋找一個最合適的窗口來處理消息,而WMS是窗口的管理者,系統(tǒng)中所有的窗口狀態(tài)和信息都在其掌握之中,完成這一工作不在話下。


27、ProGuard簡介

因為Java代碼是非常容易反編碼的,況且Android開發(fā)的應(yīng)用程序是用Java代碼寫的,為了很好的保護Java源代碼,我們需要對編譯好后的class文件進行混淆。

ProGuard是一個混淆代碼的開源項目,它的主要作用是混淆代碼,殊不知ProGuard還包括以下4個功能。

壓縮(Shrink):檢測并移除代碼中無用的類、字段、方法和特性(Attribute)。

優(yōu)化(Optimize):對字節(jié)碼進行優(yōu)化,移除無用的指令。

混淆(Obfuscate):使用a,b,c,d這樣簡短而無意義的名稱,對類、字段和方法進行重命名。

預(yù)檢(Preveirfy):在Java平臺上對處理后的代碼進行預(yù)檢,確保加載的class文件是可執(zhí)行的。

總而言之,根據(jù)官網(wǎng)的翻譯:Proguard是一個Java類文件壓縮器、優(yōu)化器、混淆器、預(yù)校驗器。壓縮環(huán)節(jié)會檢測以及移除沒有用到的類、字段、方法以及屬性。優(yōu)化環(huán)節(jié)會分析以及優(yōu)化方法的字節(jié)碼。混淆環(huán)節(jié)會用無意義的短變量去重命名類、變量、方法。這些步驟讓代碼更精簡,更高效,也更難被逆向(破解)。

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

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

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