Android四大組件之Activity

1. 什么是Activity

  • Activity負(fù)責(zé)UI元素的加載與頁面之前的跳轉(zhuǎn),代表了一個頁面單元。

2. Activity的構(gòu)成

  • Activity的構(gòu)成并不是一個Activity對象再加上一個布局那么簡單,在Activity和開發(fā)人員設(shè)置的視圖之間還隔著兩層。
  • 實(shí)際上視圖會被設(shè)置給一個Window類,這個Window中含有一個DecorView,這個DecorView才是整個窗口的頂級視圖。開發(fā)人員設(shè)置的布局會被設(shè)置到這個DecorView的mContentParent布局中。
  • 也就是說Android中實(shí)際上內(nèi)置了一些系統(tǒng)布局文件xml,我們在xml中定義的視圖最終會被設(shè)置到這些系統(tǒng)布局的特定節(jié)點(diǎn)之下,這樣就形成了整個的DecorView。

3. 隱式啟動Activity

  • 顯式Intent指的是Intent的“意圖”非常明顯,指明了從哪個活動跳轉(zhuǎn)到哪個活動。隱式Intent并不明確指出啟動哪一個活動,而是指定一系列更為抽象的action和category信息,然后交由系統(tǒng)去分析這個intent,并幫我們找到合適的活動去啟動。

  • 默認(rèn)的category的intent

  1. 創(chuàng)建FirstActivity,并且在配置文件中配置action和category:
public class FirstActivity extends Activity  {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_first);
    }
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <TextView
        android:id="@+id/bt_first"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center"
        android:text="I am FirstActivity"
        android:textSize="50px" />

</LinearLayout>
 <activity android:name=".FirstActivity">
        <intent-filter>
            <action android:name="com.fkq.menu.First" />
            <category android:name="android.intent.category.DEFAULT"/>
        </intent-filter>
</activity>

說明:

  1. 在<action>標(biāo)簽中我們指明了當(dāng)前活動可以響應(yīng) com.fkq.menu.First 這個action,而<category>標(biāo)簽則包含一些附加信息,更精確地指明了當(dāng)前的活動能夠響應(yīng)的Intent中還可能帶有的category。
  2. 只有<action>和<category>中的內(nèi)容同時能夠匹配上Intent指定的action和category時,這個活動才能響應(yīng)該Intent。

2.修改MainActivity,進(jìn)行跳轉(zhuǎn):

    @InjectView(R.id.bt_main)
    Button btMain;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ButterKnife.inject(this);
        btMain.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                switch (view.getId()){
                    case R.id.bt_main:
                        startActivity(new Intent("com.fkq.menu.First"));
                }
            }
        });
    }

說明:android.intent.category.DEFAULT 是默認(rèn)的category,在調(diào)用startActivity方法的時候會自動將這個category添加到Intent中。

  • 非默認(rèn)的category的intent

每個Intent中只能指定一個action,但卻能指定多個category。

1.修改配置文件的category,即添加一個:

<activity android:name=".FirstActivity">
            <intent-filter>
                <action android:name="com.fkq.menu.First" />
                <category android:name="android.intent.category.DEFAULT"/>
                <category android:name="com.fkq.menu.my_category"/>
            </intent-filter>
</activity>

2.修改MainActivity的startActivity部分代碼:

Intent intent = new Intent("com.fkq.menu.First");
    intent.addCategory("com.fkq.menu.my_category");
    startActivity(intent);

4. 更多Intent用法

1. 簡單示例

使用隱式Intent,不僅可以啟動自己程序內(nèi)的活動,還可以啟動其他程序的活動,這使得Android多個應(yīng)用程序之間的功能共享成為了可能。

比如應(yīng)用程序中需要展示一個網(wǎng)頁,只需要調(diào)用系統(tǒng)的瀏覽器來打開這個網(wǎng)頁即可。

Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("http://www.baidu.com"));
startActivity(intent);

