1. 請(qǐng)描述下Activity的生命周期。
2. 如果后臺(tái)的Activity由于某原因被系統(tǒng)回收了,如何在被系統(tǒng)回收之前保存當(dāng)前狀態(tài)?
3. 如何將一個(gè)Activity設(shè)置成窗口的樣式。(Edited by Sodino)
4. 如何退出Activity?如何安全退出已調(diào)用多個(gè)Activity的Application?
5. 請(qǐng)介紹下Android中常用的五種布局。
6. 請(qǐng)介紹下Android的數(shù)據(jù)存儲(chǔ)方式。(Edited by Sodino)
7. 請(qǐng)介紹下ContentProvider是如何實(shí)現(xiàn)數(shù)據(jù)共享的。(Edited by Sodino)
8. 如何啟用Service,如何停用Service。(Edited by Sodino)
9. 注冊(cè)廣播有幾種方式,這些方式有何優(yōu)缺點(diǎn)?請(qǐng)談?wù)凙ndroid引入廣播機(jī)制的用意。
10. 請(qǐng)解釋下在單線程模型中Message、Handler、Message Queue、Looper之間的關(guān)系。
11. AIDL的全稱(chēng)是什么?如何工作?能處理哪些類(lèi)型的數(shù)據(jù)?
12. 請(qǐng)解釋下Android程序運(yùn)行時(shí)權(quán)限與文件系統(tǒng)權(quán)限的區(qū)別。(Edited by Sodino)
13. 系統(tǒng)上安裝了多種瀏覽器,能否指定某瀏覽器訪問(wèn)指定頁(yè)面?請(qǐng)說(shuō)明原由。
14. 有一個(gè)一維整型數(shù)組int[]data保存的是一張寬為width,高為height的圖片像素值信息。請(qǐng)寫(xiě)一個(gè)算法,將該圖片所有的白色不透明(0xffffffff)像素點(diǎn)的透明度調(diào)整為50%。
15. 你如何評(píng)價(jià)Android系統(tǒng)??jī)?yōu)缺點(diǎn)。
1. 請(qǐng)描述下Activity的生命周期
http://weizhulin.blog.51cto.com/1556324/311495
詳細(xì)介紹一下這幾個(gè)方法中系統(tǒng)在做什么以及我們應(yīng)該做什么:
onCreate: 在這里創(chuàng)建界面 ,做一些數(shù)據(jù)的初始化工作
onStart: 到這一步變成用戶(hù)可見(jiàn)不可交互 的
onResume: 變成和用戶(hù)可交互 的,(在activity 棧系統(tǒng)通過(guò)棧的方式管理這些個(gè)
Activity的最上面,運(yùn)行完彈出棧,則回到上一個(gè)Activity)
onPause: 到這一步是可見(jiàn)但不可交互 的,系統(tǒng)會(huì)停止動(dòng)畫(huà) 等消耗CPU 的事情
從上文的描述已經(jīng)知道,應(yīng)該在這里保存你的一些數(shù)據(jù),因?yàn)檫@個(gè)時(shí)候
你的程序的優(yōu)先級(jí)降低,有可能被系統(tǒng)收回。在這里保存的數(shù)據(jù),應(yīng)該在
onResume里讀出來(lái),注意:這個(gè)方法里做的事情時(shí)間要短,因?yàn)橄乱?br /> 個(gè)activity不會(huì)等到這個(gè)方法完成才啟動(dòng)
onstop: 變得不可見(jiàn) ,被下一個(gè)activity覆蓋了
onDestroy: 這是activity被干掉前最后一個(gè)被調(diào)用方法了,可能是外面類(lèi)調(diào)用finish方
法或者是系統(tǒng)為了節(jié)省空間將它暫時(shí)性的干掉,可以用isFinishing()來(lái)判
斷它,如果你有一個(gè)Progress Dialog在線程中轉(zhuǎn)動(dòng),請(qǐng)?jiān)趏nDestroy里
把他cancel掉,不然等線程結(jié)束的時(shí)候,調(diào)用Dialog的cancel方法會(huì)拋
異常的。
onPause,onstop, onDestroy,三種狀態(tài) 下 activity都有可能被系統(tǒng)干掉
為了保證程序的正確性,你要在onPause()里寫(xiě)上持久層操作的代碼,將用戶(hù)編輯的內(nèi)容都保存到存儲(chǔ)介質(zhì)上(一般都是數(shù)據(jù)庫(kù))。實(shí)際工作中因?yàn)樯芷诘淖兓鴰?lái)的問(wèn)題也很多,比如你的應(yīng)用程序起了新的線程在跑,這時(shí)候中斷了,你還要去維護(hù)那個(gè)線程,是暫停還是殺掉還是數(shù)據(jù)回滾,是吧?因?yàn)锳ctivity可能被殺掉,所以線程中使用的變量和一些界面元素就千萬(wàn)要注意了,一般我都是采用Android的消息機(jī)制 [Handler,Message]來(lái)處理多線程和界面交互的問(wèn)題。這個(gè)我后面會(huì)講一些,最近因?yàn)檫@些東西頭已經(jīng)很大了,等我理清思緒再跟大家分享。
2. 如果后臺(tái)的Activity由于某原因被系統(tǒng)回收了,如何在被系統(tǒng)回收之前保存當(dāng)前狀態(tài)?
當(dāng)你的程序中某一個(gè)Activity A 在運(yùn)行時(shí)中,主動(dòng)或被動(dòng)地運(yùn)行另一個(gè)新的Activity B
這個(gè)時(shí)候A會(huì)執(zhí)行
Java代碼
- public
- void
onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putLong("id", 1234567890); - }
- public
void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState);outState.putLong("id", 1234567890);}
B 完成以后又會(huì)來(lái)找A, 這個(gè)時(shí)候就有兩種情況,一種是A被回收,一種是沒(méi)有被回收,被回
收的A就要重新調(diào)用onCreate()方法,不同于直接啟動(dòng)的是這回onCreate()里是帶上參數(shù)
savedInstanceState,沒(méi)被收回的就還是onResume就好了。
savedInstanceState是一個(gè)Bundle對(duì)象,你基本上可以把他理解為系統(tǒng)幫你維護(hù)的一個(gè)Map對(duì)象。在onCreate()里你可能會(huì)用到它,如果正常啟動(dòng)onCreate就不會(huì)有它,所以用的時(shí)候要判斷一下是否為空。
Java代碼
if(savedInstanceState != null){
long id = savedInstanceState.getLong("id");
}
if(savedInstanceState != null){ long id = savedInstanceState.getLong("id");}
就像官方的Notepad教程里的情況,你正在編輯某一個(gè)note,突然被中斷,那么就把這個(gè)note的id記住,再起來(lái)的時(shí)候就可以根據(jù)這個(gè)id去把那個(gè)note取出來(lái),程序就完整一些。這也是看你的應(yīng)用需不需要保存什么,比如你的界面就是讀取一個(gè)列表,那就不需要特殊記住什么,哦,沒(méi)準(zhǔn)你需要記住滾動(dòng)條的位置...
3. 如何將一個(gè)Activity設(shè)置成窗口的樣式
簡(jiǎn)單你只需要設(shè)置 一下Activity的主題就可以了在AndroidManifest.xml 中定義 Activity的
地方一句話:
Xml代碼
- android
:theme="@android:style/Theme.Dialog" - android:theme="@android:style/Theme.Dialog"
這就使你的應(yīng)用程序變成對(duì)話框的形式彈出來(lái)了,或者
Xml代碼
- android:theme="@android:style/Theme.Translucent"
- android:theme="@android:style/Theme.Translucent"
就變成半透明的,[友情提示-.-]類(lèi)似的這種activity的屬性可以在android.R.styleable 類(lèi)的AndroidManifestActivity 方法中看到,AndroidManifest.xml中所有元素的屬性的介紹都可以參考這個(gè)類(lèi)android.R.styleable
上面說(shuō)的是屬性名稱(chēng),具體有什么值是在android.R.style中可以看到,比如這個(gè)"@android:style/Theme.Dialog" 就對(duì)應(yīng)于android.R.style.Theme_Dialog ,('_'換成'.' <--注意:這個(gè)是文章內(nèi)容不是笑臉)就可以用在描述文件中了,找找類(lèi)定義和描述文件中的對(duì)應(yīng)關(guān)系就都明白了。
4. 如何退出Activity
對(duì)于單一Activity的應(yīng)用來(lái)說(shuō),退出很簡(jiǎn)單,直接finish()即可。
當(dāng)然,也可以用killProcess()和System.exit()這樣的方法。
現(xiàn)提供幾個(gè)方法,供參考:
1、拋異常強(qiáng)制退出:
該方法通過(guò)拋異常,使程序Force Close。
驗(yàn)證可以,但是,需要解決的問(wèn)題是,如何使程序結(jié)束掉,而不彈出Force Close的窗口。
2、記錄打開(kāi)的Activity:
每打開(kāi)一個(gè)Activity,就記錄下來(lái)。在需要退出時(shí),關(guān)閉每一個(gè)Activity即可。
3、發(fā)送特定廣播:
在需要結(jié)束應(yīng)用時(shí),發(fā)送一個(gè)特定的廣播,每個(gè)Activity收到廣播后,關(guān)閉即可。
4、遞歸退出
在打開(kāi)新的Activity時(shí)使用startActivityForResult,然后自己加標(biāo)志,在onActivityResult中處理,遞歸關(guān)閉。
除了第一個(gè),都是想辦法把每一個(gè)Activity都結(jié)束掉,間接達(dá)到目的。
但是這樣做同樣不完美。
你會(huì)發(fā)現(xiàn),如果自己的應(yīng)用程序?qū)γ恳粋€(gè)Activity都設(shè)置了nosensor,在兩個(gè)Activity結(jié)束的間隙,sensor可能有效了。
但至少,我們的目的達(dá)到了,而且沒(méi)有影響用戶(hù)使用。
為了編程方便,最好定義一個(gè)Activity基類(lèi),處理這些共通問(wèn)題。
5.請(qǐng)介紹下Android中常用的五種布局
Android布局是應(yīng)用界面開(kāi)發(fā)的重要一環(huán),在Android中,共有五種布局方式,分別是:FrameLayout(框架布
局),LinearLayout
(線性布局),AbsoluteLayout(絕對(duì)布局),RelativeLayout(相對(duì)布局),TableLayout(表格布局)。
一、FrameLayout
這個(gè)布局可以看成是墻腳堆東西,有一個(gè)四方的矩形的左上角墻腳,我們放了第一個(gè)東西,要再放一個(gè),那就在放在原來(lái)放的位置的上面,這樣依次的放,會(huì)蓋住原來(lái)的東西。這個(gè)布局比較簡(jiǎn)單,也只能放一點(diǎn)比較簡(jiǎn)單的東西。
二、LinearLayout
線性布局,這個(gè)東西,從外框上可以理解為一個(gè)div,他首先是一個(gè)一個(gè)從上往下羅列在屏幕上。每一個(gè)LinearLayout里面又可分為垂直布局
(android:orientation="vertical")和水平布局(android:orientation="horizontal"
)。當(dāng)垂直布局時(shí),每一行就只有一個(gè)元素,多個(gè)元素依次垂直往下;水平布局時(shí),只有一行,每一個(gè)元素依次向右排列。
linearLayout中有一個(gè)重要的屬性 android:layout_weight="1",這個(gè)weight在垂直布局時(shí),代表行距;水平的時(shí)候代表列寬;weight值越大就越大。
三、AbsoluteLayout
絕對(duì)布局猶如div指定了absolute屬性,用X,Y坐標(biāo)來(lái)指定元素的位置android:layout_x="20px"
android:layout_y="12px" 這種布局方式也比較簡(jiǎn)單,但是在垂直隨便切換時(shí),往往會(huì)出問(wèn)題,而且多個(gè)元素的時(shí)候,計(jì)算比較麻煩。
四、RelativeLayout
相對(duì)布局可以理解為某一個(gè)元素為參照物,來(lái)定位的布局方式。主要屬性有:
相對(duì)于某一個(gè)元素
android:layout_below="@id/aaa" 該元素在 id為aaa的下面
android:layout_toLeftOf="@id/bbb" 改元素的左邊是bbb
相對(duì)于父元素的地方
android:layout_alignParentLeft="true" 在父元素左對(duì)齊
android:layout_alignParentRight="true" 在父元素右對(duì)齊
還可以指定邊距等,具體詳見(jiàn)API
五。TableLayout
表格布局類(lèi)似Html里面的Table。每一個(gè)TableLayout里面有表格行TableRow,TableRow里面可以具體定義每一個(gè)元素,設(shè)定他的對(duì)齊方式 android:gravity="" 。
每一個(gè)布局都有自己適合的方式,另外,這五個(gè)布局元素可以相互嵌套應(yīng)用,做出美觀的界面。
6. 請(qǐng)介紹下Android的數(shù)據(jù)存儲(chǔ)方式
Android 提供了5種方式存儲(chǔ)數(shù)據(jù):
--使用SharedPreferences存儲(chǔ)數(shù)據(jù);
--文件存儲(chǔ)數(shù)據(jù);
--SQLite數(shù)據(jù)庫(kù)存儲(chǔ)數(shù)據(jù);
--使用ContentProvider存儲(chǔ)數(shù)據(jù);
--網(wǎng)絡(luò)存儲(chǔ)數(shù)據(jù);
先 說(shuō)下,Preference,F(xiàn)ile, DataBase這三種方式分別對(duì)應(yīng)的目錄是/data/data/Package Name/Shared_Pref, /data/data/Package Name/files, /data/data/Package Name/database 。
在Android中通常使用File存儲(chǔ)方式是用 Context.openFileOutput(String fileName, int mode)和Context.openFileInput(String fileName)。
Context.openFileOutput(String fileName, int mode)生成的文件自動(dòng)存儲(chǔ)在/data/data/Package Name/files目錄下,其全路徑是/data/data/Package Name/files/fileName 。注意下,這里的參數(shù)fileName不可以包含路徑分割符(如"/")。
通常來(lái)說(shuō),這種方式生成的文件只能在這個(gè)apk內(nèi)訪問(wèn)。但這個(gè)結(jié)論是指使用Context.openFileInput(String fileName)的方式。使用這種方式,每個(gè)apk只可以訪問(wèn)自己的/data/data/Package Name/files目錄下的文件,原因很簡(jiǎn)單,參數(shù)fileName中不可以包含路徑分割符,Android會(huì)自動(dòng)在/data/data /Package Name/files目錄下尋找文件名為fileName的文件。
一:使用SharedPreferences存儲(chǔ)數(shù)據(jù)
首先說(shuō)明SharedPreferences存儲(chǔ)方式,它是 Android提供的用來(lái)存儲(chǔ)一些簡(jiǎn)單配置信息的一種機(jī)制,例如:登錄用戶(hù)的用戶(hù)名與密碼。其采用了Map數(shù)據(jù)結(jié)構(gòu)來(lái)存儲(chǔ)數(shù)據(jù),以鍵值的方式存儲(chǔ),可以簡(jiǎn)單的讀取與寫(xiě)入,具體實(shí)例如下:
void ReadSharedPreferences(){
String strName,strPassword;
SharedPreferences user = getSharedPreferences(“user_info”,0);
strName = user.getString(“NAME”,””);
strPassword = user getString(“PASSWORD”,””);
}
void WriteSharedPreferences(String strName,String strPassword){
SharedPreferences user = getSharedPreferences(“user_info”,0);
uer.edit();
user.putString(“NAME”, strName);
user.putString(“PASSWORD” ,strPassword);
user.commit();
}
數(shù)據(jù)讀取與寫(xiě)入的方法都非常簡(jiǎn)單,只是在寫(xiě)入的時(shí)候有些區(qū)別:先調(diào)用edit()使其處于編輯狀態(tài),然后才能修改數(shù)據(jù),最后使用commit()提交修改的數(shù)據(jù)。實(shí)際上SharedPreferences是采用了XML格式將數(shù)據(jù)存儲(chǔ)到設(shè)備中,在DDMS中的File Explorer中的/data/data/<package name>/shares_prefs下。以上面的數(shù)據(jù)存儲(chǔ)結(jié)果為例,打開(kāi)后可以看到一個(gè)user_info.xml的文件,打開(kāi)后可以看到:
<?xml version=”1.0″ encoding=”UTF-8″?>
<map>
<string name=”NAME”>moandroid</string>
<string name=” PASSWORD”>SharedPreferences</string>
</map>
使用SharedPreferences是有些限制的:只能在同一個(gè)包內(nèi)使用,不能在不同的包之間使用。
二:文件存儲(chǔ)數(shù)據(jù)
文件存儲(chǔ)方式是一種較常用的方法,在Android中讀取/寫(xiě)入文件的方法,與 Java中實(shí)現(xiàn)I/O的程序是完全一樣的,提供了openFileInput()和openFileOutput()方法來(lái)讀取設(shè)備上的文件。 FilterInputStream, FilterOutputStream等可以到Java io package說(shuō)明中去詳細(xì)學(xué)習(xí),不再此詳細(xì)說(shuō)明,具體實(shí)例如下:
String fn = “moandroid.log”;
FileInputStream fis = openFileInput(fn);
FileOutputStream fos = openFileOutput(fn,Context.MODE_PRIVATE);
除此之外,Android還提供了其他函數(shù)來(lái)操作文件,詳細(xì)說(shuō)明請(qǐng)閱讀Android SDK。
三:網(wǎng)絡(luò)存儲(chǔ)數(shù)據(jù)
網(wǎng)絡(luò)存儲(chǔ)方式,需要與Android 網(wǎng)絡(luò)數(shù)據(jù)包打交道,關(guān)于Android 網(wǎng)絡(luò)數(shù)據(jù)包的詳細(xì)說(shuō)明,請(qǐng)閱讀Android SDK引用了Java SDK的哪些package?。
四:ContentProvider
1、ContentProvider簡(jiǎn)介
當(dāng)應(yīng)用繼承ContentProvider類(lèi),并重寫(xiě)該類(lèi)用于提供數(shù)據(jù)和存儲(chǔ)數(shù)據(jù)的方法,就可以向其他應(yīng)用共享其數(shù)據(jù)。雖然使用其他方法也可以對(duì)外共享數(shù)據(jù),但數(shù)據(jù)訪問(wèn)方式會(huì)因數(shù)據(jù)存儲(chǔ)的方式而不同,如:采用文件方式對(duì)外共享數(shù)據(jù),需要進(jìn)行文件操作讀寫(xiě)數(shù)據(jù);采用sharedpreferences共享數(shù)據(jù),需要使用sharedpreferences API讀寫(xiě)數(shù)據(jù)。而使用ContentProvider共享數(shù)據(jù)的好處是統(tǒng)一了數(shù)據(jù)訪問(wèn)方式。?
2、Uri類(lèi)簡(jiǎn)介
Uri代表了要操作的數(shù)據(jù),Uri主要包含了兩部分信息:1.需要操作的ContentProvider ,2.對(duì)ContentProvider中的什么數(shù)據(jù)進(jìn)行操作,一個(gè)Uri由以下幾部分組成:
1.scheme:ContentProvider(內(nèi)容提供者)的scheme已經(jīng)由Android所規(guī)定為:content://。
2.主機(jī)名(或Authority):用于唯一標(biāo)識(shí)這個(gè)ContentProvider,外部調(diào)用者可以根據(jù)這個(gè)標(biāo)識(shí)來(lái)找到它。
3.路徑(path):可以用來(lái)表示我們要操作的數(shù)據(jù),路徑的構(gòu)建應(yīng)根據(jù)業(yè)務(wù)而定,如下:
? 要操作contact表中id為10的記錄,可以構(gòu)建這樣的路徑:/contact/10
? 要操作contact表中id為10的記錄的name字段, contact/10/name
? 要操作contact表中的所有記錄,可以構(gòu)建這樣的路徑:/contact?
要操作的數(shù)據(jù)不一定來(lái)自數(shù)據(jù)庫(kù),也可以是文件等他存儲(chǔ)方式,如下:
要操作xml文件中contact節(jié)點(diǎn)下的name節(jié)點(diǎn),可以構(gòu)建這樣的路徑:/contact/name
如果要把一個(gè)字符串轉(zhuǎn)換成Uri,可以使用Uri類(lèi)中的parse()方法,如下:
Uri uri = Uri.parse("content://com.changcheng.provider.contactprovider/contact")
3、UriMatcher、ContentUrist和ContentResolver簡(jiǎn)介
因?yàn)閁ri代表了要操作的數(shù)據(jù),所以我們很經(jīng)常需要解析Uri,并從 Uri中獲取數(shù)據(jù)。Android系統(tǒng)提供了兩個(gè)用于操作Uri的工具類(lèi),分別為UriMatcher 和ContentUris 。掌握它們的使用,會(huì)便于我們的開(kāi)發(fā)工作。
? UriMatcher:用于匹配Uri,它的用法如下:
1.首先把你需要匹配Uri路徑全部給注冊(cè)上,如下:
//常量UriMatcher.NO_MATCH表示不匹配任何路徑的返回碼(-1)。
UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
//如果match()方法匹配content://com.changcheng.sqlite.provider.contactprovider /contact路徑,返回匹配碼為1
uriMatcher.addURI(“com.changcheng.sqlite.provider.contactprovider”, “contact”, 1);//添加需要匹配uri,如果匹配就會(huì)返回匹配碼
//如果match()方法匹配 content://com.changcheng.sqlite.provider.contactprovider/contact/230路徑,返回匹配碼為2
uriMatcher.addURI(“com.changcheng.sqlite.provider.contactprovider”, “contact/#”, 2);//#號(hào)為通配符
2.注冊(cè)完需要匹配的Uri后,就可以使用uriMatcher.match(uri)方法對(duì)輸入的Uri進(jìn)行匹配,如果匹配就返回匹配碼,匹配碼是調(diào)用 addURI()方法傳入的第三個(gè)參數(shù),假設(shè)匹配 content://com.changcheng.sqlite.provider.contactprovider/contact路徑,返回的匹配碼為1。
?
ContentUris:用于獲取Uri路徑后面的ID部分,它有兩個(gè)比較實(shí)用的方法:
? withAppendedId(uri, id)用于為路徑加上ID部分
? parseId(uri)方法用于從路徑中獲取ID部分
? ContentResolver:當(dāng)外部應(yīng)用需要對(duì)ContentProvider中的數(shù)據(jù)進(jìn)行添加、刪除、修改和查詢(xún)操作時(shí),可以使用 ContentResolver 類(lèi)來(lái)完成,要獲取ContentResolver 對(duì)象,可以使用Activity提供的getContentResolver()方法。 ContentResolver使用insert、delete、update、query方法,來(lái)操作數(shù)據(jù)。
五:總結(jié)說(shuō)明
以上5中存儲(chǔ)方式,在以后的開(kāi)發(fā)過(guò)程中,根據(jù)設(shè)計(jì)目標(biāo)、性能需求、空間需求等找到合適的數(shù)據(jù)存儲(chǔ)方式。Android 中的數(shù)據(jù)存儲(chǔ)都是私有的,其他應(yīng)用程序都是無(wú)法訪問(wèn)的,除非通過(guò)ContentResolver獲取其他程序共享的數(shù)據(jù)。采用文件方式對(duì)外共享數(shù)據(jù),需要進(jìn)行文件操作讀寫(xiě)數(shù)據(jù);采用sharedpreferences共享數(shù)據(jù),需要使用sharedpreferences API讀寫(xiě)數(shù)據(jù)。而使用ContentProvider共享數(shù)據(jù)的好處是統(tǒng)一了數(shù)據(jù)訪問(wèn)方式。
8.如何啟用Service,如何停用Service
Android中的服務(wù)和windows中的服務(wù)是類(lèi)似的東西,服務(wù)一般沒(méi)有用戶(hù)操作界面,它運(yùn)行于系統(tǒng)中不容易被用戶(hù)發(fā)覺(jué),可以使用它開(kāi)發(fā)如監(jiān)控之類(lèi)的程序。服務(wù)的開(kāi)發(fā)比較簡(jiǎn)單,如下:
第一步:繼承Service類(lèi)
public class SMSService extends Service {
}
第二步:在AndroidManifest.xml文件中的<application>節(jié)點(diǎn)里對(duì)服務(wù)進(jìn)行配置:
<service android:name=".SMSService" />
服務(wù)不能自己運(yùn)行,需要通過(guò)調(diào)用Context.startService()或Context.bindService()方法啟動(dòng)服務(wù)。這兩個(gè)方法都可以啟動(dòng)Service,但是它們的使用場(chǎng)合有所不同。使用startService()方法啟用服務(wù),調(diào)用者與服務(wù)之間沒(méi)有關(guān)連,即使調(diào)用者退出了,服務(wù)仍然運(yùn)行。使用bindService()方法啟用服務(wù),調(diào)用者與服務(wù)綁定在了一起,調(diào)用者一旦退出,服務(wù)也就終止,大有“不求同時(shí)生,必須同時(shí)死”的特點(diǎn)。
如果打算采用Context.startService()方法啟動(dòng)服務(wù),在服務(wù)未被創(chuàng)建時(shí),系統(tǒng)會(huì)先調(diào)用服務(wù)的onCreate()方法,接著調(diào)用onStart()方法。如果調(diào)用startService()方法前服務(wù)已經(jīng)被創(chuàng)建,多次調(diào)用startService()方法并不會(huì)導(dǎo)致多次創(chuàng)建服務(wù),但會(huì)導(dǎo)致多次調(diào)用onStart()方法。采用startService()方法啟動(dòng)的服務(wù),只能調(diào)用Context.stopService()方法結(jié)束服務(wù),服務(wù)結(jié)束時(shí)會(huì)調(diào)用onDestroy()方法。
如果打算采用Context.bindService()方法啟動(dòng)服務(wù),在服務(wù)未被創(chuàng)建時(shí),系統(tǒng)會(huì)先調(diào)用服務(wù)的onCreate()方法,接著調(diào)用onBind()方法。這個(gè)時(shí)候調(diào)用者和服務(wù)綁定在一起,調(diào)用者退出了,系統(tǒng)就會(huì)先調(diào)用服務(wù)的onUnbind()方法,接著調(diào)用onDestroy()方法。如果調(diào)用bindService()方法前服務(wù)已經(jīng)被綁定,多次調(diào)用bindService()方法并不會(huì)導(dǎo)致多次創(chuàng)建服務(wù)及綁定(也就是說(shuō)onCreate()和onBind()方法并不會(huì)被多次調(diào)用)。如果調(diào)用者希望與正在綁定的服務(wù)解除綁定,可以調(diào)用unbindService()方法,調(diào)用該方法也會(huì)導(dǎo)致系統(tǒng)調(diào)用服務(wù)的onUnbind()-->onDestroy()方法。
服務(wù)常用生命周期回調(diào)方法如下:onCreate() 該方法在服務(wù)被創(chuàng)建時(shí)調(diào)用,該方法只會(huì)被調(diào)用一次,無(wú)論調(diào)用多少次startService()或bindService()方法,服務(wù)也只被創(chuàng)建一次。
onDestroy()該方法在服務(wù)被終止時(shí)調(diào)用。
與采用Context.startService()方法啟動(dòng)服務(wù)有關(guān)的生命周期方法
onStart() 只有采用Context.startService()方法啟動(dòng)服務(wù)時(shí)才會(huì)回調(diào)該方法。該方法在服務(wù)開(kāi)始運(yùn)行時(shí)被調(diào)用。多次調(diào)用startService()方法盡管不會(huì)多次創(chuàng)建服務(wù),但onStart() 方法會(huì)被多次調(diào)用。
與采用Context.bindService()方法啟動(dòng)服務(wù)有關(guān)的生命周期方法
onBind()只有采用Context.bindService()方法啟動(dòng)服務(wù)時(shí)才會(huì)回調(diào)該方法。該方法在調(diào)用者與服務(wù)綁定時(shí)被調(diào)用,當(dāng)調(diào)用者與服務(wù)已經(jīng)綁定,多次調(diào)用Context.bindService()方法并不會(huì)導(dǎo)致該方法被多次調(diào)用。
onUnbind()只有采用Context.bindService()方法啟動(dòng)服務(wù)時(shí)才會(huì)回調(diào)該方法。該方法在調(diào)用者與服務(wù)解除綁定時(shí)被調(diào)用
采用Context.startService()方法啟動(dòng)服務(wù)的代碼如下:
public class HelloActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
......
Button button =(Button) this.findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener(){
public void onClick(View v) {
Intent intent = new Intent(HelloActivity.this, SMSService.class);
startService(intent);
}});
}
}
采用Context. bindService()方法啟動(dòng)服務(wù)的代碼如下:
public class HelloActivity extends Activity {
ServiceConnection conn = new ServiceConnection() {
public void onServiceConnected(ComponentName name, IBinder service) {
}
public void onServiceDisconnected(ComponentName name) {
}
};
@Override public void onCreate(Bundle savedInstanceState) {
Button button =(Button) this.findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener(){
public void onClick(View v) {
Intent intent = new Intent(HelloActivity.this, SMSService.class);
bindService (intent, conn, Context.BIND_AUTO_CREATE);
//unbindService(conn);//解除綁定
}});
}
}
為了保證程序的正確性,你要在onPause()里寫(xiě)上持久層操作的代碼,將用戶(hù)編輯的內(nèi)容都保存到存儲(chǔ)介質(zhì)上(一般都是數(shù)據(jù)庫(kù))。實(shí)際工作中因?yàn)樯芷诘淖兓鴰?lái)的問(wèn)題也很多,比如你的應(yīng)用程序起了新的線程在跑,這時(shí)候中斷了,你還要去維護(hù)那個(gè)線程,是暫停還是殺掉還是數(shù)據(jù)回滾,是吧?因?yàn)锳ctivity可能被殺掉,所以線程中使用的變量和一些界面元素就千萬(wàn)要注意了,一般我都是采用Android的消息機(jī)制 [Handler,Message]來(lái)處理多線程和界面交互的問(wèn)題。這個(gè)我后面會(huì)講一些,最近因?yàn)檫@些東西頭已經(jīng)很大了,等我理清思緒再跟大家分享。
2. 如果后臺(tái)的Activity由于某原因被系統(tǒng)回收了,如何在被系統(tǒng)回收之前保存當(dāng)前狀態(tài)?
當(dāng)你的程序中某一個(gè)Activity A 在運(yùn)行時(shí)中,主動(dòng)或被動(dòng)地運(yùn)行另一個(gè)新的Activity B
這個(gè)時(shí)候A會(huì)執(zhí)行
Java代碼
- public
- void
onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putLong("id",1234567890); - }
- public
void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putLong("id", 1234567890);}
B 完成以后又會(huì)來(lái)找A, 這個(gè)時(shí)候就有兩種情況,一種是A被回收,一種是沒(méi)有被回收,被回
收的A就要重新調(diào)用onCreate()方法,不同于直接啟動(dòng)的是這回onCreate()里是帶上參數(shù)
savedInstanceState,沒(méi)被收回的就還是onResume就好了。
savedInstanceState是一個(gè)Bundle對(duì)象,你基本上可以把他理解為系統(tǒng)幫你維護(hù)的一個(gè)Map對(duì)象。在onCreate()里你可能會(huì)用到它,如果正常啟動(dòng)onCreate就不會(huì)有它,所以用的時(shí)候要判斷一下是否為空。
Java代碼
if(savedInstanceState != null){
}
if(savedInstanceState != null){
就像官方的Notepad教程里的情況,你正在編輯某一個(gè)note,突然被中斷,那么就把這個(gè)note的id記住,再起來(lái)的時(shí)候就可以根據(jù)這個(gè)id去把那個(gè)note取出來(lái),程序就完整一些。這也是看你的應(yīng)用需不需要保存什么,比如你的界面就是讀取一個(gè)列表,那就不需要特殊記住什么,哦,沒(méi)準(zhǔn)你需要記住滾動(dòng)條的位置...
3. 如何將一個(gè)Activity設(shè)置成窗口的樣式簡(jiǎn)單你只需要設(shè)置 一下Activity的主題就可以了在AndroidManifest.xml 中定義 Activity的
地方一句話:
Xml代碼
- android
:theme="@android:style/Theme.Dialog" - android:theme="@android:style/Theme.Dialog"
這就使你的應(yīng)用程序變成對(duì)話框的形式彈出來(lái)了,或者
Xml代碼
- android:theme="@android:style/Theme.Translucent"
- android:theme="@android:style/Theme.Translucent"
就變成半透明的,[友情提示-.-]類(lèi)似的這種activity的屬性可以在android.R.styleable 類(lèi)的AndroidManifestActivity 方法中看到,AndroidManifest.xml中所有元素的屬性的介紹都可以參考這個(gè)類(lèi)android.R.styleable
上面說(shuō)的是屬性名稱(chēng),具體有什么值是在android.R.style中可以看到,比如這個(gè)"@android:style/Theme.Dialog" 就對(duì)應(yīng)于android.R.style.Theme_Dialog ,('_'換成'.' <--注意:這個(gè)是文章內(nèi)容不是笑臉)就可以用在描述文件中了,找找類(lèi)定義和描述文件中的對(duì)應(yīng)關(guān)系就都明白了。
4. 如何退出Activity
對(duì)于單一Activity的應(yīng)用來(lái)說(shuō),退出很簡(jiǎn)單,直接finish()即可。
當(dāng)然,也可以用killProcess()和System.exit()這樣的方法。
現(xiàn)提供幾個(gè)方法,供參考:
1、拋異常強(qiáng)制退出:
該方法通過(guò)拋異常,使程序Force Close。
驗(yàn)證可以,但是,需要解決的問(wèn)題是,如何使程序結(jié)束掉,而不彈出Force Close的窗口。
2、記錄打開(kāi)的Activity:
每打開(kāi)一個(gè)Activity,就記錄下來(lái)。在需要退出時(shí),關(guān)閉每一個(gè)Activity即可。
3、發(fā)送特定廣播:
在需要結(jié)束應(yīng)用時(shí),發(fā)送一個(gè)特定的廣播,每個(gè)Activity收到廣播后,關(guān)閉即可。
4、遞歸退出
在打開(kāi)新的Activity時(shí)使用startActivityForResult,然后自己加標(biāo)志,在onActivityResult中處理,遞歸關(guān)閉。
除了第一個(gè),都是想辦法把每一個(gè)Activity都結(jié)束掉,間接達(dá)到目的。
但是這樣做同樣不完美。
你會(huì)發(fā)現(xiàn),如果自己的應(yīng)用程序?qū)γ恳粋€(gè)Activity都設(shè)置了nosensor,在兩個(gè)Activity結(jié)束的間隙,sensor可能有效了。
但至少,我們的目的達(dá)到了,而且沒(méi)有影響用戶(hù)使用。
為了編程方便,最好定義一個(gè)Activity基類(lèi),處理這些共通問(wèn)題。
5.請(qǐng)介紹下Android中常用的五種布局
Android布局是應(yīng)用界面開(kāi)發(fā)的重要一環(huán),在Android中,共有五種布局方式,分別是:FrameLayout(框架布
局),LinearLayout
(線性布局),AbsoluteLayout(絕對(duì)布局),RelativeLayout(相對(duì)布局),TableLayout(表格布局)。
一、FrameLayout
這個(gè)布局可以看成是墻腳堆東西,有一個(gè)四方的矩形的左上角墻腳,我們放了第一個(gè)東西,要再放一個(gè),那就在放在原來(lái)放的位置的上面,這樣依次的放,會(huì)蓋住原來(lái)的東西。這個(gè)布局比較簡(jiǎn)單,也只能放一點(diǎn)比較簡(jiǎn)單的東西。
二、LinearLayout
線性布局,這個(gè)東西,從外框上可以理解為一個(gè)div,他首先是一個(gè)一個(gè)從上往下羅列在屏幕上。每一個(gè)LinearLayout里面又可分為垂直布局
(android:orientation="vertical")和水平布局(android:orientation="horizontal"
)。當(dāng)垂直布局時(shí),每一行就只有一個(gè)元素,多個(gè)元素依次垂直往下;水平布局時(shí),只有一行,每一個(gè)元素依次向右排列。
linearLayout中有一個(gè)重要的屬性 android:layout_weight="1",這個(gè)weight在垂直布局時(shí),代表行距;水平的時(shí)候代表列寬;weight值越大就越大。
三、AbsoluteLayout
絕對(duì)布局猶如div指定了absolute屬性,用X,Y坐標(biāo)來(lái)指定元素的位置android:layout_x="20px"
android:layout_y="12px" 這種布局方式也比較簡(jiǎn)單,但是在垂直隨便切換時(shí),往往會(huì)出問(wèn)題,而且多個(gè)元素的時(shí)候,計(jì)算比較麻煩。
四、RelativeLayout
相對(duì)布局可以理解為某一個(gè)元素為參照物,來(lái)定位的布局方式。主要屬性有:
相對(duì)于某一個(gè)元素
android:layout_below="@id/aaa" 該元素在 id為aaa的下面
android:layout_toLeftOf="@id/bbb" 改元素的左邊是bbb
相對(duì)于父元素的地方
android:layout_alignParentLeft="true" 在父元素左對(duì)齊
android:layout_alignParentRight="true" 在父元素右對(duì)齊
還可以指定邊距等,具體詳見(jiàn)API
五。TableLayout
表格布局類(lèi)似Html里面的Table。每一個(gè)TableLayout里面有表格行TableRow,TableRow里面可以具體定義每一個(gè)元素,設(shè)定他的對(duì)齊方式 android:gravity="" 。
每一個(gè)布局都有自己適合的方式,另外,這五個(gè)布局元素可以相互嵌套應(yīng)用,做出美觀的界面。
6. 請(qǐng)介紹下Android的數(shù)據(jù)存儲(chǔ)方式
Android 提供了5種方式存儲(chǔ)數(shù)據(jù):
--使用SharedPreferences存儲(chǔ)數(shù)據(jù);
--文件存儲(chǔ)數(shù)據(jù);
--SQLite數(shù)據(jù)庫(kù)存儲(chǔ)數(shù)據(jù);
--使用ContentProvider存儲(chǔ)數(shù)據(jù);
--網(wǎng)絡(luò)存儲(chǔ)數(shù)據(jù);
先 說(shuō)下,Preference,F(xiàn)ile, DataBase這三種方式分別對(duì)應(yīng)的目錄是/data/data/Package Name/Shared_Pref, /data/data/Package Name/files, /data/data/Package Name/database 。
在Android中通常使用File存儲(chǔ)方式是用 Context.openFileOutput(String fileName, int mode)和Context.openFileInput(String fileName)。
Context.openFileOutput(String fileName, int mode)生成的文件自動(dòng)存儲(chǔ)在/data/data/Package Name/files目錄下,其全路徑是/data/data/Package Name/files/fileName 。注意下,這里的參數(shù)fileName不可以包含路徑分割符(如"/")。
通常來(lái)說(shuō),這種方式生成的文件只能在這個(gè)apk內(nèi)訪問(wèn)。但這個(gè)結(jié)論是指使用Context.openFileInput(String fileName)的方式。使用這種方式,每個(gè)apk只可以訪問(wèn)自己的/data/data/Package Name/files目錄下的文件,原因很簡(jiǎn)單,參數(shù)fileName中不可以包含路徑分割符,Android會(huì)自動(dòng)在/data/data /Package Name/files目錄下尋找文件名為fileName的文件。
一:使用SharedPreferences存儲(chǔ)數(shù)據(jù)
首先說(shuō)明SharedPreferences存儲(chǔ)方式,它是 Android提供的用來(lái)存儲(chǔ)一些簡(jiǎn)單配置信息的一種機(jī)制,例如:登錄用戶(hù)的用戶(hù)名與密碼。其采用了Map數(shù)據(jù)結(jié)構(gòu)來(lái)存儲(chǔ)數(shù)據(jù),以鍵值的方式存儲(chǔ),可以簡(jiǎn)單的讀取與寫(xiě)入,具體實(shí)例如下:
void ReadSharedPreferences(){
String strName,strPassword;
SharedPreferences user = getSharedPreferences(“user_info”,0);
strName = user.getString(“NAME”,””);
strPassword = user getString(“PASSWORD”,””);
}
void WriteSharedPreferences(String strName,String strPassword){
SharedPreferences user = getSharedPreferences(“user_info”,0);
uer.edit();
user.putString(“NAME”, strName);
user.putString(“PASSWORD” ,strPassword);
user.commit();
}
數(shù)據(jù)讀取與寫(xiě)入的方法都非常簡(jiǎn)單,只是在寫(xiě)入的時(shí)候有些區(qū)別:先調(diào)用edit()使其處于編輯狀態(tài),然后才能修改數(shù)據(jù),最后使用commit()提交修改的數(shù)據(jù)。實(shí)際上SharedPreferences是采用了XML格式將數(shù)據(jù)存儲(chǔ)到設(shè)備中,在DDMS中的File Explorer中的/data/data/<package name>/shares_prefs下。以上面的數(shù)據(jù)存儲(chǔ)結(jié)果為例,打開(kāi)后可以看到一個(gè)user_info.xml的文件,打開(kāi)后可以看到:
<?xml version=”1.0″ encoding=”UTF-8″?>
<map>
<string name=”NAME”>moandroid</string>
<string name=” PASSWORD”>SharedPreferences</string>
</map>
使用SharedPreferences是有些限制的:只能在同一個(gè)包內(nèi)使用,不能在不同的包之間使用。
strName = user.getString(“NAME”,””);
strPassword = user getString(“PASSWORD”,””);
}
void WriteSharedPreferences(String strName,String strPassword){
SharedPreferences
uer.edit();
user.putString(“NAME”, strName);
user.putString(“PASSWORD” ,strPassword);
user.commit();
}
數(shù)據(jù)讀取與寫(xiě)入的方法都非常簡(jiǎn)單,只是在寫(xiě)入的時(shí)候有些區(qū)別:先調(diào)用edit()使其處于編輯狀態(tài),然后才能修改數(shù)據(jù),最后使用commit()提交修改的數(shù)據(jù)。實(shí)際上SharedPreferences是采用了XML格式將數(shù)據(jù)存儲(chǔ)到設(shè)備中,在DDMS中的File Explorer中的/data/data/<package name>/shares_prefs下。以上面的數(shù)據(jù)存儲(chǔ)結(jié)果為例,打開(kāi)后可以看到一個(gè)user_info.xml的文件,打開(kāi)后可以看到:
<?xml version=”1.0″ encoding=”UTF-8″?>
<map>
<string name=”NAME”>moandroid</string>
<string name=” PASSWORD”>SharedPreferences</string>
</map>
使用SharedPreferences是有些限制的:只能在同一個(gè)包內(nèi)使用,不能在不同的包之間使用。
二:文件存儲(chǔ)數(shù)據(jù)
文件存儲(chǔ)方式是一種較常用的方法,在Android中讀取/寫(xiě)入文件的方法,與 Java中實(shí)現(xiàn)I/O的程序是完全一樣的,提供了openFileInput()和openFileOutput()方法來(lái)讀取設(shè)備上的文件。 FilterInputStream, FilterOutputStream等可以到Java io package說(shuō)明中去詳細(xì)學(xué)習(xí),不再此詳細(xì)說(shuō)明,具體實(shí)例如下:
String fn = “moandroid.log”;
FileInputStream fis = openFileInput(fn);
FileOutputStream fos = openFileOutput(fn,Context.MODE_PRIVATE);
除此之外,Android還提供了其他函數(shù)來(lái)操作文件,詳細(xì)說(shuō)明請(qǐng)閱讀Android SDK。
三:網(wǎng)絡(luò)存儲(chǔ)數(shù)據(jù)
網(wǎng)絡(luò)存儲(chǔ)方式,需要與Android 網(wǎng)絡(luò)數(shù)據(jù)包打交道,關(guān)于Android 網(wǎng)絡(luò)數(shù)據(jù)包的詳細(xì)說(shuō)明,請(qǐng)閱讀Android SDK引用了Java SDK的哪些package?。
四:ContentProvider
1、ContentProvider簡(jiǎn)介
當(dāng)應(yīng)用繼承ContentProvider類(lèi),并重寫(xiě)該類(lèi)用于提供數(shù)據(jù)和存儲(chǔ)數(shù)據(jù)的方法,就可以向其他應(yīng)用共享其數(shù)據(jù)。雖然使用其他方法也可以對(duì)外共享數(shù)據(jù),但數(shù)據(jù)訪問(wèn)方式會(huì)因數(shù)據(jù)存儲(chǔ)的方式而不同,如:采用文件方式對(duì)外共享數(shù)據(jù),需要進(jìn)行文件操作讀寫(xiě)數(shù)據(jù);采用sharedpreferences共享數(shù)據(jù),需要使用sharedpreferences API讀寫(xiě)數(shù)據(jù)。而使用ContentProvider共享數(shù)據(jù)的好處是統(tǒng)一了數(shù)據(jù)訪問(wèn)方式。?
2、Uri類(lèi)簡(jiǎn)介
Uri代表了要操作的數(shù)據(jù),Uri主要包含了兩部分信息:1.需要操作的ContentProvider ,2.對(duì)ContentProvider中的什么數(shù)據(jù)進(jìn)行操作,一個(gè)Uri由以下幾部分組成:
1.scheme:ContentProvider(內(nèi)容提供者)的scheme已經(jīng)由Android所規(guī)定為:content://。
2.主機(jī)名(或Authority):用于唯一標(biāo)識(shí)這個(gè)ContentProvider,外部調(diào)用者可以根據(jù)這個(gè)標(biāo)識(shí)來(lái)找到它。
3.路徑(path):可以用來(lái)表示我們要操作的數(shù)據(jù),路徑的構(gòu)建應(yīng)根據(jù)業(yè)務(wù)而定,如下:
? 要操作contact表中id為10的記錄,可以構(gòu)建這樣的路徑:/contact/10
? 要操作contact表中id為10的記錄的name字段, contact/10/name
? 要操作contact表中的所有記錄,可以構(gòu)建這樣的路徑:/contact?
要操作的數(shù)據(jù)不一定來(lái)自數(shù)據(jù)庫(kù),也可以是文件等他存儲(chǔ)方式,如下:
要操作xml文件中contact節(jié)點(diǎn)下的name節(jié)點(diǎn),可以構(gòu)建這樣的路徑:/contact/name
如果要把一個(gè)字符串轉(zhuǎn)換成Uri,可以使用Uri類(lèi)中的parse()方法,如下:
Uri uri = Uri.parse("content://com.changcheng.provider.contactprovider/contact")
3、UriMatcher、ContentUrist和ContentResolver簡(jiǎn)介
因?yàn)閁ri代表了要操作的數(shù)據(jù),所以我們很經(jīng)常需要解析Uri,并從 Uri中獲取數(shù)據(jù)。Android系統(tǒng)提供了兩個(gè)用于操作Uri的工具類(lèi),分別為UriMatcher 和ContentUris 。掌握它們的使用,會(huì)便于我們的開(kāi)發(fā)工作。
? UriMatcher:用于匹配Uri,它的用法如下:
1.首先把你需要匹配Uri路徑全部給注冊(cè)上,如下:
//常量UriMatcher.NO_MATCH表示不匹配任何路徑的返回碼(-1)。
UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
//如果match()方法匹配content://com.changcheng.sqlite.provider.contactprovider /contact路徑,返回匹配碼為1
uriMatcher.addURI(“com.changcheng.sqlite.provider.contactprovider”, “contact”, 1);//添加需要匹配uri,如果匹配就會(huì)返回匹配碼
//如果match()方法匹配 content://com.changcheng.sqlite.provider.contactprovider/contact/230路徑,返回匹配碼為2
uriMatcher.addURI(“com.changcheng.sqlite.provider.contactprovider”, “contact/#”, 2);//#號(hào)為通配符
2.注冊(cè)完需要匹配的Uri后,就可以使用uriMatcher.match(uri)方法對(duì)輸入的Uri進(jìn)行匹配,如果匹配就返回匹配碼,匹配碼是調(diào)用 addURI()方法傳入的第三個(gè)參數(shù),假設(shè)匹配 content://com.changcheng.sqlite.provider.contactprovider/contact路徑,返回的匹配碼為1。
?
ContentUris:用于獲取Uri路徑后面的ID部分,它有兩個(gè)比較實(shí)用的方法:
? withAppendedId(uri, id)用于為路徑加上ID部分
? parseId(uri)方法用于從路徑中獲取ID部分
? ContentResolver:當(dāng)外部應(yīng)用需要對(duì)ContentProvider中的數(shù)據(jù)進(jìn)行添加、刪除、修改和查詢(xún)操作時(shí),可以使用 ContentResolver 類(lèi)來(lái)完成,要獲取ContentResolver 對(duì)象,可以使用Activity提供的getContentResolver()方法。 ContentResolver使用insert、delete、update、query方法,來(lái)操作數(shù)據(jù)。
五:總結(jié)說(shuō)明
以上5中存儲(chǔ)方式,在以后的開(kāi)發(fā)過(guò)程中,根據(jù)設(shè)計(jì)目標(biāo)、性能需求、空間需求等找到合適的數(shù)據(jù)存儲(chǔ)方式。Android 中的數(shù)據(jù)存儲(chǔ)都是私有的,其他應(yīng)用程序都是無(wú)法訪問(wèn)的,除非通過(guò)ContentResolver獲取其他程序共享的數(shù)據(jù)。采用文件方式對(duì)外共享數(shù)據(jù),需要進(jìn)行文件操作讀寫(xiě)數(shù)據(jù);采用sharedpreferences共享數(shù)據(jù),需要使用sharedpreferences API讀寫(xiě)數(shù)據(jù)。而使用ContentProvider共享數(shù)據(jù)的好處是統(tǒng)一了數(shù)據(jù)訪問(wèn)方式。
8.如何啟用Service,如何停用Service
Android中的服務(wù)和windows中的服務(wù)是類(lèi)似的東西,服務(wù)一般沒(méi)有用戶(hù)操作界面,它運(yùn)行于系統(tǒng)中不容易被用戶(hù)發(fā)覺(jué),可以使用它開(kāi)發(fā)如監(jiān)控之類(lèi)的程序。服務(wù)的開(kāi)發(fā)比較簡(jiǎn)單,如下:
第一步:繼承Service類(lèi)
public class SMSService extends Service {
}
第二步:在AndroidManifest.xml文件中的<application>節(jié)點(diǎn)里對(duì)服務(wù)進(jìn)行配置:
<service android:name=".SMSService" />
服務(wù)不能自己運(yùn)行,需要通過(guò)調(diào)用Context.startService()或Context.bindService()方法啟動(dòng)服務(wù)。這兩個(gè)方法都可以啟動(dòng)Service,但是它們的使用場(chǎng)合有所不同。使用startService()方法啟用服務(wù),調(diào)用者與服務(wù)之間沒(méi)有關(guān)連,即使調(diào)用者退出了,服務(wù)仍然運(yùn)行。使用bindService()方法啟用服務(wù),調(diào)用者與服務(wù)綁定在了一起,調(diào)用者一旦退出,服務(wù)也就終止,大有“不求同時(shí)生,必須同時(shí)死”的特點(diǎn)。
如果打算采用Context.startService()方法啟動(dòng)服務(wù),在服務(wù)未被創(chuàng)建時(shí),系統(tǒng)會(huì)先調(diào)用服務(wù)的onCreate()方法,接著調(diào)用onStart()方法。如果調(diào)用startService()方法前服務(wù)已經(jīng)被創(chuàng)建,多次調(diào)用startService()方法并不會(huì)導(dǎo)致多次創(chuàng)建服務(wù),但會(huì)導(dǎo)致多次調(diào)用onStart()方法。采用startService()方法啟動(dòng)的服務(wù),只能調(diào)用Context.stopService()方法結(jié)束服務(wù),服務(wù)結(jié)束時(shí)會(huì)調(diào)用onDestroy()方法。
服務(wù)常用生命周期回調(diào)方法如下:
onCreate() 該方法在服務(wù)被創(chuàng)建時(shí)調(diào)用,該方法只會(huì)被調(diào)用一次,無(wú)論調(diào)用多少次startService()或bindService()方法,服務(wù)也只被創(chuàng)建一次。
onDestroy()該方法在服務(wù)被終止時(shí)調(diào)用。
與采用Context.startService()方法啟動(dòng)服務(wù)有關(guān)的生命周期方法
onStart() 只有采用Context.startService()方法啟動(dòng)服務(wù)時(shí)才會(huì)回調(diào)該方法。該方法在服務(wù)開(kāi)始運(yùn)行時(shí)被調(diào)用。多次調(diào)用startService()方法盡管不會(huì)多次創(chuàng)建服務(wù),但onStart() 方法會(huì)被多次調(diào)用。
與采用Context.bindService()方法啟動(dòng)服務(wù)有關(guān)的生命周期方法
onBind()只有采用Context.bindService()方法啟動(dòng)服務(wù)時(shí)才會(huì)回調(diào)該方法。該方法在調(diào)用者與服務(wù)綁定時(shí)被調(diào)用,當(dāng)調(diào)用者與服務(wù)已經(jīng)綁定,多次調(diào)用Context.bindService()方法并不會(huì)導(dǎo)致該方法被多次調(diào)用。
onUnbind()只有采用Context.bindService()方法啟動(dòng)服務(wù)時(shí)才會(huì)回調(diào)該方法。該方法在調(diào)用者與服務(wù)解除綁定時(shí)被調(diào)用
采用Context.startService()方法啟動(dòng)服務(wù)的代碼如下:
public class HelloActivity extends Activity {
}
采用Context. bindService()方法啟動(dòng)服務(wù)的代碼如下:
public class HelloActivity extends Activity {
}