日誌工具Log
Log.v(String tag,String msg);//verbose級別,最瑣碎
Log.d(String tag,String msg);//debug級別,調試程序分析問題
Log.i(String tag,String msg);//info級別,幫助分析用戶行爲
Log.w(String tag,String msg);//warn級別,警告信息
Log.e(String tag,String msg);//error級別,打印錯誤信息
下面給出本書後面的自定義日誌工具類,方便開發調試使用打印日誌和發佈打包的時候屏蔽日誌
import android.util.Log;
public class LogUtil {
public static final int VERBOSE=1;
public static final int DEBUG=2;
public static final int INFO=3;
public static final int WARN=4;
public static final int ERROR=5;
public static final int NOTHING=6;
public static final int LEVEL=VERBOSE;
//LEVEL設置爲VERBOSE表示級別最高,此工具類會打印所有信息,設置成NOTHING,此工具類不會打印任何日誌
public static void v(String tag,String msg){
if (LEVEL<=VERBOSE){
Log.v(tag,msg);
}
}
public static void d(String tag,String msg){
if (LEVEL<=DEBUG){
Log.d(tag,msg);
}
}
public static void i(String tag,String msg){
if (LEVEL<=INFO){
Log.i(tag,msg);
}
}
public static void w(String tag,String msg){
if (LEVEL<=WARN){
Log.w(tag,msg);
}
}
public static void e(String tag,String msg){
if (LEVEL<=ERROR){
Log.e(tag,msg);
}
}
}
Activity
Activity的創建與註冊
創建:1.新建一個佈局文件(xml)
2.新建一個.java文件,自定義類繼承自Activity,重寫onCreate()函數
public class BaseActivity extends Activity{
@Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
//隱藏活動標題欄
requestWindowFeature(Window.FEATURE_NO_TITLE);
//Log.d("BaseActivity", getClass().getSimpleName());
setContentView(R.layout.first_layout);
}
最後別忘了註冊哦,在AndroidManifest文件的< application >標籤內註冊activity
<activity
android:name=".FirstActivity"
android:launchMode="singleTask"
android:label="This is FirstActivity!">
<intent-filter>//若這是一個主活動,需要這樣寫
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
在Activity中使用Menu
1.在res文件夾中創建一個menu文件夾→創建Android XML File
→在activity中重寫onCreateOptionsMenu(Menu menu)
→重寫public boolean onOptionsItemSelected(MenuItem item)編寫響應菜單項代碼
Android XML File:
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/add_item"
android:title="Add"/>
<item
android:id="@+id/remove_item"
android:title="Remove"/>
</menu>
activity.java:
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu, menu);
return true;
}
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.add_item:
Toast.makeText(FirstActivity.this, "you clicked Add", Toast.LENGTH_SHORT).show();
break;
case R.id.remove_item:
Toast.makeText(FirstActivity.this, "you clicked Remove", Toast.LENGTH_SHORT).show();
default:
break;
}
return true;
}
Intent之於活動
創建Activity
顯式Intent:
Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
startActivity(intent);
隱式Intent:
含蓄的Intent需要指定一系列action和category等信息,只有AndroidManifest的< activity>中< action>和< category>與intent的action和category完全匹配才能啓動該activity。
<action android:name="com.example.activitytest.ACTION_START"/>
<category android:name="com.example.activitytest.MY_CATEGORY"/>
Intent intent=new Intent("com.example.activitytest.ACTION_START"); intent.addCategory("com.example.activitytest.MY_CATEGORY");
隱式intent還可以用來啓動其他程序的活動
在< intent-filter>標籤中在配置一個< data>標籤
Intent intent1=new Intent(Intent.ACTION_VIEW);
intent1.setData(Uri.parse("http://www.baidu.com"));
//<data android:scheme="http"/> 在AndroidManifest中配置
Intent intent=new Intent(Intent.ACTION_DIAL);
intent.setData(Uri.parse("tel:10086"));
////<data android:scheme="tel"/>
startActivity(intent1);
Intent傳遞數據的使者
1、可以通過intent.putExtra(String keyname, String value) 把數據暫存到intent中,啓動到另一個活動後,再把數據通過鍵值從intent中取出。
Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
String data="Hello SecondActivity";
intent.putExtra("extra_data",data);
startActivity(intent);
Intent intent=getIntent();
String data=intent.getStringExtra("extra_data");
Log.d("SecondActivity",data);
2、返回數據給上一個活動
父活動:
Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
startActivityForResult(intent,1);//第二個參數是請求碼
子活動:
Intent intent = new Intent();
String data = "Hello FirstActivity";
intent.putExtra("data_return", data);
setResult(RESULT_OK, intent);//專用於向上一個活動返回數據,第一個參數是用於向上一個活動返回處理結果,一般是RESULT_OK,RESULT_CANCELED
finish();//銷燬活動,回調onActivityResult,可以在此方法得到返回數據。
//按返回鍵銷燬活動的回調函數
@Override
public void onBackPressed(){
Intent intent=new Intent();
intent.putExtra("data_return","Hello FirstActivity");
setResult(RESULT_OK, intent);
finish();
}
父活動中重寫此活動,得到返回的數據:
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case 1:
if (resultCode == RESULT_OK) {
String returnedData = data.getStringExtra("data_return");
Log.d("FirstActivity", returnedData);
}
break;
default:
break;
}
}
—-圖來自android編程權威指南
3、我們還可以通過intent來傳遞對象
(a)、Serializable方式,將整個對象序列化。
只需要讓該對象implement Serializable接口,寫一系列set,get方法來爲對象的數據做賦值和讀取。
比如,FirstActivity:
Person person=new Person();
person.setName("TellH");
Person.setAge(20);
Intent intent=new Intent(FirstActivity.this,SecondActivity.class);
intent.putExtra("person_data",person):///假如Person類已經實現了Serializable接口
startActivity(intent);
SecondActivity:
Person person=(Person)getIntent().getSerializableExtra("person_data");
(b)、Parcelable方式:
public class Person implements Parcelable {
private String name;
private int age;
//需要重寫一下兩個方法
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {//將數據一一打包,寫入Parcel
dest.writeString(name);
dest.writeInt(age);
}
//創建一個Parcelable.Creator<Person>接口的實現,重寫兩個方法
private static final Parcelable.Creator<Person> CREATOR=new Parcelable.Creator<Person>(){
@Override
public Person createFromParcel(Parcel source) {//從Parcel讀取數據
Person person= new Person();
//這裏的讀出數據的順序一定要和寫入數據的順序要一致
person.name=source.readString();
person.age=source.readInt();
return person;
}
@Override
public Person[] newArray(int size) {
return new Person[size];
}
};
}
這裏深入瞭解一下intent的通信:
intent對象是component用來與操作系統通信的一種媒介工具。當調用startActivity()方法是,該方法把intent發送給操作系統的ActivityManager,ActivityManager負責創建Activity實例並調用其onCreate()方法,這種模式會使在不同應用間的Activity的交互變得容易得多。
活動的生命週期
1、返回棧(back stack==Task)
Task是一個具有棧結構的對象,一個Task就是一組activity的集合。這些activity按照它們打開的順序被放置於一個先進後出的棧中(back stack)。用戶點擊圖標打開一個app時,該app的task會被移到前臺顯示。如果當前沒有該app的task,系統將會新建一個task並在其中運行Main activity。如果HOME鍵被按下,從當前app回到桌面,該app的Task會被移到後臺,後臺的task所屬的所有activity都是stop狀態,且back stack依然存在——這個task其實只是失去了和用戶交互的焦點。
taskAffinity屬性:每個Activity都有taskAffinity屬性,這個屬性指出了它希望進入的Task。如果一個Activity沒有顯式的指明該Activity的taskAffinity,那麼它的這個屬性就等於Application指明的taskAffinity,如果Application也沒有指明,那麼該taskAffinity的值就等於包名。而Task也有自己的affinity屬性,它的值等於它的根Activity的taskAffinity的值。
Task與Activity,application的關係:
2、活動生存期
(a)、當任務被創建和銷燬分別會回調onCreate()和onDestroy()
(b)、當任務進入前臺或者解鎖屏(由不可見到可見)和退出前臺進入後臺或者被鎖屏(由可見到不可見)時分別會回調onStart()和onStop()
(c)、當任務(位於返回棧的棧頂)要準備與用戶進行交互的時候回調onResume();
但當任務要準備被另一個活動或對話框覆蓋,需要釋放掉系統資源,保存關鍵數據,回調onPause(),此時任務仍然可見,但不能與用戶進行交互。
(d)、但任務從stop狀態變爲start狀態前,先回調onRestart()。
(e)、其他的Activity狀態方法
onWindowFocusChanged方法:在Activity窗口獲得或失去焦點時被調用,例如創建時首次呈現在用戶面前;當前Activity被其他Activity覆蓋;當前Activity轉到其他Activity或按Home鍵回到主屏,自身退居後臺;用戶退出當前Activity。
onSaveInstanceState:(1)在Activity被覆蓋或退居後臺之後,系統資源不足將其殺死,此方法會被調用,此方法會被調用,此方法攜帶一個Bundle類型的參數,利用bundle.putString(或者putInt,put~)向bundle寫入數據,在onCreate(Bundle savedInstanceState),或者onRestoreInstanceState(Bundle savedInstanceState),中獲取數據,恢復之前活動被回收的狀態;(2)在用戶改變屏幕方向時,此方法會被調用;(3)在當前Activity跳轉到其他Activity或者按Home鍵回到主屏,自身退居後臺時,此方法會被調用。onSaveInstanceState的調用順序是在onPause之前。
onRestoreInstanceState:(1)在Activity被覆蓋或退居後臺之後,系統資源不足時被回收,然後用戶又回到了此Activity;(2)在用戶改變屏幕方向時,重建的過程中,此方法會被調用。我們可以重寫此方法,以便可以恢復一些臨時數據。onRestoreInstanceState的調用順序是在onStart之後。
活動的啓動模式
在AndroidManifest中註冊活動的時候配置,< activity android:launchMode=”?”>
(a)、standard,默認模式,每次啓動該活動都會創建並往返回棧棧頂添加該活動的實例
(b)、singleTop,啓動該活動前檢查返回棧棧頂是否有該活動的實例,若有直接使用棧頂的實例,否則常見病往返回棧棧頂添加該活動的實例
(c)、singleTask,每次啓動該活動前都會先檢查是否存在與它的taskAffinity相同的Task。若存在該Task,檢查Task是否有該活動的實例,若有直接使用棧頂的實例,並把這活動之上的所有活動統統出棧,否則創建並往返回棧棧頂添加該活動的實例,將該Task調到前臺;若無則新建Task和該Activity實例,入棧。
(d)、singleInstance, 當要啓動該活動時,如果該Activity沒有被實例化,那麼就重新創建一個Task併入棧,並保證不再有其他Activity實例進入(即這個task中永遠只有一個activity),以便於其他應用程序共享該實例。如果已經被實例化,那麼就調用該Activity的onNewIntent;任何從該Activity加載的其它Actiivty(假設爲Activity2)都會被放入其它的Task中,如果存在與Activity2相同affinity的Task,則在該Task內創建Activity2。如果不存在,則重新生成新的Task併入棧。
singleInstance與singleTask的區別在於一個Task內只有一個Instance,活動的啓動過程都是相似的。
啓動活動的最佳寫法
在SecondActivity中添加一個actionStart()方法
public static void actionStart(Context context,String param1,String param2){
Intent intent=new Intent(context,SecondActivity.class);
intent.putExtra("param1",param1);
intent.putExtra("param2",param2);
context.startActivity(intent);
}
隨時隨地退出程序
用一個List< Activity>管理Activity。
public class ActivityCollector{
public static List<Activity> activities=new ArrayList<>();
public static void addActivity(Activity activity){//在每次onCreate()調用
activities.add(activity);
}
public static void removeActivity(Activity activity){//在每次onDestroy()調用
activities.remove(activity);
}
public static void finishAll(){
for(Activity activity:activities){
if(!activity.isFinishing()){
activity.finish();
activities.remove(activity);
}
}
}
查閱和參考的資料:
基礎總結篇之一:Activity生命週期:http://blog.csdn.net/liuhe688/article/details/6733407
基礎總結篇之二:Activity的四種launchMode:http://blog.csdn.net/liuhe688/article/details/6754323
Android開發中任務和返回棧:http://www.android100.org/html/201402/22/5690.html
Android中的“Application”,“Task”,“Activities”的關係:http://blog.csdn.net/mengweiqi33/article/details/7670541
Activity的taskAffinity屬性:http://blog.csdn.net/wangshione/article/details/8491249