說明:

  1. 首先指定了Intent的action是Intent.ACTION_ViEW,這是一個Android系統(tǒng)內(nèi)置的動作,其常量值為android.intent.action.VIEW.
  2. 然后通過Uri.parse方法,將一個網(wǎng)址字符串解析承一個Uri對象。
  3. 再調(diào)用Intent的setData方法將這個Uri對象傳遞進(jìn)去。

再次說明:
setData方法接收一個Uri對象,主要用于指定當(dāng)前Intent正在操作的數(shù)據(jù),而這些數(shù)據(jù)通常都是以字符串的形式傳入到Uri.parse方法中解析產(chǎn)生的。

2. 配置data標(biāo)簽

我們可以在<intent-filter>標(biāo)簽中再配置一個<data>標(biāo)簽,用于更精確地指定當(dāng)前活動能夠響應(yīng)什么類型的數(shù)據(jù)。<data>標(biāo)簽中主要可以配置以下內(nèi)容:

  1. android:scheme 用于指定數(shù)據(jù)的協(xié)議部分,如上例中的http部分。
  2. android:host 用于指定數(shù)據(jù)的主機(jī)名部分,如上例中的www.baidu.com部分。
  3. android:port 用于指定數(shù)據(jù)的端口部分,一般緊跟在主機(jī)名之后。
  4. android:path 用于指定主機(jī)名和端口之后的部分,如一段網(wǎng)址中跟在域名之后的內(nèi)容。
  5. android:mimeType 用于指定可以處理的數(shù)據(jù)類型,允許使用通配符的方式進(jìn)行指定。

注意:只有<data>標(biāo)簽中指定的內(nèi)容和Intent中攜帶的Data完全一致時,當(dāng)前活動才能夠響應(yīng)該Intent。不過一般在<data>標(biāo)簽中都不會指定過多的內(nèi)容,如上面瀏覽器示例中,其實(shí)只需要指定android:scheme為http,就可以響應(yīng)所有的http協(xié)議的Intent了。

修改配置文件如下:

 <activity android:name=".FirstActivity">
        <intent-filter>
            <action android:name="android.intent.action.VIEW" />
            <category android:name="android.intent.category.DEFAULT" />
            <data android:scheme="http" />
        </intent-filter>
</activity>

說明:<data>標(biāo)簽中通過android:sheme指定了數(shù)據(jù)的協(xié)議必須是http協(xié)議,這樣就和瀏覽器一樣,能夠響應(yīng)一個打開網(wǎng)頁的Intent了。

Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("http://www.baidu.com"));
startActivity(intent);

除了http協(xié)議外,我們還可以指定很多其他協(xié)議,比如geo表示顯示地理位置、tel表示撥打電話。

<intent-filter>
    <action android:name="android.intent.action.DIAL" />
    <category android:name="android.intent.category.DEFAULT" />
    <data android:scheme="tel" />
</intent-filter>
Intent intent = new Intent(Intent.ACTION_DIAL);
intent.setData(Uri.parse("tel:10086"));
startActivity(intent);

說明:

  1. 首先指定Intent的action是Intent.ACTION_DIAL,這又是Android系統(tǒng)的內(nèi)置動作。
  2. 然后在data部分指定了協(xié)議是tel,號碼是10086。

5. 向下一個活動傳遞數(shù)據(jù)

發(fā)送:

String data = "hello world";
Intent intent = new Intent(MainActivity.this,FirstActivity.class);
intent.putExtra("mydata",data);
startActivity(intent);

說明:通過putExtra方法傳遞一個字符串,接收兩個參數(shù),第一個參數(shù)是鍵,用于從Intent中取值,第二個參數(shù)才是真正要傳遞的數(shù)據(jù)。

接收:

Intent intent = getIntent();
String data = intent.getStringExtra("mydata");
Toast.makeText(this, "傳遞過來的值是" + data, Toast.LENGTH_SHORT).show();

說明:通過getIntent方法獲取到用于啟動FirstActivity的Intent,然后調(diào)用getStringExtra方法來獲取傳遞的數(shù)據(jù)。如果是整型數(shù)據(jù),則使用getIntExtra方法,如果是布爾數(shù)據(jù),則使用getBooleanExtra方法。

