android 知識點彙總 這一篇就夠了

廢話不多說,直接上圖:
在這裏插入圖片描述

Activity

什麼是Activity?

Activity是一個Android的應用組件,它提供屏幕進行交互。每個Activity都會獲得一個用於繪製其用戶界面的窗口,窗口可以充滿哦屏幕也可以小於屏幕並浮動在其他窗口之上

Activity的生命週期

在這裏插入圖片描述

如何保存Activity的狀態

1.一般來說, 調用 onPause()和 onStop()方法後的 activity 實例仍然存在於內存中, activity 的所有信息和狀態數據不會消失, 當 activity 重新回到前臺之後, 所有的改變都會得到保留。
但是當系統內存不足時, 調用onPause()和onStop()方法後的activity可能會被系統摧毀, 此時內存中就不會存有
該 activity 的實例對象了。如果之後這個 activity 重新回到前臺, 之前所作的改變就會消失。爲了避免此種情況的發生,我們可以覆寫 onSaveInstanceState()方法 onSaveInstanceState()方法接受一個 Bundle 類型的參數, 開發者可以將狀態數據存儲到這個 Bundle 對象中, 這樣即使 activity 被系統摧毀, 當用戶重新啓動這個 activity 而調用它的onCreate()方法時, 上述的 Bundle 對象會作爲實參傳遞給 onCreate()方法,(或者是onRestoreInstanceState) 開發者可以從 Bundle 對象中取出保存的數據, 然後利用這些數據將 activity 恢復到被摧毀之前的狀態。
2.需要注意的是, onSaveInstanceState()方法並不是一定會被調用的, 因爲有些場景是不需要保存狀態數據的.如按下back鍵退出當前活動

兩個Activity之間跳轉時必然會執行的是哪幾個方法?

當在A 裏面激活B 組件的時候, A會調用onPause()方法,然後B調用onCreate() ,onStart(), onResume()。
這個時候B覆蓋了A的窗體, A會調用onStop()方法。
如果B是個透明的窗口,或者是對話框的樣式, 就不會調用A的onStop()方法。
如果B已經存在於Activity棧中,B就不會調用onCreate()方法。

橫豎屏切換時Activity的生命週期

第一次運行Activity : onCreate–>onStart–>onResume–>
切換成橫屏時:onSaveInstanceState–>onPause–>onStop–>onDestroy–>onCreate–>onStart–>onRestoreInstanceState–>onResume–>
在切換成豎屏時:onSaveInstanceState–>onPause–>onStop–>onDestroy–>onCreate–>onStart–>onRestoreInstanceState–>onResume–>
onSaveInstanceState–>onPause–>onStop–>onDestroy–>onCreate–>onStart–>onRestoreInstanceState–>onResume–>

如何將一個Activity設置成窗口的樣式

activity中配置android:theme="@android:style/Theme.Dialog",另外
android:theme="@android:style/Theme.Translucent"是設置透明

如何退出Activity?如何安全退出已調用多個Activity的Application?

退出Activity 直接調用 finish () 方法即可,退出activity 會執行 onDestroy()方法

多個Activity的Application退出方法:

1.記錄打開的Activity:
每打開一個Activity,就記錄下來。在需要退出時,關閉每一個Activity即可。
2、發送特定廣播:
在需要結束應用時,發送一個特定的廣播,每個Activity收到廣播後,關閉即可。
3、遞歸退出
在打開新的Activity時使用startActivityForResult,然後自己加標誌,在onActivityResult中處理,遞歸關閉。

Activity的四種啓動模式,singletop和singletask區別是什麼?一般書籤的使用模式是singletop,那爲什麼不使用singletask?

Activity的四種啓動模式

