1. 請描述下Activity的生命週期。
2. 如果背景Activity由於某原因被系統回收了,如何在被系統回收之前儲存目前狀態?
3. 如何將一個Activity設定成視窗的樣式。(Edited by Sodino)
4. 如何退出Activity?如何安全退出已調用多個Activity的Application?
5. 請介紹下Android中常用的五種布局。
6. 請介紹下Android的資料存放區方式。(Edited by Sodino)
7. 請介紹下ContentProvider是如何?資料共用的。(Edited by Sodino)
8. 如何啟用Service,如何停用Service。(Edited by Sodino)
9. 註冊廣播有幾種方式,這些方式有何優缺點?請談談Android引入廣播機制的用意。
10. 請解釋下在單執行緒模式中Message、Handler、Message Queue、Looper之間的關係。
11. AIDL的全稱是什嗎?如何工作?能處理哪些類型的資料?
12. 請解釋下Android程式運行時許可權與檔案系統許可權的區別。(Edited by Sodino)
13. 系統上安裝了多種瀏覽器,能否指定某瀏覽器訪問指定頁面?請說明原由。
14. 有一個一維整型數組int[]data儲存的是一張寬為width,高為height的圖片像素值資訊。請寫一個演算法,將該圖片所有的白色不透明(0xffffffff)像素點的透明度調整為50%。
15. 你如何評價Android系統?優缺點。
1. 請描述下Activity的生命週期
詳細介紹一下這幾個方法中系統在做什麼以及我們應該做什麼:
onCreate: 在這裡建立介面 ,做一些資料 的初始化工作
onStart: 到這一步變成使用者可見不可互動 的
onResume: 變成和使用者可互動 的,(在activity 棧系統通過棧的方式管理這些個
Activity的最上面,運行完彈出棧,則回到上一個Activity)
onPause: 到這一步是可見但不可互動 的,系統會停止動畫 等消耗CPU 的事情
從上文的描述已經知道,應該在這裡儲存你的一些資料,因為這個時候
你的程式的優先順序降低,有可能被系統收回。在這裡儲存的資料,應該在
onResume裡讀出來,注意:這個方法裡做的事情時間要短,因為下一
個activity不會等到這個方法完成才啟動
onstop: 變得不可見 ,被下一個activity覆蓋了
onDestroy: 這是activity被幹掉前最後一個被呼叫者法了,可能是外面類調用finish方
法或者是系統為了節省空間的將它暫時性的幹掉,可以用isFinishing()來判
斷它,如果你有一個Progress Dialog線上程中轉動,請在onDestroy裡
把他cancel掉,不然等線程結束的時候,調用Dialog的cancel方法會拋
異常的。
onPause,onstop, onDestroy,三種狀態 下 activity都有可能被系統幹掉
為了保證程式的正確性,你要在onPause()裡寫上持久層操作的代碼,將使用者編輯的內容都儲存到儲存介質上(一般都是資料庫 )。實際工作中因為生命週期的變化而帶來的問題也很多,比如你的應用程式起了新的線程在跑,這時候中斷了,你還要去維護那個線程,是暫停還是殺掉還是資料 復原,是吧?因為Activity可能被殺掉,所以線程中使用的變數和一些介面元素就千萬要注意了,一般我都是採用Android的訊息機制 [Handler,Message]來處理多線程和介面互動的問題。這個我後面會講一些,最近因為這些東西頭已經很大了,等我理清思緒再跟大家分享。
2. 如果背景Activity由於某原因被系統回收了,如何在被系統回收之前儲存目前狀態?
當你的程式中某一個Activity A 在運行時中,主動或被動地運行另一個新的Activity B
這個時候A會執行
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 完成以後又會來找A, 這個時候就有兩種情況,一種是A被回收,一種是沒有被回收,被回
收的A就要重新調用onCreate()方法,不同於直接啟動的是這回onCreate()裡是帶上參數
savedInstanceState,沒被收回的就還是onResume就好了。
savedInstanceState是一個Bundle對象,你基本上可以把他理解為系統幫你維護的一個Map對象。在onCreate()裡你可能會 用到它,如果正常啟動onCreate就不會有它,所以用的時候要判斷一下是否為空白。
Java代碼
if(savedInstanceState != null){
long id = savedInstanceState.getLong("id");
}
if(savedInstanceState != null){ long id = savedInstanceState.getLong("id");}
就像官方的Notepad教程 裡的情況,你正在編輯某一個note,突然被中斷,那麼就把這個note的id記住,再起來的時候就可以根據這個id去把那個note取出來,程式就完整 一些。這也是看你的應用需不需要儲存什麼,比如你的介面就是讀取一個列表,那就不需要特殊記住什麼,哦, 沒準你需要記住捲軸的位置...
3. 如何將一個Activity設定成視窗的樣式
簡單你只需要設定 一下Activity的主題就可以了在AndroidManifest.xml 中定義 Activity的
地方一句話:
Xml代碼
android :theme="@android:style/Theme.Dialog"
android:theme="@android:style/Theme.Dialog"
這就使你的應用程式變成對話方塊的形式彈出來了,或者
Xml代碼
android:theme="@android:style/Theme.Translucent"
android:theme="@android:style/Theme.Translucent"
就變成半透明的,[友情提示-.-]類似的這種activity的屬性可以在android.R.styleable 類的AndroidManifestActivity 方法中看到,AndroidManifest.xml中所有元素的屬性的介紹都可以參考這個類android.R.styleable
上面說的是屬性名稱,具體有什麼值是在android.R.style中 可以看到,比如這個"@android:style/Theme.Dialog" 就對應於android.R.style.Theme_Dialog ,('_'換成'.' <--注意:這個是文章內容不是笑臉)就可以用在描述檔案 中了,找找類定義和描述檔案中的對應關係就都明白了。
4. 如何退出Activity
對於單一Activity的應用來說,退出很簡單,直接finish()即可。
當然,也可以用killProcess()和System.exit()這樣的方法。
現提供幾個方法,供參考:
1、拋異常強制退出:
該方法通過拋異常,使程式Force Close。
驗證可以,但是,需要解決的問題是,如何使程式結束掉,而不彈出Force Close的視窗。
2、記錄開啟的Activity:
每開啟一個Activity,就記錄下來。在需要退出時,關閉每一個Activity即可。
3、發送特定廣播:
在需要結束應用時,發送一個特定的廣播,每個Activity收到廣播後,關閉即可。
4、遞迴退出
在開啟新的Activity時使用startActivityForResult,然後自己加標誌,在onActivityResult中處理,遞迴關閉。
除了第一個,都是想辦法把每一個Activity都結束掉,間接達到目的。
但是這樣做同樣不完美。
你會發現,如果自己的應用程式對每一個Activity都設定了nosensor,在兩個Activity結束的間隙,sensor可能有效了。
但至少,我們的目的達到了,而且沒有影響使用者使用。
為了編程方便,最好定義一個Activity基類,處理這些共通問題。
5.請介紹下Android中常用的五種布局
Android布局是應用介面開發的重要一環,在Android中,共有五種布局方式,分別是:FrameLayout(架構布
局),LinearLayout
(線性布局),AbsoluteLayout(絕對布局),RelativeLayout(相對布局),TableLayout(表格版面配置)。
一、FrameLayout
這個布局可以看成是牆腳堆東西,有一個四方的矩形的左上方牆腳,我們放了第一個東西,要再放一個,那就在放在原來放的位置的上面,這樣依次的放,會蓋住原來的東西。這個布局比較簡單,也只能放一點比較簡單的東西。
二、LinearLayout
線性布局,這個東西,從外框上可以理解為一個div,他首先是一個一個從上往下羅列在螢幕上。每一個LinearLayout裡面又可分為垂直布局
(android:orientation="vertical")和水平布局(android:orientation="horizontal"
)。當垂直布局時,每一行就只有一個元素,多個元素依次垂直往下;水平布局時,只有一行,每一個元素依次向右排列。
linearLayout中有一個重要的屬性 android:layout_weight="1",這個weight在垂直布局時,代表行距;水平的時候代表列寬;weight值越大就越大。
三、AbsoluteLayout
絕對布局猶如div指定了absolute屬性,用X,Y座標來指定元素的位置android:layout_x="20px"
android:layout_y="12px" 這種布局方式也比較簡單,但是在垂直隨便切換時,往往會出問題,而且多個元素的時候,計算比較麻煩。
四、RelativeLayout
相對布局可以理解為某一個元素為參照物,來定位的布局方式。主要屬性有:
相對於某一個元素
android:layout_below="@id/aaa" 該元素在 id為aaa的下面
android:layout_toLeftOf="@id/bbb" 改元素的左邊是bbb
相對於父元素的地方
android:layout_alignParentLeft="true" 在父元素靠左對齊
android:layout_alignParentRight="true" 在父元素靠右對齊
還可以指定邊距等,具體詳見API
五。TableLayout
表格版面配置類似Html裡面的Table。每一個TableLayout裡面有表格行TableRow,TableRow裡面可以具體定義每一個元素,設定他的對齊 android:gravity="" 。
每一個布局都有自己適合的方式,另外,這五個布局元素可以相互嵌套應用,做出美觀的介面。
6. 請介紹下Android的資料存放區方式
Android 提供了5種方式儲存資料:
--使用SharedPreferences儲存資料;
--檔案儲存體資料;
--SQLite資料庫儲存資料;
--使用ContentProvider儲存資料;
--網路儲存資料;
先 說下,Preference,File, DataBase這三種方式分別對應的目錄是/data/data/Package Name/Shared_Pref, /data/data/Package Name/files, /data/data/Package Name/database 。
在Android中通常使用File儲存方式是用 Context.openFileOutput(String fileName, int mode)和Context.openFileInput(String fileName)。
Context.openFileOutput(String fileName, int mode)產生的檔案自動儲存在/data/data/Package Name/files目錄下,其全路徑是/data/data/Package Name/files/fileName 。注意下,這裡的參數fileName不可以包含路徑分割符(如"/")。
通常來說,這種方式產生的檔案只能在這個apk內訪問。但這個結論是指使用Context.openFileInput(String fileName)的方式。使用這種方式,每個apk只可以訪問自己的/data/data/Package Name/files目錄下的檔案,原因很簡單,參數fileName中不可以包含路徑分割符,Android會自動在/data/data /Package Name/files目錄下尋找檔案名稱為fileName的檔案。
一:使用SharedPreferences儲存資料
首先說明SharedPreferences儲存方式,它是 Android提供的用來儲存一些簡單配置資訊的一種機制,例如:登入使用者的使用者名稱與密碼。其採用了Map資料結構來儲存資料,以索引值的方式儲存,可以簡 單的讀取與寫入,具體執行個體如下:
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();
}
資料讀取與寫入的方法都非常簡單,只是在寫入的時候有些區別:先調用edit()使其處於編輯狀態,然後才能修改資料,最後使用commit()提交修改 的資料。實際上SharedPreferences是採用了XML格式將資料存放區到裝置中,在DDMS中的File Explorer中的/data/data/<package name>/shares_prefs下。以上面的資料存放區結果為例,開啟後可以看到一個user_info.xml的檔案,開啟後可以看到:
<?xml version=”1.0″ encoding=”UTF-8″?>
<map>
<string name=”NAME”>moandroid</string>
<string name=” PASSWORD”>SharedPreferences</string>
</map>
使用SharedPreferences是有些限制的:只能在同一個包內使用,不能在不同的包之間使用。
二:檔案存 儲資料
檔案儲存體方式是一種較常用的方法,在Android中讀取/寫入檔案的方法,與 Java中實現I/O的程式是完全一樣的,提供了openFileInput()和openFileOutput()方法來讀取裝置上的檔案。 FilterInputStream, FilterOutputStream等可以到Java io package說明中去詳細學習,不再此詳細說明,具體執行個體如下:
String fn = “moandroid.log”;
FileInputStream fis = openFileInput(fn);
FileOutputStream fos = openFileOutput(fn,Context.MODE_PRIVATE);
除此之外,Android還提供了其他函數來操作檔案,詳細說明請閱讀Android SDK。
三:網路儲存資料
網路儲存方式,需要與Android 網路資料包打交道,關於Android 網路資料包的詳細說明,請閱讀Android SDK引用了Java SDK的哪些package?。
四:ContentProvider
1、ContentProvider簡介
當應用繼承ContentProvider類,並重寫該類用於提供資料和儲存資料的方法,就可以向其他應用共用其資料。雖然使用其他方法也可以對外共用數 據,但資料訪問方式會因資料存放區的方式而不同,如:採用檔案方式對外共用資料,需要進行檔案操作讀寫資料;採用sharedpreferences共用數 據,需要使用sharedpreferences API讀寫資料。而使用ContentProvider共用資料的好處是統一了資料訪問方式。?
2、Uri類簡介
Uri代表了要操作的資料,Uri主要包含了兩部分資訊:1.需要操作的ContentProvider ,2.對ContentProvider中的什麼資料進行操作,一個Uri由以下幾部分組成:
1.scheme:ContentProvider(內容提供者)的scheme已經由Android所規定為:content://。
2.主機名稱(或Authority):用於唯一標識這個ContentProvider,外部調用者可以根據這個標識來找到它。
3.路徑(path):可以用來表示我們要操作的資料,路徑的構建應根據業務而定,如下:
? 要操作contact表中id為10的記錄,可以構建這樣的路徑:/contact/10
? 要操作contact表中id為10的記錄的name欄位, contact/10/name
? 要操作contact表中的所有記錄,可以構建這樣的路徑:/contact?
要操作的資料不一定來自資料庫,也可以是檔案等他儲存方式,如下:
要操作xml檔案中contact節點下的name節點,可以構建這樣的路徑:/contact/name
如果要把一個字串轉換成Uri,可以使用Uri類中的parse()方法,如下:
Uri uri = Uri.parse("content://com.changcheng.provider.contactprovider/contact")
3、UriMatcher、ContentUrist和ContentResolver簡介
因為Uri代表了要操作的資料,所以我們很經常需要解析Uri,並從 Uri中擷取資料。Android系統提供了兩個用於操作Uri的工具類,分別為UriMatcher 和ContentUris 。掌握它們的使用,會便於我們的開發工作。
? UriMatcher:用於匹配Uri,它的用法如下:
1.首先把你需要匹配Uri路徑全部給註冊上,如下:
//常量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,如果匹配就會返回匹配碼
//如果match()方法匹配 content://com.changcheng.sqlite.provider.contactprovider/contact/230路徑,返 回匹配碼為2
uriMatcher.addURI(“com.changcheng.sqlite.provider.contactprovider”, “contact/#”, 2);//#號為萬用字元
2.註冊完需要匹配的Uri後,就可以使用uriMatcher.match(uri)方法對輸入的Uri進行匹配,如果匹配就返回匹配碼,匹配碼是調用 addURI()方法傳入的第三個參數,假設匹配 content://com.changcheng.sqlite.provider.contactprovider/contact路徑,返回的匹配 碼為1。
?
ContentUris:用於擷取Uri路徑後面的ID部分,它有兩個比較實用的方法:
? withAppendedId(uri, id)用於為路徑加上ID部分
? parseId(uri)方法用於從路徑中擷取ID部分
? ContentResolver:當外部應用需要對ContentProvider中的資料進行添加、刪除、修改和查詢操作時,可以使用 ContentResolver 類來完成,要擷取ContentResolver 對象,可以使用Activity提供的getContentResolver()方法。 ContentResolver使用insert、delete、update、query方法,來操作資料。
五:總結說明
以上5中儲存方式,在以後的開發過程中,根據設計目標、效能需求、空間需求等找到 合適的資料存放區方式。Android 中的資料存放區都是私人的,其他應用程式都是無法訪問的,除非通過ContentResolver擷取其他程式共用的資料。採用檔案方式對外共用資料,需要 進行檔案操作讀寫資料;採用sharedpreferences共用資料,需要使用sharedpreferences API讀寫資料。而使用ContentProvider共用資料的好處是統一了資料訪問方式。
8.如何啟用Service,如何停用Service
Android中的服務和windows中的服務是類似的 東西,服務一般沒有使用者操作介面,它運行於系統中不容易被使用者發覺,可以使用它開發如監控之類的程式。服務的開發比較簡單,如下:
第一步:繼承Service類
public class SMSService extends Service {
}
第二步:在AndroidManifest.xml文 件中的<application>節點裡對服務進 行配置:
<service android:name=".SMSService" />
服務不能自己運行,需要通過調用Context.startService()或Context.bindService()方法啟動服務。這兩個方法都 可以啟動Service,但是它們的使用場合有所不同。使用startService()方法啟用服務,調用者與服務之間沒有關連, 即使調用者退出了,服務仍然運行。使用bindService()方 法啟用服務,調用者與服務綁定在了一起,調用者一旦退出,服務也就終止,大有“不求同時生,必須同時死”的特點。
如果打算採用Context.startService()方 法啟動服務,在服務未被建立時,系統會先調用服務的onCreate()方 法,接著調用onStart()方法。如果調用startService()方法前服務已經被建立,多次調用startService()方法並不會導致多次建立服務,但會導致多次調 用onStart()方法。採用startService()方法啟動的服務,只能調用Context.stopService()方法結束服務,服務結束時會調 用onDestroy()方法。
如果打算採用Context.bindService()方 法啟動服務,在服務未被建立時,系統會先調用服務的onCreate()方 法,接著調用onBind()方法。這個時候調用者和服務綁定 在一起,調用者退出了,系統就會先調用服務的onUnbind()方 法,接著調用onDestroy()方法。如果調用bindService()方法前服務已經被綁定,多次調用bindService()方法並不會導致多次建立服務及綁定(也就是說onCreate()和onBind()方 法並不會被多次調用)。如果調用者希望與正在綁定的服務解除綁 定,可以調用unbindService()方法,調用該方法 也會導致系統調用服務的onUnbind()-->onDestroy()方 法。
服務常用生命週期回調方法如下:
onCreate() 該方法在服務被建立 時調用,該方法只會被調用一次,無論調用多少次startService()或bindService()方法,服務也只被建立一次。
onDestroy()該方法在服務被終止時調用。
與採用Context.startService()方 法啟動服務有關的生命週期方法
onStart() 只有採用Context.startService()方 法啟動服務時才會回調該方法。該方法在服務開始運行時被調用。多次調用startService()方 法儘管不會多次建立服務,但onStart() 方法會被多次調用。
與採用Context.bindService()方 法啟動服務有關的生命週期方法
onBind()只有採用Context.bindService()方 法啟動服務時才會回調該方法。該方法在調用者與服務綁定時被調用,當調用者與服務已經綁定,多次調用Context.bindService()方法並不會導致該方法被多次調用。
onUnbind()只有採用Context.bindService()方 法啟動服務時才會回調該方法。該方法在調用者與服務解除綁定時被調用
採用Context.startService()方法啟動服務的代碼如下:
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()方法啟動服務的代碼如下:
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);//解除綁定
}});
}
}