6. 返回?cái)?shù)據(jù)給上一個活動

Activity中有一個startActivityForResult方法用于啟動活動,期望在活動銷毀的時候能夠返回一個結(jié)果給上一個活動。

  • 示例:MainActivity跳轉(zhuǎn)到FirstActivity,F(xiàn)irstActivity銷毀返回?cái)?shù)據(jù)給MainActivity

MainActivity:

@Override
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.bt_trans:
                Intent intent = new Intent(MainActivity.this, FirstActivity.class);
                startActivityForResult(intent, 1);
        }
    }

    @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.e("MainActivity",returnedData);
                }
        }
    }

說明:

  1. startActivityForResult方法接收兩個參數(shù),第一個參數(shù)還是intent,第二個參數(shù)是請求碼,用于在之后的回調(diào)中判斷數(shù)據(jù)的來源。
  2. 使用startActivityForResult方法啟動SecondActivity,請求碼只要是唯一值就可以了,這里傳入了1。

FirstActivity:

Button button = (Button) findViewById(R.id.bt_re_data);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                switch (view.getId()){
                    case R.id.bt_re_data:
                        Intent intent = new Intent();
                        intent.putExtra("data_return","hello");
                        setResult(RESULT_OK,intent);
                        finish();
                        break;
                }
            }
        });

說明:

  1. 在FirstActivity里面給按鈕添加點(diǎn)擊事件,并添加返回?cái)?shù)據(jù)的邏輯。
  2. 構(gòu)建一個Intent僅僅用于傳遞數(shù)據(jù)而已,緊接著把要傳遞的數(shù)據(jù)存放在Intent中,然后調(diào)用setResult方法,專門用于向上一個活動返回?cái)?shù)據(jù)的。
  3. setResult方法接收兩個參數(shù),第一個參數(shù)用于向上一個活動返回處理結(jié)果,一般只使用RESULT_OK或RESULT_CANCELED這兩個值,第二個參數(shù)則把帶有數(shù)據(jù)的intent傳遞回去,然后調(diào)用finish方法銷毀當(dāng)前活動。
  4. 由于使用startActivityForResult方法來啟動FirstActivity的,在FirstActivity被銷毀之后會回調(diào)MainActivity的onActivityResult方法,因此我們需要在MainActivity中重寫這個方法來得到返回的數(shù)據(jù)。
  5. onActivityResult方法帶有三個參數(shù),第一個參數(shù)requestCode,就是啟動活動的時候傳入的請求碼。第二個參數(shù)resultCode,就是我們在返回?cái)?shù)據(jù)時傳入的處理結(jié)果。第三個參數(shù)data,就是攜帶著返回?cái)?shù)據(jù)的Intent。
  6. 由于一個活動中可能調(diào)用startActivityForResult方法去啟動很多不同的活動,每一個活動返回的數(shù)據(jù)都會回調(diào)到onActivityResult這個方法中,因此首先要做得就是檢查requestCode的值來判斷數(shù)據(jù)來源。確定數(shù)據(jù)是從FirstActivity返回的之后,再通過resultCode的值來判斷處理結(jié)果是否成功。最后從data中取值并打印出來,這樣就完成了向上一個活動返回?cái)?shù)據(jù)的工作。

疑問:
假如FirstActivity中不用按鈕來銷毀活動,而是通過點(diǎn)擊Back鍵,那如何處理呢?很簡單:在FirstActivity中重寫onBackPressed方法來解決這個問題。

@Override
public void onBackPressed() {
    Intent intent = new Intent();
    intent.putExtra("data_return","hello");
    setResult(RESULT_OK,intent);
    finish();
}

7. 活動的生命周期

返回棧

Android是用任務(wù)(Task)來管理活動的,一個任務(wù)就是一組存放在棧里的活動的集合,這個棧也被稱作返回棧。

每當(dāng)我們啟動一個新的活動,它會在返回棧中入棧,并處于棧頂?shù)奈恢?。每?dāng)我們按下Back鍵或調(diào)用finish方法去銷毀一個活動時,處于棧頂?shù)幕顒訒鰲?,這時前一個入棧的活動就會重新處于棧頂?shù)奈恢谩?/p>