在 AndroidManifest.xml 文件中 Activity 元素的 android:launchMode 屬性。
Activity的四種啓動模式:standard:這是默認模式,每次激活Activity時都會創建Activity實例,並放入任務棧中。
singleTop: 如果在任務的棧頂正好存在該Activity的實例,就重用該實例( 會調用實例的
onNewIntent() ),否則就會創建新的實例並放入棧頂,即使棧中已經存在該Activity的實例,只要不在棧頂,都會創建新的實例
singleTask:如果在棧中已經有該Activity的實例,就重用該實例(會調用實例的 onNewIntent() )。重用時,會讓該實例回到棧頂,因此在它上面的實例將會被移出棧。如果棧中不存在該實例,將會創建新的實例放入棧中。
singleInstance:在一個新棧中創建該Activity的實例,並讓多個應用共享該棧中的該Activity實例。一旦該模式的Activity實例已經存在於某個棧中,任何應用再激活該Activity時都會重用該棧中的實例( 會調用實例的 onNewIntent() )。其效果相當於多個應用共享一個應用,不管誰激活該 Activity 都會進入同一個應用中。

singletop和singletask區別是什麼:

singleTop要求如果創建intent的時候棧頂已經有要創建的Activity的實例,則將intent發送給該實例,而不發送給新的實例。(注意是棧頂,不在棧頂照樣創建新實例!)
singleTask模式:當intent到來,需要創建singleTask模式Activity的時候,系統會檢查棧裏面是否已經有該Activity的實例。如果有直接將intent發送給它。

一般書籤的使用模式是singletop,那爲什麼不使用singletask?

singletask屬性是如果在棧中已經有該Activity的實例,就重用該實例(會調用實例的 onNewIntent() )。重用時,會讓該實例回到棧頂,因此在它上面的實例將會被移出棧。徹底改變了棧內的位置順序

Android中的Context, Activity,Appliction有什麼區別?

相同:Activity 和 Application 都是 Context 的子類。
Context 從字面上理解就是上下文的意思,在實際應用中它也確實是起到了管理 上下文環境中各個參數和變量的總用,方便我們可以簡單的訪問到各種資源。
不同:維護的生命週期不同。Context 維護的是當前的 Activity 的生命週期, Application 維護的是整個項目的生命週期。使用 context 的時候,小心內存泄露,防止內存泄露,注意一下幾個方面:
不要讓生命週期長的對象引用 activity context,即保證引用 activity 的對 象要與 activity 本身生命週期是一樣的。
對於生命週期長的對象,可以使用 application,context.
避免非靜態的內部類,儘量使用靜態類,避免生命週期問題,注意內部類 對外部對象引用導致的生命週期變化。

兩個Activity之間傳遞數據,除了intent,廣播接收者,content provider還有啥?

1.利用static靜態數據,public static成員變量
2.利用外部存儲的傳輸,
3. 例如 File 文件存儲
4. SharedPreferences首選項
5. Sqlite 數據庫

Context 是什麼?

1.它描述的是一個應用程序環境的信息,即上下文。
2、該類是一個抽象(abstract class)類,Android 提供了該抽象類的具體實 現類(ContextIml)。
3、通過它我們可以獲取應用程序的資源和類,也包括一些應用級別操作, 例如:啓動一個 Activity,發送廣播,接受 Intent,信息,

Service

Service是否在main thread中執行, service裏面是否能執行耗時的操作?

默認情況,如果沒有顯示的指 service 所運行的進程, Service 和 activity 是運行在當前 app 所在進程的 main
thread(UI 主線程)裏面。
service 裏面不能執行耗時的操作(網絡請求,拷貝數據庫,大文件 )

Activity怎麼和Service綁定,怎麼在Activity中啓動自己對應的Service?

Activity通過bindService(Intent service, ServiceConnection conn, int flags)跟Service進行綁定

private class myconn implements ServiceConnection

{

public void onServiceConnected(ComponentName name, IBinder service) {
// TODO Auto-generated method stub
//可以通過IBinder的對象 去使用service裏面的方法
}

public void onServiceDisconnected(ComponentName name) {
// TODO Auto-generated method stub

}

}
Service生命週期

