一、靜態註冊 ,在Manifest文件的application
節點中配置廣播接收者java
<receiver android:name=".MyBroadCastReceiver">
<!-- android:priority屬性是設置此接收者的優先級(從-1000到1000) -->
<intent-filter android:priority="20">
<actionandroid:name="android.provider.Telephony.SMS_RECEIVED"/>
</intent-filter>
</receiver>
複製代碼
二、動態註冊,經過Context
對象的registerReceiver
方法註冊廣播android
//new出上邊定義好的BroadcastReceiver
MyBroadCastReceiver yBroadCastReceiver = new MyBroadCastReceiver();
//實例化過濾器並設置要過濾的廣播
IntentFilter intentFilter = new IntentFilter("android.provider.Telephony.SMS_RECEIVED");
//註冊廣播
myContext.registerReceiver(smsBroadCastReceiver,intentFilter,
"android.permission.RECEIVE_SMS", null);
複製代碼
區別:靜態註冊的爲常駐型廣播,即便應用程序關閉了,若是又信息廣播來,程序也會被系統調用執行。而動態註冊的廣播不是常駐型,廣播被取消註冊或者應用程序關閉後都不能接收安全
一、有序廣播:按照優先級,一級一級向下傳遞,接收者能夠修改廣播數據,也能夠終止廣播事件。app
二、無序廣播:全部接收者都會接收事件,不能被攔截跟修改。ide
一、使用Context
的startService
方法啓動函數
onCreate()
--->onStartCommand()
--->onDestroy()
oop
二、使用Context
的bindService
方法啓動佈局
onCreate()
--->onBind()
--->onUnBind()
--->onDestroy()
this
一、在外部使用stopService
方法,若是使用bindService
的方式啓動,則使用unbindService
方法中止spa
二、在Service
內部(onStartCommand
方法內)使用stopSelf
onStartCommand
方法的返回值一、START_NOT_STICKY
:「非粘性的」。使用這個返回值時,若是在執行完onStartCommand
方法後,服務被異常kill掉,系統不會自動重啓該服務
二、START_STICKY
:若是Service進程被kill掉,保留Service的狀態爲開始狀態,但不保留遞送的intent對象。隨後系統會嘗試從新建立Service,因爲服務狀態爲開始狀態,因此建立服務後必定會調用onStartCommand(Intent,int,int)方法。若是在此期間沒有任何啓動命令被傳遞到Service,那麼參數Intent將爲null。
三、START_REDELIVER_INTENT
:重傳Intent。使用這個返回值時,系統會自動重啓該服務,並將Intent的值傳入。
繼承於Service
,啓動方式與Service
的傳統啓動方式同樣,不一樣點在於內部有一個線程來處理耗時操做,當任務執行完成時服務會自動中止。
standard
:標準模式,默認的啓動模式,不論是否已經存在實例都會生成新的實例
singleTop
:棧頂複用模式,若是發現有對應Activity的實例正位於棧頂,則直接打開此頁面,再也不生成新的實例,同時onNewIntent
方法會被執行,onCreate
跟onStart
方法都不會執行。不然跟standard
模式同樣繼續生成新的實例。
singleTask
:站內複用模式,若是棧內存在對應Activity的實例就會複用這個Activity,複用時會將它上面的Activity所有出棧,同時onNewIntent
方法也會被執行。
singleInstance
:單例模式,該模式具有singleTask模式的全部特性外,與它的區別就是,這種模式下的Activity會單獨佔用一個Task棧,具備全局惟一性。以singleInstance模式啓動的Activity在整個系統中是單例的,若是在啓動這樣的Activiyt時,已經存在了一個實例,那麼會把它所在的任務調度到前臺,重用這個實例。
app啓動的過程有兩種狀況,第一種是從桌面launcher上點擊相應的應用圖標,第二種是在activity中經過調用startActivity來啓動一個新的activity。
Luncher.startActivitySafely()
public final class Launcher extends Activity implements View.OnClickListener, OnLongClickListener, LauncherModel.Callbacks, AllAppsView.Watcher { ...... void startActivitySafely(Intent intent, Object tag) { intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); try { startActivity(intent); } catch (ActivityNotFoundException e) { ...... } catch (SecurityException e) { ...... } } ...... } 複製代碼
Activity.startActivity
public class Activity extends ContextThemeWrapper implements LayoutInflater.Factory, Window.Callback, KeyEvent.Callback, OnCreateContextMenuListener, ComponentCallbacks { ...... @Override public void startActivity(Intent intent) { startActivityForResult(intent, -1); } ...... } 複製代碼
Activity.startActivityForResult
public class Activity extends ContextThemeWrapper implements LayoutInflater.Factory, Window.Callback, KeyEvent.Callback, OnCreateContextMenuListener, ComponentCallbacks { ...... public void startActivityForResult(Intent intent, int requestCode) { if (mParent == null) { Instrumentation.ActivityResult ar = mInstrumentation.execStartActivity( this, mMainThread.getApplicationThread(), mToken, this, intent, requestCode); ...... } else { ...... } ...... } 複製代碼
Instrumentation.execStartActivity
public class Instrumentation { ...... public ActivityResult execStartActivity( Context who, IBinder contextThread, IBinder token, Activity target, Intent intent, int requestCode) { IApplicationThread whoThread = (IApplicationThread) contextThread; if (mActivityMonitors != null) { ...... } try { int result = ActivityManagerNative.getDefault() .startActivity(whoThread, intent, intent.resolveTypeIfNeeded(who.getContentResolver()), null, 0, token, target != null ? target.mEmbeddedID : null, requestCode, false, false); ...... } catch (RemoteException e) { } return null; } ...... } 複製代碼
這裏的
ActivityManagerNative.getDefault
返回ActivityManagerService
的遠程接口,即ActivityManagerProxy
接口
ActivityManagerProxy.startActivity
class ActivityManagerProxy implements IActivityManager { ...... public int startActivity(IApplicationThread caller, Intent intent, String resolvedType, Uri[] grantedUriPermissions, int grantedMode, IBinder resultTo, String resultWho, int requestCode, boolean onlyIfNeeded, boolean debug) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); data.writeInterfaceToken(IActivityManager.descriptor); data.writeStrongBinder(caller != null ? caller.asBinder() : null); intent.writeToParcel(data, 0); data.writeString(resolvedType); data.writeTypedArray(grantedUriPermissions, 0); data.writeInt(grantedMode); data.writeStrongBinder(resultTo); data.writeString(resultWho); data.writeInt(requestCode); data.writeInt(onlyIfNeeded ? 1 : 0); data.writeInt(debug ? 1 : 0); mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0); reply.readException(); int result = reply.readInt(); reply.recycle(); data.recycle(); return result; } ...... } 複製代碼
ActivityManagerService.startActivity
Context是一個抽象基類,翻譯爲上下文,也能夠理解爲環境,提供一些程序運行基礎信息。
Context有兩個子類,ContextWrapper
是上下文功能的封裝類,而 ContextImpl
則是上下文功能的實現類。而 ContextWrapper
又有三個直接的子類, ContextThemeWrapper
、Service
和Application
。其中,ContextThemeWrapper
是一個帶主題的封裝類,而它有一個直接子類就是Activity,因此Activity和Service以及Application的Context是不同的,只有Activity須要主題,Service不須要主題。Context一共有三種類型,分別是Application、Activity和Service。這三個類雖然分別各類承擔着不一樣的做用,但它們都屬於Context的一種,而它們具體Context的功能則是由ContextImpl
類去實現的,所以在絕大多數場景下,Activity、Service和Application這三種類型的Context都是能夠通用的。不過有幾種場景比較特殊,好比啓動Activity,還有彈出Dialog。出於安全緣由的考慮,Android是不容許Activity或Dialog憑空出現的,一個Activity的啓動必需要創建在另外一個Activity的基礎之上,也就是以此造成的返回棧。而Dialog則必須在一個Activity上面彈出(除非是System Alert類型的Dialog),所以在這種場景下,咱們只能使用Activity類型的Context,不然將會出錯。
Activity
構造的時候會初始化一個Window( PhoneWindw
)PhoneWindow
有一個 RootView
,這個RootView
是一個ViewGroup,是最初始的根視圖RootView
經過 addView
方法來一個個添加 View
View的繪製流程:onMeasure
-> onLayout
-> onDraw
第一步:onMeasure
測量視圖大小,從頂層父View到子View遞歸調用 measure
方法,measure
方法又回調 onMeasure
方法。
第二步:onLayout
肯定View位置,進行頁面佈局。從頂層父View向子View遞歸調用 layout
方法的過程,即父View根據上一步 measure
獲得的佈局大小和佈局參數,將子View放在合適的位置上。
第三步:onDraw
繪製視圖。主要步驟爲①:繪製背景,②:繪製本身,③:繪製子View,④:繪製滾動條
ViewGroup 包含 dispatchTouchEvent
、onInterceptTouchEvent
、onTouchEvent
三個相關方法,View包含 dispatchTouchEvent
、onTouchEvent
兩個相關方法。
Activity
接收到Touch事件時,將遍歷子View進行Down事件分發,分發的目的是爲了找到真正處理本次完整觸摸事件的View,這個View會在 onTouchEvent
返回true。onTouchEvent
事件。觸發的方式是調用 super.dispatchTouchEvent
函數,即調用父View的dispatchTouchEvent
方法。Android的主線程不能進行耗時操做,子線程不能進行更新UI,因此就有了Handler,它的做用就是實現線程之間的通訊。
Handler整個流程中主要有四個對象:Handler
、Message
、MessageQueue
、Looper
。經過將要傳遞的消息放在Message
中,Handler
經過 sendMessage
方法將消息放入 MessageQueue
中,Looper
對象會不斷的調用loop()
方法不斷從 MessageQueue
中取出 Message
交給 Handler
進行處理。
內存泄漏跟內存溢出的區別:
內存泄漏的緣由:
Handler引發的內存泄漏:
將Handler聲明爲靜態內部類,就不會持有外部類的引用,其生命週期就跟外部類無關。若是Handler內部要使用Context,則可使用弱引用的方式。
單例模式引發的內存泄漏:
Context是ApplicationCotnext,ApplicationCotnext的生命週期與app一致,不會致使內存泄漏.
非靜態內部類建立實例引發的:
建立爲靜態實例
非靜態匿名內部類引發的:
將匿名內部類修改成靜態的
註冊/反註冊未成對使用引發的內存泄漏
註冊廣播接受器、EventBus等,記得解綁
資源對象沒有關閉引發的內存泄漏
在這些資源不使用的時候,記得調用相應的相似close()、destroy()、recycler()、release()等方法釋放
集合對象沒有及時清理引發的內存泄漏
一般會把一些對象裝入到集合中,當不使用的時候必定要記得及時清理集合,讓相關對象再也不被引用
內存泄漏檢測:LeakCanary
ANR全名"Application not responding",即應用無響應。產生的緣由: