Activity你應該知道的一切

Activity簡介

Activity是一種展示型組件,用于向用戶直接展示一個界面,并且可以接受用戶的輸入信息從而進行交互。Activity是最重要的一組組件,對用戶來說,Activity是一個Android用戶的全部,因為其他三大組件對于用戶來說都是不可感知的。Activity的啟動由Intent觸發(fā),其中Intent可以分為顯示Intent和隱式Intent。Activity是具有生命周期的。一個Acticity組件可以有不同的啟動模式,不同的啟動模式具有不同的效果。Intent可以用于Activity之間進行數(shù)據(jù)的傳遞。Activity組件是可以停止的,在實際開發(fā)過程中可以通過Activity的finish方法來結束Activity的運行。Activity扮演的是一種前臺界面的角色

Activity的生命周期

首先來看一張Activity的生命周期圖:


activity.png

正常情況下的生命周期分析

(1)第一次啟動一個Activity,回調方法:onCreate—>onStart—>onResume


a.gif

(2)當用戶按住Home鍵的時候,回調如下:onPause->onStop


b.gif

(3)當用戶再次返回到原Activity的時候,回調方法如下:
onRestart->onStart->onResume


c.gif

(4)當用戶按back鍵回退時,回調方法如下:onPause->onStop->onDestroy


d.gif

異常情況下的生命周期分析

e.png

(1)系統(tǒng)配置發(fā)生改變導致Activity被殺死并重新創(chuàng)建

比如說,當橫豎屏切換的時候,Activity就會被銷毀并重新創(chuàng)建,當然我們也可以阻止系統(tǒng)重新創(chuàng)建Activity。當系統(tǒng)配置發(fā)生變化是,在onStop之前會調用onSaveInstanceState方法來保存當前Activity的狀態(tài)。當Activity被重新創(chuàng)建后,系統(tǒng)會調用onRestoreInstanceState方法來恢復之前保存的狀態(tài),這個方法在onStart方法之后執(zhí)行。

看代碼:


package note.com.chapter_01;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import butterknife.ButterKnife;
import butterknife.InjectView;

/**
 * Created by zhoujian on 16/9/11.
 */
public class SecondActivity extends Activity {

    private static final String TAG = "SecondActivity";
    @InjectView(R.id.bt_back)
    Button mBtBack;
    private String mName;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);
        ButterKnife.inject(this);
        Log.e(TAG, "onCreate()方法執(zhí)行了");
        if (savedInstanceState != null) {
            mName = savedInstanceState.getString("name");
            Log.e(TAG, "onCreate=" + mName);
        }
        clickEvent();
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putString("name", "周建");
        Log.e(TAG,"onSaveInstanceState方法執(zhí)行了");
    }

    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        //快捷鍵:option+command+f   快速提取變量
        String mName = savedInstanceState.getString("name");
        Log.e(TAG, "onRestoreInstanceState=" + mName);
    }

    private void clickEvent() {
        mBtBack.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                finish();
            }
        });
    }

    @Override
    protected void onRestart() {
        super.onRestart();
        Log.e(TAG, "onRestart()方法執(zhí)行了");
    }

    @Override
    protected void onStart() {
        super.onStart();
        Log.e(TAG, "onStart()方法執(zhí)行了");
    }

    @Override
    protected void onResume() {
        super.onResume();
        Log.e(TAG, "onResume()方法執(zhí)行了");
    }

    @Override
    protected void onPause() {
        super.onPause();
        Log.e(TAG, "onPause()方法執(zhí)行了");
    }

    @Override
    protected void onStop() {
        super.onStop();
        Log.e(TAG, "onStop()方法執(zhí)行了");
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.e(TAG, "onDestroy()方法執(zhí)行了");
    }
}

當橫豎屏切換的時候,Activity會被殺死并重新創(chuàng)建,運行結果截圖如下:


f.png

系統(tǒng)配置中內容很多,如何當某項內容發(fā)生改變后,我們不想系統(tǒng)重新創(chuàng)建Activity,可以給Activity指定configChanges屬性,比如如果不想讓屏幕旋轉時重新創(chuàng)建,可以給onfigChanges屬性添加orientation這個值。

android:configChanges="orientation"

android:configChanges的屬性有很多,具體讀者可以查閱相關文檔。

 android:configChanges="orientation|mcc|mnc|locale|touchscreen|keyboard
             |keyboardHidden|navigation|screenLayout|fontScale|uiMode|screenSize
             |smallestScreenSize|layoutDirection">

(2)資源內存不足導致低優(yōu)先級的Activity被殺死,導致Ativity被銷毀并重新創(chuàng)建

優(yōu)先級從高到低如下:

  • 正在和用戶交互的Activity優(yōu)先級最高。
  • 可見但非前臺的Activity,比如Activity中彈出了一個對話框,導致Activity可見但是位于后臺無法和用戶交互。
  • 已經被暫停的Activity,優(yōu)先級最低。

Activity的啟動模式

默認情況下,當我們多次啟動同一個Activity的時候,系統(tǒng)會創(chuàng)建多個實例并把它們一一放入任務棧中。任務棧是一種“先進后出”的棧結構。
Android中的四種啟動模式:standard、singleTop、singleTask、singleInstance

  • standard:標準模式,也是默認的啟動模式
    每次啟動一個Activity都會重新創(chuàng)建一個實例,不管這個實例是否存在。在這種模式下,誰啟動了這個Activity,這個Activity就運行在啟動它的那個Activity的任務棧中。
        <activity
            android:name=".MainActivity"
            android:launchMode="standard">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>

比如說連續(xù)兩次啟動MainActivity,然后執(zhí)行adb shell dumpsys activity命令查看任務棧情況


Snip20161218_11.png

可以看出此時只有一個任務棧,任務棧為當前包名,任務棧中有3個MainActivity(原本的一個MainActivity和啟動兩次)

  • singleTop:棧頂復用模式
    如果新的Activity的實例已經存在并且位于棧頂,那么此Activity不會被重新創(chuàng)建。
    如果新的Activity的實例已經存在但不是位于棧頂,那么此Activity仍然會重新創(chuàng)建。
        <activity
            android:name=".MainActivity"
            android:launchMode="singleTop">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>

比如說連續(xù)兩次啟動MainActivity,然后執(zhí)行adb shell dumpsys activity命令查看任務棧情況

因為MainActivity已經位于棧頂了,兩次啟動MainActivity的時候,不會重新創(chuàng)建,此時的任務棧中應該只有一個實例
看運行截圖:


q.png

只有一個任務棧,任務棧中只有一個實例

  • singleTask:棧內復用模式
    當一個具有singleTask模式的Activity請求啟動后,比如說Activity A,系統(tǒng)首先會尋找是否存在A想要的任務棧,如果不存在A所需的任務棧,就會重新創(chuàng)建一個任務棧,然后創(chuàng)建A的實例并把A放入任務棧中。如果存在A所需的任務棧,這是要看A是否在棧中有實例存在,如果存在,就把A調到棧頂并調用它的onNewIntent方法,如果不存在,就創(chuàng)建A的實例并把A壓入棧中。
        <activity
            android:name=".MainActivity"
            android:launchMode="singleTask">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>

比如說連續(xù)兩次啟動MainActivity,然后執(zhí)行adb shell dumpsys activity命令查看任務棧情況
因為MainActivity實例已經存在,系統(tǒng)就會把MainActivity實例調到棧頂,并兩次調用它的onNewIntent方法
看運行截圖:


q.png

兩次調用onNewIntent方法:


x.png
  • singleInstance:單實例模式
    除具有singleTask模式的所有特征外,singleInstance模式的Activity只能單獨位于一個任務棧中。
指定啟動模式

有兩種方式指定啟動模式,第二種方式優(yōu)先級高于第一種
第一種是在清單文件為Activity指定啟動模式

        <activity
            android:name=".MainActivity"
            android:launchMode="singleTask">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>

第二種是通過給Intent設置標志位來為Activity指定啟動模式

Intent mIntent =new Intent(MainActivity.this,MainActivity.class);                
mIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(mIntent);
Activity的Flags
  • FLAG_ACTIVITY_NEW_TASK
    作用是為Activity指定singleTask啟動模式,和在清單文件中指定效果相同。
  • FLAG_ACTIVITY_SINGLE_TOP
    作用是為Activity指定singleTop啟動模式,和在清單文件中指定效果相同。
  • FLAG_ACTIVITY_CLEAR_TOP
    具有此標記位的Activity,當它啟動時,在同一個任務棧中所有位于它上面的Activity都要出棧。
  • FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
    具有這個標記位的Activity不會出現(xiàn)在歷史Activity的列表中,等同于指定android:excludeFromRecents="true"。

Activity的顯示調用和隱式調用

顯示調用:明確指定被啟動對象的組件信息
隱式調用:不需要指定組件信息,隱式調用需要Intent能夠匹配目標組件IntentFilter中所設置的過濾信息,如果不匹配則無法調用目標Activity

  <activity android:name=".SecondActivity">
            <intent-filter>

                <action android:name="com.zhoujian.define"/>
                <action android:name="com.zhoujian.start"/>

                <category android:name="com.zhoujian.text"/>
                <category android:name="com.zhoujian.cool"/>
                <category android:name="android.intent.category.DEFAULT"/>

                <data android:mimeType="text/plain"/>
                
            </intent-filter>
 </activity>
  • action的匹配規(guī)則
    要求Intent中的action存在且必須和過濾規(guī)則中的其中一個相同

  • category的匹配規(guī)則
    可以不設置,要設置的話,每一個都必須和過濾規(guī)則中的任一個相同

  • data的匹配規(guī)則
    和action的匹配規(guī)則類似,如果過濾規(guī)則中定義了data,那么Intent中必須要定義可匹配的data

下面給出匹配規(guī)則

Intent mIntent = new Intent();
mIntent.setAction("com.zhoujian.define");
mIntent.addCategory("com.zhoujian.text");
mIntent.addCategory("com.zhoujian.cool");
mIntent.setDataAndType(Uri.parse("file://abc"),"text/plain");
startActivity(mIntent);