系統(tǒng)總是會顯示處于棧頂?shù)幕顒咏o用戶。

活動狀態(tài)

  1. 運(yùn)行狀態(tài):當(dāng)一個活動處于棧頂時,這個活動就處于運(yùn)行狀態(tài)。
  2. 暫停狀態(tài):當(dāng)一個活動不處于棧頂,但是依然可見的時候,這個活動就進(jìn)入了暫停狀態(tài)。如:對話框后面的活動。
  3. 停止?fàn)顟B(tài):當(dāng)一個活動不處于棧頂,并且完全不可見的時候,就進(jìn)入了停止?fàn)顟B(tài)。系統(tǒng)仍然會為這種活動保存相應(yīng)的狀態(tài)和成員變量。當(dāng)其他地方需要內(nèi)存時,活動可能會被系統(tǒng)回收。
  4. 銷毀狀態(tài):當(dāng)一個活動從返回棧中移除后就變成了銷毀狀態(tài)。
  5. 由于可見的活動被回收,用戶體驗(yàn)不好,所以系統(tǒng)最不愿意回收運(yùn)行和暫停狀態(tài)的活動,當(dāng)內(nèi)存緊張的時候,會優(yōu)先回收銷毀狀態(tài)和停止?fàn)顟B(tài)的活動。

活動的生存期

  • Activity類中定義了7個回調(diào)方法,覆蓋了活動生命周期的每一個環(huán)節(jié):
  1. onCreate:
    活動第一次被創(chuàng)建的時候調(diào)用,所以在這個活動中完成初始化操作:加載布局,綁定事件等。
  2. onStart:
    活動由不可見變?yōu)榭梢姷臅r候調(diào)用。
  3. onResume:
    活動準(zhǔn)備好和用戶進(jìn)行交互的時候調(diào)用。
  4. onPause:
    這個活動在系統(tǒng)準(zhǔn)備去啟動或者恢復(fù)另一個活動的時候調(diào)用。通常會在這個方法中將一些消耗CPU的資源釋放掉,以及保存一些關(guān)鍵數(shù)據(jù),但是這個活動執(zhí)行速度一定要快,不然會影響新的棧頂活動的使用。
  5. onStop:
    這個方法在活動完全不可見的時候調(diào)用。與onPause方法主要區(qū)別是:如果啟動的新活動是一個對話框式的活動,那么onPause方法會得到執(zhí)行,而onStop方法并不會。
    當(dāng)活動執(zhí)行了onStop方法,此時另一個優(yōu)先級更高的程序需要內(nèi)存,可能會殺掉進(jìn)程,這時再啟動的話,會先執(zhí)行onCreate方法。
  6. onDestory:
    活動被銷毀前調(diào)用。
  7. onRestart:
    活動由停止?fàn)顟B(tài)變?yōu)檫\(yùn)行狀態(tài)之前調(diào)用,即重新啟動時調(diào)用,意思就是當(dāng)一個活動執(zhí)行了onStop方法,但是并沒有執(zhí)行onDestory方法時,如果被重新啟動,會執(zhí)行onRestart方法,然后會執(zhí)行onStart方法,而不會重新執(zhí)行onCreate方法。
  • 以上活動又分為3種生存期
  1. 完整生存期:活動在onCreate方法和onDestroy方法之間所經(jīng)歷的,就是完整生存期。
  2. 可見生存期:活動在onStart和onStop方法之間所經(jīng)歷的,就是可見生存期。在這個生存期內(nèi),onStart方法對資源進(jìn)行加載,而在onStop方法對資源進(jìn)行釋放,合理管理對用戶可見的資源。
  3. 前臺生存期:活動在onResume方法和onPause方法之間就是前臺生存期。

體驗(yàn)活動的生命周期

