四大組件之
Activity的生命周期,啟動
Intent和intentFilter
Service的生命周期,兩種編程方式
BroadcastReceiver 廣播接收者
ContentProvider內容提供者
--------------------------------------------------------------------------------
什么是Activity
a,布滿整個窗口或者懸浮于其他窗口上的交互界面
b,一個應用程序中通常有一個或多個Activity構成
b,每個Activity都必須在AndroidManifest.xml中進行申明
c,多個Activity是通過棧進行管理,當前的活動的Activity在棧頂
d,在程序中自定義的Activity必須繼承基類Activity
c,Activity有自己的生命周期,并且在不同的生命周期中會調用不同的函數(shù)
創(chuàng)建方法:
1.定義一個Activity的子類
2.重寫onCreate()
3.定義一個布局視圖
4.將布局視圖關聯(lián)給活動(界面)
5.注冊活動子類到清單文件
四大組件之Activity的生命周期
class 人類{
出生方法(){}
上幼兒方法(){}
上小學(){}
上中學(){}
上大學(){}
工作1(){}
工作2(){}
找對象(){}
成家(){}
去世(){}
}
onCreate(): Activity開始被創(chuàng)建的時候被調用,
主要完成的任務:創(chuàng)建ui視圖,綁定數(shù)據(jù)到list中
onStart(): 當Activity變成可視化的時候被調用,可見了,但還不是可交互的從后臺切換到前臺也會調用
此方法中可以去維護一些顯示在Activity上的資源,比如可以注冊一個BroadcastReceiver,
用于監(jiān)控對UI產(chǎn)生影響的狀態(tài)變化
比如ui上的內容發(fā)生變化,可以通過個BroadcastReceiver去廣播
onResume: 獲取到與用戶交互的焦點,也可以認為是apk正在running
在這里可以做一些動畫的播放,打開獨占設備(比如相機)
onPause: 失去用戶交互的焦點,但是視圖還在,比如另外一個Activity切換到前臺并獲取到焦點時
(一個對話框出現(xiàn),或者是休眠)
在這個方法中執(zhí)行停止動畫等比較耗CPU的操作,或者將需要永久化存儲的數(shù)據(jù)進行保存,
因為有可能不會回來了
onResume和onPause會經(jīng)常切換,所以里面的內容盡量的是輕量級的,以避免導致用戶等待
onStop:表示當前Activity完全被其他的視圖給占用了
onDestrory: 整個Activity完全銷毀的時候,該方法中應該完成釋放資源的操作
3個階段和7個方法
開始階段:onCreate, onStart, onResume
重新獲取焦點: onRestart(); onStart();onResume;
關閉Activity: onPause, onStop,onDestory
Activity獲得與失去焦點的循環(huán):
onPause->onResume->onPause
Activity可見與不可見的循環(huán)
onStart->onRestart->onResume->onPause->onStop
整個生命周期:onCreate-->onDestory
可視周期:
onStart->onStop
焦點周期:
onResume->onPause
在 activity 被停止后重新啟動時(調用打開過的應用程序)調用該方法。
其后續(xù)會調用 onStart 方法
onRestart()
總共7個
-------------------------------------------------
activity創(chuàng)建(onCreate)->可視化(onStart)->獲取焦點(onResume)
|
來了一個電話
onPause(失去焦點)->onStop(失去視圖)
|
接完電話,返回到app
onRestart(重新開始,針對恢復activity)->onStart(可視化)->onResum(獲取焦點)
|
退出activity
onPause(失去焦點)->onStop(失去視圖)->onDestroy(毀滅)
按下返回按鍵:onPause()->onStop()->onDestory()
長按Home鍵,彈出最近打開過的應用程序
按Home鍵:onPause()->onStop()
onRestart():啟動一個另外一個Activity后,由另外一個Activity返回時
===============================================================================
啟動Activity的方式:
1,startActivity();
a,啟動一個自定義的Activity(顯示的啟動)
Intent intent = new Intent(); //創(chuàng)建一個Intent對象
intent.setClass(activity1.this, activity2.class); //描述起點和目標
startActivity(intent); //開始跳轉
b,啟動系統(tǒng)的Activity
String telString = "tel:13800138000";
final Uri telUri = Uri.parse(telString);
String data = "http://www.google.com";
final Uri webUri = Uri.parse(data);
Intent intent = new Intent(Intent.ACTION_VIEW, webUri);
startActivity(intent);
2,啟動另外一個Activity并返回結果--實質也是通過Bundle實現(xiàn)
startActivityForResult(Intent, int requestCode);---------->
參數(shù)2:requestCode請求碼,由程序員自行定義,用于標識請求來源
例如:一個Activity有兩個按鈕,點擊這兩個按鈕會打開不同的Activity
不管哪個Activity關閉后,系統(tǒng)都會調用前面Activity的onActivityResult()
如果需要獲取不同的Activity返回來的數(shù)據(jù),那么可以通過該請求碼進行識別
onActivityResult(int requestCode, int resultCode, Intent)<-----------------
----setResult(Int resultCode);
requestCode:用于區(qū)分到底是哪個請求
resultCode: 結果碼
Intent:包含Bundle,里面有跟多信息
另外一個:
Intent data=new Intent();
data.putExtra("bookname", str_bookname);
data.putExtra("booksale", str_booksale);
setResult(20, data); //
3,啟動activity的時候傳遞數(shù)據(jù): intent作為中介(也可以理解為容器)
a,攜帶Bundle
1,構建Bundle
2,填入數(shù)據(jù)
bundle.putInt("鍵", 值); //普通數(shù)據(jù)
budle.putSerialize("鍵",對象);
3,將Bundle加入到Intent
putExtra(Bundle)
b,鍵值對
putExtra("鍵", 值);
c,獲取數(shù)據(jù)
Intent intent = getIntent();
關閉Activity:
a,關閉當前的activity
finish();
b,關閉以startActivityForResult()方法啟動的Activity
finishActivity(int requestCode);
========================================================================
intent的作用和使用
什么是intent?
a,為一個信息的載體,用于應用間的交互與通訊,對應用中一次操作的動作、動作涉及數(shù)據(jù)、附加數(shù)據(jù)進行
描述,Android則根據(jù)此Intent的描述,負責找到對應的組件,將Intent傳遞給調用的組件,并完成
組件的調用
b,Intent不僅可用于應用程序之間,也可用于應用程序內部的Activity/Service之間的交互
比如啟動另外一個Activity,另外一個Service,還可以發(fā)送廣播給BoardcastReciver
c,intent的屬性--表示要做什么,帶了一些什么信息
Intent主要有以下四個重要屬性,它們分別為:
0,Component name:表示該intent是交給哪個具體的Component組件的(該對象是可選的,同時也可以不用intent-filter)
在代碼中需要如下操作:
ComponentName comp = new ComponentName(xxx類.this, 另一個Activity的this);
Intent intent = new Intent();
intent.setComponent(comp);
StartActivity(Intent);
Action 和Category,在啟動的組件中需要有intent-filter
1,Action:值為一個字符串,它代表了系統(tǒng)中已經(jīng)定義了一系列常用的動作
a,系統(tǒng)自帶的常量:ACTION_CALL,ACTION_EDIT
b,自定義的字符串,一般格式:"包名.類名.特定的字符"
2,Category:組件的類別,用于描述哪一類的組件可以處理該Intent,也是一個字符串,為Action添加的附加信息,通常會和Action結合使用
一個Intent只能指定一個Action,但可以指定多個Category
CATEGORY_DEFAULT :默認的category
CATEGORY_LAUNCHER:決定應用程序是否顯示在程序列表里,表示在luncher中可否啟動該組件
CATEGORY_BROWSABLE :在網(wǎng)頁上點擊圖片或鏈接時,系統(tǒng)會考慮將此目標Activity列入可選列表,
供用戶選擇以打開圖片或鏈接。比如有個網(wǎng)頁鏈接,你的系統(tǒng)裝了很多瀏覽器,此時會列舉出多個打開方式
3,Data:Android中采用指向數(shù)據(jù)的一個URI來表示,如在聯(lián)系人應用中,
對于不同的動作,其URI數(shù)據(jù)的類型是不同的(可以設置type屬性指定特定類型數(shù)據(jù)),
如ACTION_EDIT指定Data為文件URI,打電話為tel:URI,訪問網(wǎng)絡為http:URI,
而由content provider提供的數(shù)據(jù)則為content: URIs。一個指向某聯(lián)系人的URI可能為:content://contacts/1。
4,Extras:Extras屬性主要用于傳遞目標組件所需要的額外的數(shù)據(jù)。通過putExtras()方法設置。常用于在多個Action之間進行數(shù)據(jù)交換
public void invokeWebSearch(View view) {
Intent intent = new Intent(Intent.ACTION_WEB_SEARCH);
intent.putExtra(SearchManager.QUERY, "android"); //關鍵字
startActivity(intent);
}
以上一般比較重要的是:
action
data (both URI and data type)
category
Intent被解析的過程:顯示intent和隱式intent
顯示intent:明確指定需要啟動或者觸發(fā)的組件的類名,常用于啟動當前應用程序的不同組件
類似與找人: 找章子怡
隱式intent:指定需要啟動或者觸發(fā)的組件應滿足怎樣的條件,常用于啟動其他應用程序中的組件
也就是說系統(tǒng)會對intent進行解析,解析出它的條件
然后再在系統(tǒng)中查找與之匹配的目標組件
而被調用或目標組件需要通過intentfilter來聲明自己滿足條件
類似與找人: 穿紅衣服的女孩
Intent-filter:組件的意圖過濾器,
a,其實是一個對象,但是一般不會直接去創(chuàng)建,都是在AndroidManifest.xml中存在
b,一個組件中可以有多個Intent-filter,可以根據(jù)過濾不同的intent而采取不同的處理
c,過濾的時候會過濾三個域:action,data,category,任何intent必須成功經(jīng)過這三道過濾,缺一不可
Action test:至少有一個
<intent-filter . . . >
<action android:name="com.example.project.SHOW_CURRENT" />
<action android:name="com.example.project.SHOW_RECENT" />
<action android:name="com.example.project.SHOW_PENDING" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
必須添加一個android.intent.category.DEFAULT
c,隱式的啟動:
在intent添加過濾器intentfilter
<activity <!--被啟動的Activity -->
android:name="com.example.android.tst.SecondActivity"
android:label="@string/title_activity_main" >
<intent-filter>
<action android:name="com.example.android.tst.SecondActivity"/>
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
啟動方法:
Intent intent=new Intent("com.example.android.tst.SecondActivity");
//或者如下操作
//intent.setAction( "com.example.android.tst.SecondActivity");
//intent.addCategory(Intent.CATEGORY_DEFAULT);
startActivity(intent);
解釋:
發(fā)送了這個intent之后,android會去系統(tǒng)里保存的MainManifest.xml里查找符
合這兩個屬性的activity,
任何一個需要隱式啟動的Activity都必須要有這項:
<category android:name="android.intent.category.DEFAULT"/>
==========================================================================
Service在Android中和Activity是屬于同一級別上的組件
Activity儀表不凡,迷倒萬千少女
Service身強力壯,但是在后臺做一些搬運工的力氣活
后臺運行
Service的特性:
1, 擁有后臺運行的特性,比如將屏幕關閉后,繼續(xù)運行
2,不是一個獨立的進程,除非特別指定(存在于一個進程中)
3,它不是一個線程
4,服務是一種 應用程告訴系統(tǒng)它想在后臺要做的某個事情 的工具,并將功能提供(暴露)給其它應用程序
Service的應用場合:
從播放列表播放音樂,播放器有一些activities來叫用戶選定歌曲并開始播放。但是,播放本身不需要activity處理,因為用戶希望關閉activity
后歌曲會繼續(xù)播放。因此media player 的activity 會啟動一個service
Service和Thread的區(qū)別:
1,Thread 是程序執(zhí)行的最小單元,它是分配CPU的基本單位,而Service是一個組件,你也可以認為是應用程序的一個插件
這個插件能完成后臺的操作
2,Service其實是運行在主線程中的,如果需要執(zhí)行復雜耗時的操作,必須在Service中再創(chuàng)建一個Thread來執(zhí)行任務
3,Service的優(yōu)先級高于后臺掛起的Activity,當然,也高于Activity所創(chuàng)建的Thread,因此,系統(tǒng)可能在內存不足的時候優(yōu)先殺死后臺
的Activity或者Thread,而不會輕易殺死Service組件,即使被迫殺死Service,也會在資源可用時重啟被殺死的Service
4,Thread只是一個用來執(zhí)行后臺任務的工具類,它可以在Activity中被創(chuàng)建,也可以在Service中被創(chuàng)建。
所以不需要去疑惑使用Service還是Thread,而是應該討論在什么地方創(chuàng)建Thread。
Service的兩種啟動方式:
context.startService()-- 對應于Local Service(本地服務,調用和實現(xiàn)在同一個進程)
依附在主進程上而不是獨立的進程,這樣在一定程度上節(jié)約了資源,另外Local服務因為是在同一進程因此不需要IPC
主進程被Kill后,服務便會終止。
context.bindService()-- 對應于Remote Service(遠程服務,調用和實現(xiàn)不在同一個進程)
由于是獨立的進程,因此在Activity所在進程被Kill的時候,該服務依然在運行,不受其他進程影響,有利于為多個進程
提供服務具有較高的靈活性。該服務是獨立的進程,會占用一定資源,并且使用AIDL進行IPC稍微麻煩一點
Service的生命周期:
本地服務:
啟動一個Service的過程
context.startService() ->onCreate()->onStartCommand()->Servicerunning
startService()在Activity中啟動服務,實際是并實例化了一個Service實例
onCreate() 進行一些服務的初始化工作,比如可以創(chuàng)建一個線程用于播放音樂
onStartCommand():服務正常運行時,能夠處理Intent,如果多多次啟動服務,該方法會被調用
在以前的版本該方法為onStart();onStartCommand()內部會被調用,已經(jīng)過時了
停止一個Service的過程:
context.stopService() ->onDestroy() ->Service stop
Activity調用這即使結束了自己的生命周期,只要沒有使用stopService方法停止這個服務,服務仍會運行
遠程服務: 遠程服務其實就是給外部apk提供各種接口
啟動一個Service的過程
context.bindService()-->onCreate()-->onBind()-->Servicerunning
onBind():當綁定成功時,該方法被調用,并且需要返回一個binder接口的實例
如果重復綁定,該方法只會執(zhí)行一次
停止一個Service的過程:
context.unbindService()-->onUnBinde()-->onDestroy()-->Service stop
bindService模式下服務是與調用者生死與共的,在綁定結束之后,一旦調用者被銷毀,服務也就立即終止,
就像江湖上的一句話:不求同生,但愿同死,當然羅,如果要繼續(xù)用服務,再bind就好了, 服務會跟著運行起來的
aidl: 實際是一個工具,幫我們自定生成一些代碼,完成進程調度的細節(jié)代碼
只需要定義好service段和調用端直接的接口就可以了
package com.hq.service;
interface IService{ //一定要文件的名字保持一致,文件名一定要是aidl的后綴
int add(int a, int b);
int sub(int a, int b);
}
1,在服務端里實現(xiàn)接口:
public class MyService extends Service{
public IBinder onBind(Intent arg0)
{
// TODO Auto-generated method stub
Log.i(TAG, "------onBind--------");
//如果需要綁定成功,就一定要返回一個binder的子類
return new IServiceImpl();
}
// 實現(xiàn)用戶提供的接口,定義一個內部類
public class IServiceImpl extends IService.Stub{
public int add(int a, int b) throws RemoteException
{
// TODO Auto-generated method stub
return a+b;
}
@Override
public int sub(int a, int b) throws RemoteException
{
// TODO Auto-generated method stub
return a-b;
}
}
}
2,在client中進行調用:
bindService(intent3, serviceConnection, Service.BIND_AUTO_CREATE); //啟動服務
//參數(shù)2: 當綁定成功之后,需要做的事情:
private ServiceConnection serviceConnection = new ServiceConnection(){
public void onServiceConnected(ComponentName name, IBinder iBinder){
//通過IService中將ibider統(tǒng)一的接口轉換成自己定義的接口對象
serviceManager = IService.Stub.asInterface(iBinder);
serviceManager.add(34, 56) //直接調用
}
}
MediaPlayer media;
media = MediaPlayer.create(MyService.this,R.raw.nobody);
media.start();
media.stop();
------------------------------------------------------------------------------------------------------------------------------------
BroadcastReceiver也就是“廣播接收者”的意思,顧名思義,它就是用來接收來自系統(tǒng)和應用中的廣播
廣播體現(xiàn)在方方面面,例如
當開機完成后系統(tǒng)會產(chǎn)生一條廣播,接收到這條廣播就能實現(xiàn)開機啟動服務的功能;
當網(wǎng)絡狀態(tài)改變時系統(tǒng)會產(chǎn)生一條廣播,接收到這條廣播就能及時地做出提示和保存數(shù)據(jù)等操作;
當電池電量改變時,系統(tǒng)會產(chǎn)生一條廣播,接收到這條廣播就能在電量低時告知用戶及時保存進度,等等。
廣播的發(fā)送:
普通廣播:
對于多個接收者來說是完全異步的,通常每個接收者都無需等待即可以接收到廣播,接收者相互之間不會有影響。對于這種廣播,
接收者無法終止廣播, 即無法阻止其他接收者的接收動作。
sendBroadcast(intent);
abortBroadcast();
有序廣播:
它每次只發(fā)送到優(yōu)先級較高的接收者那里,然后由優(yōu)先級高的接受者再傳播到優(yōu)先級低的接收者那里,優(yōu)先級高的接收者有能力終止這個廣播
sendOrderedBroadcast(intent, "george.permission.MY_BROADCAST_PERMISSION");
參數(shù)中有個權限,所以
在AndroidMainfest.xml中定義一個權限:
<permission android:protectionLevel="normal"
android:name="george.permission.MY_BROADCAST_PERMISSION" />
如果要發(fā)送廣播,必須要獲取到這個權限:
<uses-permission android:name="george.permission.MY_BROADCAST_PERMISSION" />
過濾器的配置:
1,靜態(tài):在AndroidManifest.xml文件中配置,這種方式的注冊是常駐型的,也就是說當應用關閉后,
如果有廣播信息傳來,MyBroadCastReceiver也會被系統(tǒng)調用而自動運行
<receiver android:name="com.hq.component.broadcast.MyBroadCastReceiver" >
<intent-filter android:priority="999" >
<action android:name="broadcast.MyBroadCastReceiver" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
2,動態(tài):在代碼中動態(tài)的指定廣播地址并注冊,通常我們是在Activity或Service注冊一個廣播
不是常駐型的,也就是說廣播會跟隨程序的生命周期
private ThirdBroadCastReceiver receiver = null;
//新建一個廣播接收器
receiver = new ThirdBroadCastReceiver();
//新建一個過濾器
IntentFilter filter = new IntentFilter();
filter.addAction("broadcast.MyBroadCastReceiver");
filter.setPriority(997);
//為廣播接受器注冊一個過濾器
registerReceiver(receiver, filter);
廣播的接收:
普通廣播:
intent.getExtras();
有序廣播:
接受
String extraStr = getResultExtras(true).getString("passMsg");
繼續(xù)傳播:
// 給下個廣播接受者傳遞廣播
Bundle bundle = new Bundle();
bundle.putString("passMsg", intentStr + "from @SecondBroadCastReceiver");
setResultExtras(bundle);
停止傳播:
abortBroadcast();
最后編輯于 :
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。