只調用 startService() 啓動服務:onCreate() -> onStartCommand() -> onDestory()
只調用 bindService() 綁定服務:onCreate() -> onBind() -> onUnBind() -> onDestory()
同時使用startService()與bindService():onCreate() -> onStartCommnad() -> onBind() -> onUnBind() -> onDestory。

什麼是IntentService?有何優點?

IntentService 是 Service 的子類,比普通的 Service 增加了額外的功能。
優點:
會創建獨立的worker線程來處理所有的Intent請求;
會創建獨立的worker線程來處理onHandleIntent()方法實現的代碼,無需處理多線程問題;
所有請求處理完成後,IntentService會自動停止,無需調用stopSelf()方法停止Service;
爲Service的onBind()提供默認實現,返回null;
爲Service的onStartCommand提供默認實現,將請求Intent添加到隊列中;

Activity、Intent、Service是什麼關係

一個 Activity 通常是一個單獨的屏幕,每一個 Activity 都被實現爲一個單獨的類,這些類都是從 Activity 基類中繼承而來的。
Activity 類會顯示由視圖控件組成的用戶接口,並對視圖控件的事件做出響應。
Intent 的調用是用來進行屏幕之間的切換。Intent 描述應用想要做什麼。Intent 數據結構中兩個最重要的部分是動作和動作對應的數據,一個動作對應一個動作數據。
Service 是運行在後臺的代碼,不能與用戶交互,可以運行在自己的進程裏,也可以運行在其他應用程序進程的上下文裏。需要一個Activity 或者其他 Context 對象來調用。
聯繫:
Activity 跳轉 Activity,Activity 啓動 Service,Service 打開 Activity 都需要 Intent 表明意圖,以及傳遞參數,Intent 是這些組件間信號傳遞的承載着

Service和Activity在同一個線程嗎

一般來說:同一個包內的activity和service,如果service沒有設定屬性android:process=":remote"的話,service會和activity跑在同一個進程中,由於一個進程只有一個UI線程,所以,service和acitivity就是在同一個線程裏面的。

Service裏面可以彈吐司麼

Service不僅可以彈Toast還能彈出對話框,第一,Service是運行在主線程當中;第二,彈吐司有個條件就是得有一個 Context 上下文,而 Service 本身就是 Context 的子類;因此在 Service 裏面彈吐司是完全可以的。

Service裏面可以彈吐司麼

Context.startService() 和 Context.bindService()。 區別 爲
Context.startService():Service 會經歷 onCreate -> onStart(如果 Service 還沒有運行, 則android先調用onCreate()然後調用onStart();如果Service已經運行,則只調用onStart(), 所以一個 Service 的 onStart 方法可能會重複調用多次 ); stopService 的時候直接 onDestroy,如果是調用者自己直接退出而沒有調用 stopService 的話,Service 會一直在後 臺運行。該 Service 的調用者再啓動起來後可以通過 stopService 關閉 Service

Service有哪些啓動方法,有什麼區別,怎樣停用Service?

Service 的方式 Context.startService() 和 Context.bindService()。 區別 爲 Context.startService():Service 會經歷 onCreate -> onStart(如果 Service 還沒有運行, 則android先調用onCreate()然後調用onStart();如果Service已經運行,則只調用onStart(), 所以一個 Service 的 onStart 方法可能會重複調用多次 ); stopService 的時候直接 onDestroy,如果是調用者自己直接退出而沒有調用 stopService 的話,Service 會一直在後 臺運行。該 Service 的調用者再啓動起來後可以通過 stopService 關閉 Service
Context.bindService():Service 會經歷 onCreate() -> onBind(),onBind 將返回給客戶端 一個 IBind 接口實例,IBind 允許客戶端回調服務的方法,比如得到 Service 運行的狀態或其 他操作。這個時候把調用者(Context,例如 Activity)會和 Service 綁定在一起,Context 退出了,Srevice 就會調用 onUnbind -> onDestroyed 相應退出,所謂綁定在一起就共存亡 了 。
停用 service 使用 context.stopService()

service的生命週期方法onstartConmand()可不可以執行網絡操作?如何在service中執行網絡操作?