1.創(chuàng)建MainActivity:

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    private static final String TAG = "MainActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d(TAG, "onCreate");
        setContentView(R.layout.activity_main);
        Button startNormalActivity = (Button) findViewById(R.id.start_normal_activity);
        Button startDialogActivity = (Button) findViewById(R.id.start_dialog_activity);
        startNormalActivity.setOnClickListener(this);
        startDialogActivity.setOnClickListener(this);
    }

    @Override
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.start_normal_activity:
                startActivity(new Intent(this, NormalActivity.class));
                break;
            case R.id.start_dialog_activity:
                startActivity(new Intent(this, DialogActivity.class));
                break;
        }
    }

    @Override
    protected void onStart() {
        super.onStart();
        Log.d(TAG, "onStart");
    }

    @Override
    protected void onResume() {
        super.onResume();
        Log.d(TAG, "onResume");
    }

    @Override
    protected void onPause() {
        super.onPause();
        Log.d(TAG, "onPause");
    }

    @Override
    protected void onStop() {
        super.onStop();
        Log.d(TAG, "onStop");
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.d(TAG, "onDestroy");
    }

    @Override
    protected void onRestart() {
        super.onRestart();
        Log.d(TAG, "onRestart");
    }
}

2.創(chuàng)建DialogActivity和NormalActivity:

public class DialogActivity extends AppCompatActivity {
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_dialog);
    }
}
public class NormalActivity extends AppCompatActivity {
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_normal);
    }
}

3.修改配置文件:

<activity android:name=".NormalActivity"></activity>
<activity
    android:name=".DialogActivity"
    android:theme="@style/Theme.AppCompat.Dialog">
</activity>

注意:由于類繼承的是AppCompatActivity,所以主題應(yīng)該是AppCompat里面的,否則會報(bào)錯。

說明:針對MainActivity

  1. 進(jìn)入應(yīng)用程序,MainActivity第一次被創(chuàng)建會依次執(zhí)行onCreate、onStart、onResume方法
  2. 啟動NormalActivity,MainActivity會執(zhí)行onPause和onStop方法,因?yàn)镹ormalActivity把MainActivity完全遮掩住了。
  3. 按下Back返回MainActivity,MainActivity會執(zhí)行onRestart方法,然后執(zhí)行onStart和onResume方法,因?yàn)橹癕ainActivity已經(jīng)進(jìn)入了停止?fàn)顟B(tài),所以onRestart方法;之所以onCreate方法沒有執(zhí)行,因?yàn)镸ainActvity并沒有重新創(chuàng)建。
  4. 啟動DialogActivity,MainActivity只會執(zhí)行onPause方法,onStop方法并沒有執(zhí)行,因?yàn)镈ialogActivity并沒有完全遮掩住MainActivity,MainActivity只是進(jìn)入了暫停狀態(tài),并沒有進(jìn)入停止?fàn)顟B(tài)。相應(yīng)地,按下Back鍵返回MainActivity也應(yīng)該只有onResume方法會得到執(zhí)行。
  5. 在MainActivty頁面按下Back鍵推出程序,依次執(zhí)行onPause、onStop、onDestory方法。

8. 活動被回收了怎么辦

當(dāng)活動被銷毀以后,可能會銷毀掉活動中原有的數(shù)據(jù),比如EditText中輸入的內(nèi)容。為了解決這個問題,Android提供了一個onSaveInstanceState回調(diào)方法,這個方法可以保證在活動被回收之前一定會被調(diào)用。

onSaveInstanceState方法會攜帶一個Bundle類型的參數(shù),Bundle提供了一系列的方法用于保存數(shù)據(jù),比如可以使用putString保存字符串,使用putInt方法保存整形數(shù)據(jù),以此類推。每個保存方法需要傳入兩個參數(shù),第一個參數(shù)是鍵,用于后面從Bundle中取值,第二個參數(shù)是真正要保存的內(nèi)容。

 @Override
    public void onSaveInstanceState(Bundle outState) {
        String tempdata = "something you just typed";
        outState.putString("data_key",tempdata);
        super.onSaveInstanceState(outState);
        Log.e(TAG,"此時被調(diào)用");
    }
