《第一行代碼--Android》讀書筆記之日誌工具Log與Activity

日誌工具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的關係:
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

發佈了32 篇原創文章 · 獲贊 45 · 訪問量 13萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章