可以直接在Service中執行網絡操作

Broadcast Receiver
描述一下BroadcastReceiver

用於監聽(接收)應用發出的廣播消息,並做出響應

在manifest和代碼中如何註冊和使用BroadcastReceiver

首先寫一個類要繼承 BroadcastReceiver
第一種:在清單文件中聲明,添加
第二種使用代碼進行註冊如:
創建IntentFilter ,並將要廣播接收器接收的參數傳進去
創建廣播接收器,New出一個廣播接收器
接着使用registerReceiver()方法,將上述創建的兩個參數傳進去

BroadCastReceiver的生命週期

每次廣播到來時 , 會重新創建 BroadcastReceiver 對象 , 並且調用 onReceive() 方法 , 執行完以後 , 該對象即 被銷燬

ContentProvider
請介紹下ContentProvider是如何實現數據共享的

使用 ContentProvider 可以將數據共享給其他應用,讓除本應用之外的應用也可以訪問本應用的數據。它的底層是用 SQLite 數據庫實現的,所以其對數據做的各種操作都是以 Sql 實現,只是在上層提供的是 Uri,用戶只需要關心操作數據的 uri 就可以了,ContentProvider 可以實現不同 app 之間共享

請介紹下Android的數據存儲方式

五種 SharePreferences、SQLite、Contert Provider、File、網絡存儲

爲什麼要用ContentProvider?它和sql的實現上有什麼差別?

ContentProvider實現了不同APP之間數據共享,ContentProvider爲其他應用程序提供了訪問本應用程序的接口,其他應用程序可以通過ContentResolver來操作ContentProvider提供的數據,同時ContentProvider保證了被訪數據的安全性,用戶只需要關心操作數據的uri就可以了。
sql也有增刪改查的方法,單sql只能操作本應用下的數據庫。

說說ContentProvider、ContentResolver、ContentObserver之間的關係

ContentProvider——內容提供者, 在android中的作用是對外共享數據,也就是說你可以通過ContentProvider把應用中的數據共享給其他應用訪問,其他應用可以通過ContentProvider 對你應用中的數據進行添刪改查。
ContentResolver——內容解析者, 其作用是按照一定規則訪問內容提供者的數據(其實就是調用內容提供者自定義的接口來操作它的數據)。
ContentObserver——內容觀察者,目的是觀察(捕捉)特定Uri引起的數據庫的變化,繼而做一些相應的處理,它類似於數據庫技術中的觸發器(Trigger),當ContentObserver所觀察的Uri發生變化時,便會觸發它。

Intent
Intent傳遞數據時,可以傳遞哪些類型數據?

Intent/Bundle支持傳遞基本類型的數據和基本類型的

Serializable和Parcelable的區別

兩者區別在於存儲媒介的不同。
Serializable使用IO讀寫存儲在硬盤上。序列化過程使用了反射技術,並且期間產生臨時對象。優點代碼少。
Parcelable是直接在內存中讀寫,我們知道內存的讀寫速度肯定優於硬盤讀寫速度,所以Parcelable序列化方式性能上要優於Serializable方式很多。但是代碼寫起來相比Serializable方式麻煩一些。

請描述一下Intent 和 IntentFilter

filter一般不會在java代碼中設置,而是在應用的manifest文件中作爲元素的方式聲明。一個例外是,爲broadcast
receiver註冊動態的filter,可以調用Context.registerReceiver()方法,通過直接實例化IntentFilter對象創建。

Fragment
Fragment跟Activity之間是如何傳值的

fragment跳轉activity傳值 採用Bundle

Intent intent = new Intent(getActivity(), FirstActivity.class);
Bundle bundle = new Bundle();
bundle.putString("address", address);
intent.putExtras(bundle);
startActivity(intent);
描述一下Fragment的生命週期

被創建到用戶可見: onAttach()->onCreate()->onCreateView()->onActivityCreated()onStart()->onResume()
後臺模式:onPause()->onStop()
銷燬: onPause()->onStop()->onDestroyView()->onDestroy()->onDetach()

Fragment的replace和add方法的區別

可以看到add()方法添加的Fragment沒有發生銷燬對象的情況,怎麼切換還是原來的Fragment
而replace()方法,會銷燬前一個Fragment1,重新創建Fragment2

Fragment如何實現類似Activity棧的壓棧和出棧效果的?

Fragment的事物管理器內部維持了一個雙向鏈表結構,該結構可以記錄我們每次add的Fragment和replace的Fragment,然後當我們點擊back按鈕的時候會自動幫我們實現退棧操作。

如何切換fragement,不重新實例化

正確的切換方式是add(),切換時hide(),add()另一個Fragment,再次切換時,只需hide()當前,show()另一 個。

擴展
在單線程模型中Message,Handler,Message Queue,Looper之間的關係。

拿主線程來說,主線程啓動時會調用Looper.prepare()方法,會初始化一個Looper,放入Threadlocal中,接着調用Looper.loop()不斷遍歷Message Queue, Handler的創建依賴與當前線程中的Looper,如果當前線程沒有Looper則必須調用Looper.prepare()。Handler , sendMessage到MessageQueue,Looper不斷從MessageQueue中取出消息,回調handleMessage方法。

內存泄漏有哪些場景以及解決方法
  1. 類的靜態變量持有大數據對象 靜態變量長期維持到大數據對象的引用,阻止垃圾回收。
  2. 非靜態內部類存在靜態實例 非靜態內部類會維持一個到外部類實例的引用,如果非靜態內部類的實例是靜態的,就會間接長期維持着外部類的引用,阻止被回收掉。
    3.資源對象未關閉 資源性對象比如(Cursor,File文件等)往往都用了一些緩衝,我們在不使用的時候,應該及時關閉它們, 以便它們的緩衝及時回收內存。它們的緩衝不僅存在於java虛擬機內,還存在於java虛擬機外。 如果我們僅僅是把它的引用設置爲null,而不關閉它們,往往會造成內存泄露。 解決辦法: 比如SQLiteCursor(在析構函數finalize(),如果我們沒有關閉它,它自己會調close()關閉), 如果我們沒有關閉它,系統在回收它時也會關閉它,但是這樣的效率太低了。 因此對於資源性對象在不使用的時候,應該調用它的close()函數,將其關閉掉,然後才置爲null. 在我們的程序退出時一定要確保我們的資源性對象已經關閉。 程序中經常會進行查詢數據庫的操作,但是經常會有使用完畢Cursor後沒有關閉的情況。如果我們的查詢結果集比較小, 對內存的消耗不容易被發現,只有在常時間大量操作的情況下才會復現內存問題,這樣就會給以後的測試和問題排查帶來困難和風險,記得try catch後,在finally方法中關閉連接
    4.Handler內存泄漏 Handler作爲內部類存在於Activity中,但是Handler生命週期與Activity生命週期往往並不是相同的,比如當Handler對象有Message在排隊,則無法釋放,進而導致本該釋放的Acitivity也沒有辦法進行回收。 解決辦法:
    5.一些不良代碼習慣 有些代碼並不造成內存泄露,但是他們的資源沒有得到重用,頻繁的申請內存和銷燬內存,消耗CPU資源的同時,也引起內存抖動 解決方案 如果需要頻繁的申請內存對象和和釋放對象,可以考慮使用對象池來增加對象的複用。 例如ListView便是採用這種思想,通過複用converview來避免頻繁的GC
如何避免 OOM 問題的出現