@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        if (savedInstanceState!=null){
            String tempdata = savedInstanceState.getString("data_key");
            Toast.makeText(this,"tempdata::"+tempdata,Toast.LENGTH_SHORT).show();
        }
    }

說明:

  1. 利用手機(jī)的橫豎屏切換,可以完美做模擬,先調(diào)用onSaveInstanceState,然后調(diào)用onCreate。
  2. onCreate方法中有一個Bundle類型的參數(shù)。這個參數(shù)在一般情況下都是null,但是如果在活動被系統(tǒng)回收之前有通過onSaveInstanceState方法來保存數(shù)據(jù)的話,這個參數(shù)就會帶有之前所保存的全部數(shù)據(jù)。

9. 活動的啟動模式和應(yīng)用場景

啟動模式有4種,分別是standard、singleTop、singleTask和singleInstance,可以在配置文件中通過給<activity>標(biāo)簽指定android:launchMode屬性來選擇啟動模式。

standard

不管活動是否已經(jīng)在返回棧中存在,每次啟動都會創(chuàng)建一個新的實(shí)例,并且位于棧頂。

singleTop

在啟動活動時如果發(fā)現(xiàn)返回棧的棧頂已經(jīng)是該活動,則認(rèn)為可以直接使用它,不會再創(chuàng)建新的活動實(shí)例。

應(yīng)用場景:下拉欄通知界面點(diǎn)擊進(jìn)入一個頁面的情景,避免了因?yàn)槎啻螁訉?dǎo)致的需要返回多次的情況。

singleTask

每次啟動該活動時系統(tǒng)首先會在返回棧中檢查是否存在該活動的實(shí)例,如果發(fā)現(xiàn)已經(jīng)存在則直接使用該實(shí)例,并把在這個活動之上的所有活動統(tǒng)統(tǒng)出棧,如果沒有發(fā)現(xiàn)就會創(chuàng)建一個新的活動示例。

應(yīng)用場景: 例如瀏覽器的主界面。不管從多少個應(yīng)用啟動瀏覽器,只會啟動主界面一次,其余情況都會走onNewIntent,并且會清空主界面上面的其他頁面。之前打開過的頁面,打開之前的頁面就ok,不再新建.

singleInstance

啟動一個新的返回棧來管理這個活動。假設(shè)我們的程序中有一個活動是允許其他程序調(diào)用的,如果我們想實(shí)現(xiàn)其他程序和我們的程序可以共享這個活動的案例,使用之前的三種模式是做不到的,因?yàn)槊總€應(yīng)用程序都有自己的返回棧,同一個活動在不同的返回棧中入棧時必然是創(chuàng)建了新的實(shí)例。而使用singleInstance模式就可以解決這個問題,在這個種模式下會有一個單獨(dú)的返回棧來管理活動,不管是哪個應(yīng)用程序來訪問這個活動,都共用同一個返回棧,也就解決了共享活動實(shí)例的問題。

栗子:FirstActivity跳轉(zhuǎn)到SecondActivity,然后在SecondActivity進(jìn)入到THirdActivity。SecondActivity單獨(dú)在一個返回棧,F(xiàn)irstActivity和THirdActivity在一個返回棧。點(diǎn)擊Back,ThirdActivity直接返回到FirstActivity,再按下Back鍵又會返回到SecondActivity,再按下Back鍵會推出程序。

原理:FirstA和ThridA存放在同一個返回棧,當(dāng)在ThridA的界面按下Back鍵,ThridAcitivy會從返回棧出棧,F(xiàn)irstA成為棧頂活動顯示在界面上。在FirstA界面上按下Back鍵,當(dāng)前的返回棧空了就顯示了另一個返回棧的棧頂活動,即SecondActivity,按下Back,所有的返回??樟?,退出程序。

應(yīng)用場景: 比如通話頁面、鬧鈴提醒頁面.

10. 動態(tài)設(shè)置活動的啟動模式

  • FLAG_ACTIVITY_NEW_TASK