Intent在Activity間傳遞數(shù)據(jù)

  • Intent傳遞簡單數(shù)據(jù)

在原Activity發(fā)送數(shù)據(jù)

Intent  intent = new Intent(MainActivity.this,SecondActivity.class);
Bundle bundle = new Bundle();
bundle.putString("name","周建");
bundle.putInt("age",25);
intent.putExtras(bundle);
startActivity(intent);

在目標Activity接受數(shù)據(jù)

Intent intent = getIntent();
bundle = intent.getExtras();
String mName = bundle.getString("name");
int mAge = bundle.getInt("age");
Log.d(TAG, "姓名:"+mName+",年齡:"+mAge);

  • Intent傳遞JavaBean
    實現(xiàn)Serializable接口
package note.com.chapter_01;

import java.io.Serializable;

/**
 * Created by zhoujian on 2016/12/21.
 */

public class Person implements Serializable
{
    private static final long serialVersionUID = 1L;
    private int age;
    private String name;

    public int getAge()
    {
        return age;
    }

    public void setAge(int age)
    {
        this.age = age;
    }

    public String getName()
    {
        return name;
    }

    public void setName(String name)
    {
        this.name = name;
    }

    @Override
    public String toString()
    {
        return "Person{" +"age=" + age + ", name='" + name + '\'' + '}';
    }
}

在原Activity發(fā)送數(shù)據(jù)

Person person= new Person();
person.setName("周建");
person.setAge(25);
Intent  intent = new Intent(MainActivity.this,SecondActivity.class);
intent.putExtra("person",person);
startActivity(intent);

在目標Activity接受數(shù)據(jù)


Intent intent = getIntent();
Person mPerson = (Person)intent.getSerializableExtra("person");
Log.d(TAG, mPerson.toString());

實現(xiàn)Parcelable接口

package note.com.chapter_01;

import android.os.Parcel;
import android.os.Parcelable;

/**
 * Created by zhoujian on 2016/12/21.
 */

public class User  implements Parcelable
{
    private int age;
    private String name;
    public User()
    {
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
    @Override
    public int describeContents() {
        return 0;
    }
    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeInt(this.age);
        dest.writeString(this.name);
    }
    protected User(Parcel in) {
        this.age = in.readInt();
        this.name = in.readString();
    }

    public static final Creator<User> CREATOR = new Creator<User>()
    {
        @Override
        public User createFromParcel(Parcel source)
        {
            return new User(source);
        }

        @Override
        public User[] newArray(int size)
        {
            return new User[size];
        }
    };

    @Override
    public String toString()
    {
        return "User{" + "age=" + age + ", name='" + name + '\'' + '}';
    }
}

在原Activity發(fā)送數(shù)據(jù)

User user = new User();
user.setAge(25);
user.setName("周建");

Intent  intent = new Intent(MainActivity.this,SecondActivity.class);
intent.putExtra("user",user);
startActivity(intent);

在目標Activity接受數(shù)據(jù)

Intent intent = getIntent();
User mUser = (User) intent.getParcelableExtra("user");
Log.d(TAG, mUser.toString());
  • Intent傳遞集合

在原Activity發(fā)送數(shù)據(jù)

ArrayList<Person> personArrayList = new ArrayList<Person>();

Person Aperson= new Person();
Aperson.setName("周建");
Aperson.setAge(25);
personArrayList.add(Aperson);

Person Bperson= new Person();
Bperson.setName("zhoujian");
Bperson.setAge(28);
personArrayList.add(Bperson);

Intent  intent = new Intent(MainActivity.this,SecondActivity.class);
intent.putExtra("personArrayList",(Serializable)personArrayList);
startActivity(intent);

在目標Activity接受數(shù)據(jù)

Intent intent = getIntent();
ArrayList<Person> mList = (ArrayList<Person>) intent.getSerializableExtra("personArrayList");
Log.d(TAG, mList.toString());
  • onActivityResult

MainActivity.java

  private void clickEvent() {
        mButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent = new Intent(MainActivity.this, SecondActivity.class);
                //requestCode
                startActivityForResult(intent, INTENT_FLAG);
            }
        });

    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {


        if (resultCode == RESULT_OK)
        {
            switch (requestCode)
            {
                case INTENT_FLAG:
                    String result = data.getStringExtra("msg");
                    Toast.makeText(this, result, Toast.LENGTH_SHORT).show();
                    break;
            }
        }
    }

SecondActivity.java

  private void clickEvent() {
        mBtBack.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent = new  Intent();
                intent.putExtra("msg","我來自第二個界面");
                setResult(RESULT_OK,intent);
                finish();
            }
        });
    }

以上就是有關Activity的基礎知識的總結

CSDN博客:http://blog.csdn.net/u014005316

Github:https://github.com/zeke123

掘金:https://gold.xitu.io/user/5740329671cfe4006c391e1d

簡書:http://m.itdecent.cn/users/002601150b0b/latest_articles

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容