Android五種佈局: FrameLayout 、 LinearLayout 、 AbsoluteLayout 、 RelativeLayout 、 TableLayout 全都繼承自ViewGroup,各自特點及繪製效率對比。
-
FrameLayout(框架佈局)
此佈局是五種佈局中最簡單的佈局,Android中並沒有對child view的擺佈進行控制,這個佈局中所有的控制元件都會預設出現在檢視的左上角,我們可以使用
android:layout_margin
,android:layout_gravity
等屬性去控制子控制元件相對佈局的位置。 -
LinearLayout(線性佈局)
一行(或一列)只控制一個控制元件的線性佈局,所以當有很多控制元件需要在一個介面中列出時,可以用LinearLayout佈局。
此佈局有一個需要格外注意的屬性:android:orientation=“horizontal|vertical
。
* 當`android:orientation="horizontal`時,*說明你希望將水平方向的佈局交給**LinearLayout** *,其子元素的`android:layout_gravity="right|left"` 等控制水平方向的gravity值都是被忽略的,*此時**LinearLayout**中的子元素都是預設的按照水平從左向右來排*,我們可以用`android:layout_gravity="top|bottom"`等gravity值來控制垂直展示。
* 反之,可以知道 當`android:orientation="vertical`時,**LinearLayout**對其子元素展示上的的處理方式。
複製程式碼
-
AbsoluteLayout(絕對佈局)
又可以叫做座標佈局, 可以放置多個控制元件,可以直接指定子元素的絕對位置(xy),由於手機螢幕尺寸差別比較大,使用絕對定位的適應性會比較差,在螢幕的適配上有缺陷
-
RelativeLayout(相對佈局)
這個佈局也是相對自由的佈局,Android 對該佈局的child view的 水平layout& 垂直layout做了解析,由此我們可以FrameLayout的基礎上使用標籤或者Java程式碼對垂直方向 以及 水平方向 佈局中的views進行任意的控制.
- 相關屬性:
android:layout_centerInParent="true|false" droid:layout_centerHorizontal="true|false" droid:layout_alignParentRight="true|false" 複製程式碼
-
TableLayout(表格佈局)
將子元素的位置分配到行或列中,一個TableLayout由許多的TableRow組成。 TableLayout的用法還是很簡單的,無非就是確定表格的行數,以及使用 它三個屬性(collapseColumns,stretchColumns,shrinkColumns)來設定每一行中的第某列的元素隱藏,拉伸,或者收縮即可!
Activity生命週期
-
啟動Activity: onCreate()—>onStart()—>onResume(),Activity進入執行狀態。
-
Activity退居後臺: 當前Activity轉到新的Activity介面或按Home鍵回到主屏: onPause()—>onStop(),進入停滯狀態。
-
Activity返回前臺: onRestart()—>onStart()—>onResume(),再次回到執行狀態。
-
Activity退居後臺,且系統記憶體不足, 系統會殺死這個後臺狀態的Activity(此時這個Activity引用仍然處在任務棧中,只是這個時候引用指向的物件已經為null),若再次回到這個Activity,則會走onCreate()–>onStart()—>onResume()(將重新走一次Activity的初始化生命週期)
-
鎖屏:
onPause()->onStop()
-
解鎖:
onStart()->onResume()
-
生命週期流程圖
通過Acitivty的xml標籤來改變任務棧的預設行為
-
使用
android:launchMode="standard|singleInstance|singleTask|singleTop"
來控制Acivity任務棧。任務棧是一種後進先出的結構。位於棧頂的Activity處於焦點狀態,當按下back按鈕的時候,棧內的Activity會一個一個的出棧,並且呼叫其
onDestory()
方法。如果棧內沒有Activity,那麼系統就會回收這個棧,每個APP預設只有一個棧,以APP的包名來命名.- standard : 標準模式,每次啟動Activity都會建立一個新的Activity例項,並且將其壓入任務棧棧頂,而不管這個Activity是否已經存在。Activity的啟動三回撥(onCreate()->onStart()->onResume())都會執行。
- singleTop : 棧頂複用模式.這種模式下,如果新Activity已經位於任務棧的棧頂,那麼此Activity不會被重新建立,所以它的啟動三回撥就不會執行,同時Activity的
onNewIntent()
方法會被回撥.如果Activity已經存在但是不在棧頂,那麼作用與standard模式一樣. - singleTask: 棧內複用模式.建立這樣的Activity的時候,系統會先確認它所需任務棧已經建立,否則先建立任務棧.然後放入Activity,如果棧中已經有一個Activity例項,那麼這個Activity就會被調到棧頂,
onNewIntent()
,並且singleTask會清理在當前Activity上面的所有Activity.(clear top) - singleInstance : 加強版的singleTask模式,這種模式的Activity只能單獨位於一個任務棧內,由於棧內複用的特性,後續請求均不會建立新的Activity,除非這個獨特的任務棧被系統銷燬了
Activity的堆疊管理以ActivityRecord為單位,所有的ActivityRecord都放在一個List裡面.可以認為一個ActivityRecord就是一個Activity棧
Activity快取方法
有a、b兩個Activity,當從a進入b之後一段時間,可能系統會把a回收,這時候按back,執行的不是a的onRestart而是onCreate方法,a被重新建立一次,這是a中的臨時資料和狀態可能就丟失了。
可以用Activity中的onSaveInstanceState()回撥方法儲存臨時資料和狀態,這個方法一定會在活動被回收之前呼叫。方法中有一個Bundle引數,putString()、putInt()等方法需要傳入兩個引數,一個鍵一個值。資料儲存之後會在onCreate中恢復,onCreate也有一個Bundle型別的引數。
示例程式碼:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//這裡,當Acivity第一次被建立的時候為空
//所以我們需要判斷一下
if( savedInstanceState != null ){
savedInstanceState.getString("anAnt");
}
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString("anAnt","Android");
}
複製程式碼
一、onSaveInstanceState (Bundle outState)
當某個activity變得“容易”被系統銷燬時,該activity的onSaveInstanceState就會被執行,除非該activity是被使用者主動銷燬的,例如當使用者按BACK鍵的時候。
注意上面的雙引號,何為“容易”?言下之意就是該activity還沒有被銷燬,而僅僅是一種可能性。這種可能性有哪些?通過重寫一個activity的所有生命週期的onXXX方法,包括onSaveInstanceState和onRestoreInstanceState方法,我們可以清楚地知道當某個activity(假定為activity A)顯示在當前task的最上層時,其onSaveInstanceState方法會在什麼時候被執行,有這麼幾種情況:
1、當使用者按下HOME鍵時。
這是顯而易見的,系統不知道你按下HOME後要執行多少其他的程式,自然也不知道activity A是否會被銷燬,故系統會呼叫onSaveInstanceState,讓使用者有機會儲存某些非永久性的資料。以下幾種情況的分析都遵循該原則
2、長按HOME鍵,選擇執行其他的程式時。
3、按下電源按鍵(關閉螢幕顯示)時。
4、從activity A中啟動一個新的activity時。
5、螢幕方向切換時,例如從豎屏切換到橫屏時。(如果不指定configchange屬性) 在螢幕切換之前,系統會銷燬activity A,在螢幕切換之後系統又會自動地建立activity A,所以onSaveInstanceState一定會被執行
總而言之,onSaveInstanceState的呼叫遵循一個重要原則,即當系統“未經你許可”時銷燬了你的activity,則onSaveInstanceState會被系統呼叫,這是系統的責任,因為它必須要提供一個機會讓你儲存你的資料(當然你不儲存那就隨便你了)。另外,需要注意的幾點:
1.佈局中的每一個View預設實現了onSaveInstanceState()方法,這樣的話,這個UI的任何改變都會自動地儲存和在activity重新建立的時候自動地恢復。但是這種情況只有在你為這個UI提供了唯一的ID之後才起作用,如果沒有提供ID,app將不會儲存它的狀態。
2.由於預設的onSaveInstanceState()方法的實現幫助UI儲存它的狀態,所以如果你需要覆蓋這個方法去儲存額外的狀態資訊,你應該在執行任何程式碼之前都呼叫父類的onSaveInstanceState()方法(super.onSaveInstanceState())。 既然有現成的可用,那麼我們到底還要不要自己實現onSaveInstanceState()?這得看情況了,如果你自己的派生類中有變數影響到UI,或你程式的行為,當然就要把這個變數也儲存了,那麼就需要自己實現,否則就不需要。
3.由於onSaveInstanceState()方法呼叫的不確定性,你應該只使用這個方法去記錄activity的瞬間狀態(UI的狀態)。不應該用這個方法去儲存持久化資料。當使用者離開這個activity的時候應該在onPause()方法中儲存持久化資料(例如應該被儲存到資料庫中的資料)。
4.onSaveInstanceState()如果被呼叫,這個方法會在onStop()前被觸發,但系統並不保證是否在onPause()之前或者之後觸發。
二、onRestoreInstanceState (Bundle outState)
至於onRestoreInstanceState方法,需要注意的是,onSaveInstanceState方法和onRestoreInstanceState方法“不一定”是成對的被呼叫的,(本人注:我昨晚除錯時就發現原來不一定成對被呼叫的!)
onRestoreInstanceState被呼叫的前提是,activity A“確實”被系統銷燬了,而如果僅僅是停留在有這種可能性的情況下,則該方法不會被呼叫,例如,當正在顯示activity A的時候,使用者按下HOME鍵回到主介面,然後使用者緊接著又返回到activity A,這種情況下activity A一般不會因為記憶體的原因被系統銷燬,故activity A的onRestoreInstanceState方法不會被執行
另外,onRestoreInstanceState的bundle引數也會傳遞到onCreate方法中,你也可以選擇在onCreate方法中做資料還原。 還有onRestoreInstanceState在onstart之後執行。 至於這兩個函式的使用,給出示範程式碼(留意自定義程式碼在呼叫super的前或後):
@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
savedInstanceState.putBoolean("MyBoolean", true);
savedInstanceState.putDouble("myDouble", 1.9);
savedInstanceState.putInt("MyInt", 1);
savedInstanceState.putString("MyString", "Welcome back to Android");
// etc.
super.onSaveInstanceState(savedInstanceState);
}
@Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
boolean myBoolean = savedInstanceState.getBoolean("MyBoolean");
double myDouble = savedInstanceState.getDouble("myDouble");
int myInt = savedInstanceState.getInt("MyInt");
String myString = savedInstanceState.getString("MyString");
}
//可以把要儲存的靜態全域性變數先轉成Json
//https://juejin.im/post/5bc55a3af265da0a8b574e3f
複製程式碼
Fragment的生命週期和activity如何的一個關係
這我們引用本知識庫裡的一張圖片:
Fragment每個生命週期方法的意義:https://www.cnblogs.com/fajieyefu/p/6092465.html
為什麼在Service中建立子執行緒而不是Activity中
這是因為Activity很難對Thread進行控制,當Activity被銷燬之後,就沒有任何其它的辦法可以再重新獲取到之前建立的子執行緒的例項。而且在一個Activity中建立的子執行緒,另一個Activity無法對其進行操作。但是Service就不同了,所有的Activity都可以與Service進行關聯,然後可以很方便地操作其中的方法,即使Activity被銷燬了,之後只要重新與Service建立關聯,就又能夠獲取到原有的Service中Binder的例項。因此,使用Service來處理後臺任務,Activity就可以放心地finish,完全不需要擔心無法對後臺任務進行控制的情況。
Intent的使用方法,可以傳遞哪些資料型別。
通過查詢Intent/Bundle的API文件,我們可以獲知,Intent/Bundle支援傳遞基本型別的資料和基本型別的陣列資料,以及String/CharSequence型別的資料和String/CharSequence型別的陣列資料。而對於其它型別的資料貌似無能為力,其實不然,我們可以在Intent/Bundle的API中看到Intent/Bundle還可以傳遞Parcelable(包裹化,郵包)和Serializable(序列化)型別的資料,以及它們的陣列/列表資料。
所以要讓非基本型別和非String/CharSequence型別的資料通過Intent/Bundle來進行傳輸,我們就需要在資料型別中實現Parcelable介面或是Serializable介面。
blog.csdn.net/kkk0526/art… www.cnblogs.com/jiefeiduan/…
Fragment生命週期
注意和Activity的相比的區別,按照執行順序
- onAttach(),onDetach()
- onCreateView(),onDestroyView()
Service的兩種啟動方法,有什麼區別
1.在Context中通過public boolean bindService(Intent service,ServiceConnection conn,int flags)
方法來進行Service與Context的關聯並啟動,並且Service的生命週期依附於Context(不求同時同分同秒生!但求同時同分同秒屎!!)。
2.通過public ComponentName startService(Intent service)
方法去啟動一個Service,此時Service的生命週期與啟動它的Context無關。
3.要注意的是,whatever,都需要在xml裡註冊你的Service,就像這樣:
<service
android:name=".packnameName.youServiceName"
android:enabled="true" />
複製程式碼
廣播(Broadcast Receiver)的兩種動態註冊和靜態註冊有什麼區別。
- 靜態註冊:在AndroidManifest.xml檔案中進行註冊,當App退出後,Receiver仍然可以接收到廣播並且進行相應的處理
- 動態註冊:在程式碼中動態註冊,當App退出後,也就沒辦法再接受廣播了
ContentProvider使用方法
目前能否保證service不被殺死
Service設定成START_STICKY
- kill 後會被重啟(等待5秒左右),重傳Intent,保持與重啟前一樣
提升service優先順序
- 在AndroidManifest.xml檔案中對於intent-filter可以通過
android:priority = "1000"
這個屬性設定最高優先順序,1000是最高值,如果數字越小則優先順序越低,同時適用於廣播。 - 【結論】目前看來,priority這個屬性貌似只適用於broadcast,對於Service來說可能無效
提升service程式優先順序
- Android中的程式是託管的,當系統程式空間緊張的時候,會依照優先順序自動進行程式的回收
- 當service執行在低記憶體的環境時,將會kill掉一些存在的程式。因此程式的優先順序將會很重要,可以在startForeground()使用startForeground()將service放到前臺狀態。這樣在低記憶體時被kill的機率會低一些。
- 【結論】如果在極度極度低記憶體的壓力下,該service還是會被kill掉,並且不一定會restart()
onDestroy方法裡重啟service
- service +broadcast 方式,就是當service走onDestory()的時候,傳送一個自定義的廣播,當收到廣播的時候,重新啟動service
- 也可以直接在onDestroy()裡startService
- 【結論】當使用類似口口管家等第三方應用或是在setting裡-應用-強制停止時,APP程式可能就直接被幹掉了,onDestroy方法都進不來,所以還是無法保證
監聽系統廣播判斷Service狀態
- 通過系統的一些廣播,比如:手機重啟、介面喚醒、應用狀態改變等等監聽並捕獲到,然後判斷我們的Service是否還存活,別忘記加許可權
- 【結論】這也能算是一種措施,不過感覺監聽多了會導致Service很混亂,帶來諸多不便
在JNI層,用C程式碼fork一個程式出來
- 這樣產生的程式,會被系統認為是兩個不同的程式.但是Android5.0之後可能不行
root之後放到system/app變成系統級應用
大招: 放一個畫素在前臺(手機QQ)
動畫有哪兩類,各有什麼特點?三種動畫的區別
-
tween 補間動畫。通過指定View的初末狀態和變化時間、方式,對View的內容完成一系列的圖形變換來實現動畫效果。 Alpha Scale Translate Rotate。
-
frame 幀動畫 AnimationDrawable 控制 animation-list xml佈局
-
PropertyAnimation 屬性動畫
Android的資料儲存形式。
-
SQLite:SQLite是一個輕量級的資料庫,支援基本的SQL語法,是常被採用的一種資料儲存方式。 Android為此資料庫提供了一個名為SQLiteDatabase的類,封裝了一些運算元據庫的api
-
SharedPreference: 除SQLite資料庫外,另一種常用的資料儲存方式,其本質就是一個xml檔案,常用於儲存較簡單的引數設定。
-
File: 即常說的檔案(I/O)儲存方法,常用語儲存大數量的資料,但是缺點是更新資料將是一件困難的事情。
-
ContentProvider: Android系統中能實現所有應用程式共享的一種資料儲存方式,由於資料通常在各應用間的是互相私密的,所以此儲存方式較少使用,但是其又是必不可少的一種儲存方式。例如音訊,視訊,圖片和通訊錄,一般都可以採用此種方式進行儲存。每個Content Provider都會對外提供一個公共的URI(包裝成Uri物件),如果應用程式有資料需要共享時,就需要使用Content Provider為這些資料定義一個URI,然後其他的應用程式就通過Content Provider傳入這個URI來對資料進行操作。
Sqlite的基本操作。
如何判斷應用被強殺
在Application中定義一個static常量,賦值為-1,在歡迎介面改為0,如果被強殺,application重新初始化,在父類Activity判斷該常量的值。
應用被強殺如何解決
如果在每一個Activity的onCreate裡判斷是否被強殺,冗餘了,封裝到Activity的父類中,如果被強殺,跳轉回主介面,如果沒有被強殺,執行Activity的初始化操作,給主介面傳遞intent引數,主介面會呼叫onNewIntent方法,在onNewIntent跳轉到歡迎頁面,重新來一遍流程。
Json有什麼優劣勢。
怎樣退出終止App
Asset目錄與res目錄的區別。 res 目錄下面有很多檔案,例如 drawable,mipmap,raw 等。res 下面除了 raw 檔案不會被壓縮外,其餘檔案都會被壓縮。同時 res目錄下的檔案可以通過R 檔案訪問。Asset 也是用來儲存資源,但是 asset 檔案內容只能通過路徑或者 AssetManager 讀取。 官方文件
Android怎麼加速啟動Activity。 分兩種情況,啟動應用 和 普通Activity 啟動應用 :Application 的構造方法,onCreate 方法中不要進行耗時操作,資料預讀取(例如 init 資料) 放在非同步中操作 啟動普通的Activity:A 啟動B 時不要在 A 的 onPause 中執行耗時操作。因為 B 的 onResume 方法必須等待 A 的 onPause 執行完成後才能執行
Android記憶體優化方法:ListView優化,及時關閉資源,圖片快取等等。
Android中弱引用與軟引用的應用場景。
Bitmap的四種屬性,與每種屬性隊形的大小。
View與View Group分類。自定義View過程:onMeasure()、onLayout()、onDraw()。
如何自定義控制元件:
-
自定義屬性的宣告和獲取
- 分析需要的自定義屬性
- 在res/values/attrs.xml定義宣告
- 在layout檔案中進行使用
- 在View的構造方法中進行獲取
-
測量onMeasure
-
佈局onLayout(ViewGroup)
-
繪製onDraw
-
onTouchEvent
-
onInterceptTouchEvent(ViewGroup)
-
狀態的恢復與儲存
Android長連線,怎麼處理心跳機制。
View樹繪製流程
下拉重新整理實現原理
你用過什麼框架,是否看過原始碼,是否知道底層原理。
Retrofit
EventBus
glide
Android5.0、6.0新特性。
Android5.0新特性:
- MaterialDesign設計風格
- 支援多種裝置
- 支援64位ART虛擬機器
Android6.0新特性
- 大量漂亮流暢的動畫
- 支援快速充電的切換
- 支援資料夾拖拽應用
- 相機新增專業模式
Android7.0新特性
- 分屏多工
- 增強的Java8語言模式
- 夜間模式
Context區別
- Activity和Service以及Application的Context是不一樣的,Activity繼承自ContextThemeWraper.其他的繼承自ContextWrapper
- 每一個Activity和Service以及Application的Context都是一個新的ContextImpl物件
- getApplication()用來獲取Application例項的,但是這個方法只有在Activity和Service中才能呼叫的到。那麼也許在絕大多數情況下我們都是在Activity或者Service中使用Application的,但是如果在一些其它的場景,比如BroadcastReceiver中也想獲得Application的例項,這時就可以藉助getApplicationContext()方法,getApplicationContext()比getApplication()方法的作用域會更廣一些,任何一個Context的例項,只要呼叫getApplicationContext()方法都可以拿到我們的Application物件。
- Activity在建立的時候會new一個ContextImpl物件並在attach方法中關聯它,Application和Service也差不多。ContextWrapper的方法內部都是轉調ContextImpl的方法
- 建立對話方塊傳入Application的Context是不可以的
- 儘管Application、Activity、Service都有自己的ContextImpl,並且每個ContextImpl都有自己的mResources成員,但是由於它們的mResources成員都來自於唯一的ResourcesManager例項,所以它們看似不同的mResources其實都指向的是同一塊記憶體
- Context的數量等於Activity的個數 + Service的個數 + 1,這個1為Application
IntentService的使用場景與特點。
IntentService是Service的子類,是一個非同步的,會自動停止的服務,很好解決了傳統的Service中處理完耗時操作忘記停止並銷燬Service的問題
優點:
- 一方面不需要自己去new Thread
- 另一方面不需要考慮在什麼時候關閉該Service
onStartCommand中回撥了onStart,onStart中通過mServiceHandler傳送訊息到該handler的handleMessage中去。最後handleMessage中回撥onHandleIntent(intent)。
圖片快取
檢視每個應用程式最高可用記憶體:
int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
Log.d("TAG", "Max memory is " + maxMemory + "KB");
複製程式碼
Gradle
構建工具、Groovy語法、Java
Jar包裡面只有程式碼,aar裡面不光有程式碼還包括程式碼還包括資原始檔,比如 drawable 檔案,xml 資原始檔。對於一些不常變動的 Android Library,我們可以直接引用 aar,加快編譯速度