舉例說明:經(jīng)過測試,并沒有開啟一個額外的任務(wù)棧,并且會重新創(chuàng)建。(如果測試不正確,后期會修改)

  • FLAG_ACTIVITY_SINGLE_TOP

舉例說明:棧中有A B C D四個活動,在D中用這個Flag啟動D,現(xiàn)在棧中有A B C D 四個活動,D不會重新創(chuàng)建,會回調(diào)onNewIntent方法。

  • FLAG_ACTIVITY_CLEAR_TOP

舉例說明:棧中有A B C D 四個活動,在D中用這個Flag啟動B,此時棧中只有A B ,B會重新創(chuàng)建。

  • FLAG_ACTIVITY_NO_HISTORY

舉例說明:棧中有A B C D 四個活動,在D中用這個Flag啟動B,B會重新創(chuàng)建,此時棧中有A B C D 新B,然后從新B打開C,現(xiàn)在棧中有A B C D C 五個活動。

  • FLAG_ACTIVITY_BROUGHT_TO-FRONT

舉例說明:我們有A,A打開B,B打開C,C打開D,D然后以這個Flag啟動B, 此時棧的情況就是A,C,D,B。B不會重新創(chuàng)建,回調(diào)onNewIntent方法。

  • FLAG_ACTIVITY_CLEAR_TOP和FLAG_ACTIVITY_NEW_TASK

舉例說明: 我看郭霖博客,這兩個Flag可以讓Activity不會重新創(chuàng)建,但是經(jīng)過我測試,依然會重新創(chuàng)建。(如果測試不正確,后期會修改)

11. 知曉當(dāng)前是在哪一個活動

創(chuàng)建BaseActivity,讓FirstActivity、SecondActivity、ThirdActivity繼承BaseAcitify,點(diǎn)擊進(jìn)入FirstActivity、SecondActivity、ThirdActivity,Log就會打印出當(dāng)前活動的名稱。BaseActivity代碼如下:

public class BaseActivity extends AppCompatActivity {

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d("BaseActivity",getClass().getSimpleName());
    }
}

12.隨時隨地退出程序

  1. 新建ActivityCollector:
public class ActivityCollector {
    public static List<Activity> activities = new ArrayList<>();

    public static void addActivity(Activity activity) {
        activities.add(activity);
    }

    public static void removeActivity(Activity activity) {
        activities.remove(activity);
    }

    public static void finishAll() {
        for (Activity activity : activities) {
            if (!activity.isFinishing()) {
                activity.finish();
            }
        }
    }
}

2.新建BaseActivity:

public class BaseActivity extends AppCompatActivity {

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d("BaseActivity",getClass().getSimpleName());
        ActivityCollector.addActivity(this);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        ActivityCollector.removeActivity(this);
    }
}

3.新建FirstActivity繼承BaseActivity:

ActivityCollector.finishAll();
android.os.Process.killProcess(android.os.Process.myPid());

說明:

  1. FirstActivity繼承BaseActivity,啟動FirstActivity,F(xiàn)irstActivity這個類就會被保存到集合里面。
  2. 如果FirstActivit被系統(tǒng)內(nèi)存回收銷毀后,集合會把FirstActivit移除。
  3. 想退出程序,只需清空集合即可。
  4. 為了保證程序完全退出,殺掉當(dāng)前進(jìn)程:killProcess方法用于殺掉一個進(jìn)程,它接收一個進(jìn)程id參數(shù),我們可以通過myPid()方法來獲得當(dāng)前程序的進(jìn)程id。

13. 啟動活動的最佳寫法

假設(shè)SecondActivity中需要用到兩個非常重要的字符串參數(shù),在啟動MainActivity的時候必須要傳遞過來:

Intent intent = new Intent(this,MainActivity.class);
intent.putExtra("param1","data1");
intent.putExtra("param2","data2");
startActivity(intent);
public static void actionStart(Context context, String data1, String data2) {
        Intent intent = new Intent(context, SecondActivity.class);
        intent.putExtra("param1", data1);
        intent.putExtra("param2", data2);
        context.startActivity(intent);
}
MainActivity.actionStart(this,"data1","data2");
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容