onCreate()
,而後調用onstart()
,最後調用onResume()
,Activity 就此進入運行狀態。onPause()
,而後調用onStop()
,最後調用onDestroy()
,Activity 就此銷燬。onPause()
、onStop()
, 從新回到 Activity,依次執行onRestart()
、onStart()
、onResume()
(Activity 不被回收的狀況下)。onPause()
,回到前臺執行onResume()
。onCreate()
、onStart()
、onResume()
。onPause()
,而後新 Activity 再啓動。onStart()
、onStop()
。onResume()
、onPause
。注意:當 Activity 彈出對話框時,並不會回調onPause
,可是會回調onStop()
。android
當系統內存不足,或者系統配置發生改變(如旋轉方向),Activity 會被殺死。數據庫
onSaveInstanceState()
來保存當前 Activity 的狀態,這個方法的調用時機是在onStop()
以前,當 Activity 從新建立後,系統會把銷燬時保存的 Bundle 對象做爲參數傳遞給onCreate()
和onRestoreInstanceState()
,建議在onRestoreInstanceState()
中作數據恢復,畢竟專門用來恢復實例狀態的。另外,每一個 View 自己都有onSaveInstanceState()
和onRestoreInstanceState()
方法,所以系統都會默認恢復 View 的基本狀態。android:configChanges="orientation"
,彷佛有些設備須要多指定一個參數,即android:configChanges:="orientaion|screenSize"
。總共 4 種啓動模式:Standard,SingleTop,SingleTask,SingleInstance。安全
onNewIntent()
方法會被回調,其他生命週期方法均不會回調。onNewIntent()
。此外,位於此 Activity 之上的全部 Activity 均會出棧,此時 Activity 位於棧頂。注意:默認狀況下,全部 Activity 所需的任務棧的名字爲應用的包名,能夠在 AndroidManifest.xml 中經過android:taskAffinity=""
來指定任務棧。bash
被啓動的 Service 默認是在主線程下工做的,所以若是須要執行耗時操做,應當另開一個子線程來執行,以避免阻塞主線程致使出現 ANR(Application Not Response)。任何 Activity 均可以控制同一個 Service,而且系統中也只會存在一個 Service 實例。網絡
stopService()
或者在在 Service 類中調用stopSelf()
,服務纔會中止,Activity 沒法與 Service 進行通訊。onCreate
中能夠作一些初始化,onStartCommand()
中放置執行任務的代碼,onDestroy()
中進行資源的釋放。onCreate()
->onStartCommand()
->onDestroy()
,當 Service 已經被啓動後,不管執行多少次startServvice()
,都不會走onCreate()
,而是會調用onStartCommand()
。unbindService()
中止。這種模式下能夠進行 Activity 和 Service 的通訊。onCreate()
->onBind()
->onUnbind()
->onDestroy()
,onStartCommand()
不會有調用機會。注意:當startService()
和bindService()
一塊兒被調用後,若想中止服務,必須同時調用stopService()
和unbindService()
,這樣服務纔會中止,順序沒有嚴格要求,但必定要同時調用。異步
示例:ide
public class MyService extends Service {
private static final String TAG = "MyService";
private IBinder mBinder;
@Override
public IBinder onBind(Intent intent) {
if (mBinder == null) {
mBinder = new MyBinder();
}
Log.d(TAG, "-----onBind()-----");
return mBinder;
}
@Override
public boolean onUnbind(Intent intent) {
Log.d(TAG, "-----onUnbind()-----");
return super.onUnbind(intent);
}
@Override
public void onCreate() {
super.onCreate();
Log.d(TAG, "-----onCreate()-----");
}
@Override
public void onDestroy() {
super.onDestroy();
Log.d(TAG, "-----onDestroy()-----");
}
public class MyBinder extends Binder {
// 這裏能夠定義想要通訊的方法,在 Activity 中能夠經過 Binder 實例調用
public void print(String data) {
Log.d(TAG, "print: " + data);
}
}
}
複製代碼
<!--android:enabled 表示是否啓用,android:exported 表示是否向外界公開-->
<service
android:name=".MyService"
android:enabled="true"
android:exported="false" />
複製代碼
public class MainActivity extends AppCompatActivity {
private ServiceConnection mConnection;
private MyService.MyBinder mBinder;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mConnection = new MyConnection();
initView();
}
@Override
protected void onDestroy() {
super.onDestroy();
unbindService(mConnection);
}
private void initView() {
Button bindService = findViewById(R.id.btn3);
Button unbindService = findViewById(R.id.btn4);
bindService.setOnClickListener(view -> {
bindService(new Intent(MainActivity.this, MyService.class), mConnection, BIND_AUTO_CREATE);
});
unbindService.setOnClickListener(view -> {
unbindService(mConnection);
});
}
private class MyConnection implements ServiceConnection {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
// 轉換爲本身定義的 Binder
mBinder = (MyService.MyBinder) service;
// 調用本身定義的方法進行通訊
mBinder.print("成功通訊");
}
@Override
public void onServiceDisconnected(ComponentName name) {
// 這個方法只有在出現異常的時候纔會被系統調用
}
}
}
複製代碼
服務幾乎都是在後臺運行的,系統優先級相對比較低,當系統出現內存不足時就容易被回收,若是但願服務能夠一直保持運行狀態,不會由於內存不足而被回收,這時就可使用前臺服務。與普通服務不一樣,前臺服務會有一個正在運行的圖標在通知欄裏顯示,相似通知。例如騰訊手機管家等通知,會在通知欄顯示此時手機的內存狀態等。學習
示例:在 Service 中經過startForeground()
建立前臺服務,而後在 Activity 中經過startService()
或bindService()
開啓,經過stopService()
或unbindService()
關閉。ui
public class MyService extends Service {
private static final String TAG = "MyService";
private IBinder mBinder;
@Override
public void onCreate() {
super.onCreate();
createForegroundService();
}
private void createForegroundService() {
Intent intent = new Intent(this, MainActivity.class);
PendingIntent pi = PendingIntent.getActivity(this, 0, intent, 0);
Notification notification;
// 使用了建造者模式,將須要定義到的部分提早設置好
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, "Channel_1")
.setContentTitle("前臺服務")
.setContentText("This is content text")
.setWhen(System.currentTimeMillis())
.setSmallIcon(R.mipmap.ic_launcher)
.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher))
.setContentIntent(pi);
// 由於 Android 8.0 添加了 NotificationChannel(通知渠道)
// 所以須要適配,否則在 8.0 上會顯示不了通知
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
NotificationChannel channel = new NotificationChannel("Channel_1", "前臺服務", NotificationManager.IMPORTANCE_DEFAULT);
manager.createNotificationChannel(channel);
notification = builder.build();
} else {
notification = builder.build();
}
startForeground(1, notification);
}
......
}
複製代碼
在前面就知道了,普通服務默認是運行在主線程中的,若是在服務裏執行一些耗時操做就容易出現 ANR,固然也能夠本身另開線程來執行,而後在合適的時機在 Service 內部調用stopSelf()
來中止。可是這樣稍顯麻煩,爲了能夠簡單地建立一個異步的、會自動中止的 Service,Android 提供了 IntentService 類,很好地解決了這個問題。this
onHandleIntent()
方法便可,在這個方法中即可以處理耗時操做,而且當執行完畢後,Service 會自動中止。示例:
public class MyIntentService extends IntentService {
public MyIntentService() {
// 必須調用父類有參構造
super("MyIntentService");
}
@Override
protected void onHandleIntent(Intent intent) {
Log.d("MyIntentService", "currentThread: " + Thread.currentThread().getName());
}
@Override
public void onDestroy() {
super.onDestroy();
Log.d("MyIntentService", "-----onDestroy()-----");
}
}
複製代碼
因爲遠程服務我並不熟悉,這裏就先落下了,後面學習了再補充上去。
sendBroadcast(intent)
—— 表示發送標準廣播sendOrderedBroadcast(intent, null)
—— 表示發送有序廣播abortBroadcast()
—— 表示截斷接收到的廣播注意: BroadcastReceiver 生命週期很短, 若是須要在
onReceiver()
完成一些耗時操做,應該考慮在 Service 中開啓一個新線程處理耗時操做,不該該在 BroadcastReceiver 中開啓一個新的線程,由於 BroadcastReceiver 生命週期很短,在執行完 onReceiver 之後就結束,若是開啓一個新的線程,可能出現 BroadcastRecevier 退出之後線程還在,而若是 BroadcastReceiver 所在的進程結束了,該線程就會被標記爲一個空線程,根據 Android 的內存管理策略,在系統內存緊張的時候,會按照優先級,結束優先級低的線程,而空線程無異是優先級最低的,這樣就可能致使 BroadcastReceiver 啓動的子線程不能執行完成。
onReceive()
方法,調用 addAction()
添加 action 值,當網絡狀態發生變化時,系統發出的正式一條值爲 android.net.conn.CONNECTIVITY_CHANGE
的廣播,想要監聽什麼廣播便添加相應的 action 值。最後,動態註冊的接受器必定要取消註冊。public class MainActivity extends AppCompatActivity {
private IntentFilter intentFilter;
private NetworkChangeReceiver networkChangeReceiver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
intentFilter = new IntentFilter();
intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");
networkChangeReceiver = new NetworkChangeReceiver();
registerReceiver(networkChangeReceiver, intentFilter);
}
@Override
protected void onDestroy(){
super.onDestroy();
unregisterReceiver(networkChangeReceiver);
}
class NetworkChangeReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent){
ConnectivityManager manager = (ConnectivityManager)
getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = manager.getActiveNetworkInfo();
if(networkInfo != null && networkInfo.isAvailable()){
Toast.makeText(context, "網絡沒毛病", Toast.LENGTH_SHORT).show();
}else{
Toast.makeText(context, "網絡不可用", Toast.LENGTH_SHORT).show();
}
}
}
}
複製代碼
在 onReceive()
方法中,經過 getSystemService()
方法獲得了 ConnectivityManager 的實例,這是一個系統服務類,專門用於管理網絡鏈接。而後調用它的 getActiveNetworkInfo()
方法能夠獲得 NetworkInfo 的實例,接着調用 NetworkInfo 的 isAvailable()
方法便可判斷當前是否有網絡。
最後須要在 AndroidManifest.xml 中註冊訪問系統網絡狀態權限。
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<receiver
android:name=".BootCompleteReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter>
</receiver>
複製代碼
本地廣播用了一個 LocalBroadcastManager 來對廣播進行管理,並提供了發送廣播和註冊廣播接收器的方法。另外,本地廣播是沒法經過靜態註冊的方式來接收的
public class MainActivity extends AppCompatActivity {
private IntentFilter intentFilter;
private LocalReceiver localReceiver;
private LocalBroadcastManager localBroadcastManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
localBroadcastManager = LocalBroadcastManager.getInstance(this);
Button button = findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent =
new Intent("com.example.broadcasttest.LOCAL_BROADCAST");
localBroadcastManager.sendBroadcast(intent);
}
});
intentFilter = new IntentFilter();
intentFilter.addAction("com.example.broadcasttest.LOCAL_BROADCAST");
localReceiver = new LocalReceiver();
localBroadcastManager.registerReceiver(localReceiver, intentFilter);
}
@Override
protected void onDestroy(){
super.onDestroy();
localBroadcastManager.unregisterReceiver(localReceiver);
}
class LocalReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent){
// 編寫邏輯操做
}
}
}
複製代碼
ContentProvider 是 Android 四大組件之一的內容提供器,它主要的做用就是將程序的內部的數據和外部進行共享,爲數據提供外部訪問接口,被訪問的數據主要以數據庫的形式存在,並且還能夠選擇共享哪一部分的數據。這樣一來,對於程序當中的隱私數據能夠不共享,從而更加安全。ContentProvider 是 Android 中一種跨程序共享數據的重要組件。
系統的 ContentProvider 有不少,如通話記錄,短信,通信錄等等,都須要和第三方的 App 進行共享數據。既然是使用系統的,那麼 ContentProvider 的具體實現就不須要咱們擔憂了,使用內容提供者的步驟以下:
能夠經過讀取系統通信錄的聯繫人信息,顯示在Listview中來實踐這些知識。不要忘記在讀取通信錄的時候,在清單文件中要加入相應的讀取權限。
系統的 ContentProvider 在與咱們交互的時候,只接受了一個 Uri 的參數,而後根據咱們的操做返回給咱們結果。系統究竟是如何根據一個 Uri 就可以提供給咱們準確的結果呢?只有本身親自實現一個看看了。和以前提到的同樣,想從新自定義本身程序中的四大組件,就必須從新實現一個類,重寫這個類中的抽象方法,在清單文件中註冊,最後纔可以正常使用。
從新實現 ContentProvider 以後,發現咱們重寫了 6 個重要的抽象方法
onCreate()
query()
update()
insert()
delete()
getType()
大部分的方法在數據庫那裏已經見過了,他們內部的邏輯可想而知都是對數據的增刪改查操做,其中這些方法的第一個參數大多都是 Uri 實例。其中有兩個方法比較特殊:
onCreate()
方法應該是內容提供者建立的時候所執行的一個回調方法,負責數據庫的建立和更新操做。這個方法只有咱們在程序中獲取 ContentResolver 實例以後準備訪問共享數據的時候,纔會被執行。
getType()
方法是獲取咱們經過參數傳遞進去的 Uri 的 MIME 類型,這個類型是什麼,後面會有實例說明。
內容提供者首先要作的一個事情就是將咱們傳遞過來的 Uri 解析出來,肯定其餘程序到底想訪問哪些數據。Uri 的形式通常有兩種:
content://com.demo.androiddemo.provider/table1
標識咱們要訪問 table1 表中全部的數據。content://com.demo.androiddemo.provider/table1/1
標識咱們要訪問 table1 表中 _id 列值爲 1 的數據。若是是內容提供器的設計者,那麼咱們確定知道這個程序的數據庫是什麼樣的,每一張表,或者每一張表中的 _id 都應該有一個惟一的內容 Uri 。咱們能夠將傳遞進來的 Uri 和咱們存好的 Uri 進行匹配,匹配到了以後,就說明數據源已經找到,即可以進行相應的增刪改查操做。
四大組件的學習能夠參考第一行代碼裏面的知識點,都是比較基礎的東西,本身碼出來練習練習便可,不必死記,須要用到時腦殼裏有這麼個印象而後知道哪裏能夠查就好了,長此以往天然而然就記住了。