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存儲數據;
--網絡存儲數據;
在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);//解除綁定
}});
}
}