1.使用更加輕量的數據結構 例如,我們可以考慮使用ArrayMap/SparseArray而不是HashMap等傳統數據結構。通常的HashMap的實現方式更加消耗內存,因爲它需要一個額外的實例對象來記錄Mapping操作。另外,SparseArray更加高效,在於他們避免了對key與value的自動裝箱(autoboxing),並且避免了裝箱後的解箱。
2.避免在Android裏面使用Enum Android官方培訓課程提到過“Enums often require more than twice as much memory as static constants. You should strictly avoid using enums on Android.”,具體原理請參考
3. 減小Bitmap對象的內存佔用 Bitmap是一個極容易消耗內存的大胖子,減小創建出來的Bitmap的內存佔用可謂是重中之重,,通常來說有以下2個措施: inSampleSize:縮放比例,在把圖片載入內存之前,我們需要先計算出一個合適的縮放比例,避免不必要的大圖載入。 decode format:解碼格式,選擇ARGB_6666/RBG_545/ARGB_4444/ALPHA_6,存在很大差異
4. Bitmap對象的複用 縮小Bitmap的同時,也需要提高BitMap對象的複用率,避免頻繁創建BitMap對象,複用的方法有以下2個措施 LRUCache : “最近最少使用算法”在Android中有極其普遍的應用。ListView與GridView等顯示大量圖片的控件裏,就是使用LRU的機制來緩存處理好的Bitmap,把近期最少使用的數據從緩存中移除,保留使用最頻繁的數據, inBitMap高級特性:利用inBitmap的高級特性提高Android系統在Bitmap分配與釋放執行效率。使用inBitmap屬性可以告知Bitmap解碼器去嘗試使用已經存在的內存區域,新解碼的Bitmap會嘗試去使用之前那張Bitmap在Heap中所佔據的pixel data內存區域,而不是去問內存重新申請一塊區域來存放Bitmap。利用這種特性,即使是上千張的圖片,也只會僅僅只需要佔用屏幕所能夠顯示的圖片數量的內存大小
5.使用更小的圖片 在涉及給到資源圖片時,我們需要特別留意這張圖片是否存在可以壓縮的空間,是否可以使用更小的圖片。儘量使用更小的圖片不僅可以減少內存的使用,還能避免出現大量的InflationException。假設有一張很大的圖片被XML文件直接引用,很有可能在初始化視圖時會因爲內存不足而發生InflationException,這個問題的根本原因其實是發生了OOM。
6.StringBuilder 在有些時候,代碼中會需要使用到大量的字符串拼接的操作,這種時候有必要考慮使用StringBuilder來替代頻繁的“+”。避免在onDraw方法裏面執行對象的創建 類似onDraw等頻繁調用的方法,一定需要注意避免在這裏做創建對象的操作,因爲他會迅速增加內存的使用,而且很容易引起頻繁的gc,甚至是內存抖動。

Android 中常用的五種佈局

Android 佈局是應用界面開發的重要一環,在 Android 中,共有五種佈局方式,分別是: FrameLayout (框架佈局),LinearLayout (線性佈局),AbsoluteLayout (絕對佈局), RelativeLayout (相對佈局), TableLayout (表格佈局)。

handler機制的原理

andriod提供了Handler和Looper來滿足線程間的通信。Handler先進先出原則。Looper類用來管理特定線程內對象之間的消息交換(MessageExchange)。
1.Looper:一個線程可以產生一個Looper對象,由它來管理此線程裏的MessageQueue(消息隊列)。
2.Handler:你可以構造Handler對象來與Looper溝通,以便push新消息到MessageQueue裏;或者接收Looper從MessageQueue取出)所送來的消息。
3.MessageQueue(消息隊列):用來存放線程放入的消息。
4.線程:UIthread通常就是mainthread,而Android啓動程序時會替它建立一個MessageQueue。

AsyncTask使用在哪些場景?它的缺陷是什麼?如何解決?

解析 AsyncTask 運用的場景就是我們需要進行一些耗時的操作,耗時操作完成後更新主線程,或者在操作過程中對主線程的UI進行更新。 缺陷:AsyncTask中維護着一個長度爲128的線程池,同時可以執行5個工作線程,還有一個緩衝隊列,當線程池中已有128個線程,緩衝隊列已滿時,如果 此時向線程提交任務,將會拋出RejectedExecutionException。 解決:由一個控制線程來處理AsyncTask的調用判斷線程池是否滿了,如果滿了則線程睡眠否則請求AsyncTask繼續處理。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章