活动(Activity)的探究

一、活动的基本用法

    活动(Activity)是最容易吸引用户的地方,它是一种可以包含用户界面的组件,主要用于和用户进行交互。所有的活动都要在AndroidManifest.xml中进行注册才能生效,代码如下:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="com.xiao.onecode">
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".FirstActivity"
            android:label="This is FirstActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
    </application>
</manifest>
    在<activity>标签的内部加入<intent-filter>标签,并在标签里添加<action android:name="android.intent.action.MAIN"/>和<category android:name="android.intent.action.LAUNCHER"/>这两句,表明为程序配置主活动,也就是当程序运行起来时,首先启动的活动。还可以使用android:label指定活动中标题栏的内容,标题栏显示在活动最顶部。

二、使用Intent在活动之间跳转

    Intent是Android程序中各组件之间进行交互的一种重要方式,它不仅可以致命当前组件想要执行的动作,还可以在不同组件之间传递数据。Intent一般用于启动活动、启动服务以及发送广播等场景。

2.1 使用显式Intent

    Intent大致分为两种:显式Intent和隐式Intent,先来看一下显式Intent的使用Intent有多个构造函数的重载,其中一个是Intent(Context packageContext, Class<?> cls)。这个构造函数接收两个参数,第一个参数Context要求提供一个启动活动的上下文,第二个参数则是指定想要启动的目标活动。Activity类中提供了一个startActivity()方法,这个方法是专门用于启动活动的,它接收一个Intent参数,只要将构建好的Intent传入startActivity()方法就可以启动目标活动了。

    创建两个活动(FirstActivity和SecondActivity),并分别为它们添加一个只包含Button控件的布局。修改FirstActivity中按钮的点击事件,代码如下:
Button firstButton = (Button) findViewById(R.id.first_button);
firstButton.setOnClickListener(new View.OnClickListener()
{
     @Override
     public void onClick(View v)
     {
          Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
          startActivity(intent);
      }
 });
2.2 使用隐式Intent

    相比于显式Intent,隐式Intent则含蓄了许多,它并不明确指出想要启动哪一个活动,而是指定了一系列更为抽象的action和category等信息,然后交由系统去分析这个Intent,并找出合适的活动去启动。

    通过在<activity>标签下配置<intent-filter>的内容,可以指定当前活动能够响应的action和category,打开AndroidManifest.xml,添加如下代码:

<activity android:name=".SecondActivity">
      <intent-filter>
            <action android:name="com.xiao.activity.ACTION_START"/>
            <category android:name="android.intent.category.DEFAULT"/>
      </intent-filter>
</activity>
    在action标签中指明了当前活动可以响应<action android:name="com.xiao.activity.ACTION_START"/>这个action,而<category>标签则包含了一些附加信息,更精确地指明了当前的活动能够

响应的Intent。只有<action>和<category>中的内容同时能够匹配上Intent中指定的action和category时,这个活动才能响应该Intent。

    修改FirstActivity中按钮的点击事件,代码如下:

firstButton.setOnClickListener(new View.OnClickListener()
{
      @Override
      public void onClick(View v)
      {
           Intent intent = new Intent("com.xiao.activity.ACTION_START");
           startActivity(intent);
      }
});

    可以看到,这里使用了Intent的另一个构造函数,直接将action的字符串传了进去,表明想要启动能够响应com.xiao.activity.ACTION_START这个action的活动。因为android.intent.category.DEFAULT是一种默认的category,在调用startActivity()方法时会自动将这个category添加到Intent中,否则就需要通过intent.addCategory()方法来指定category。注意每个Intent中只能指定一个action,但却能指定多个category。

    使用隐式Intent,不仅可以启动自己程序内的活动,还可以启动其他应用程序的活动,这使得过个应用程序之间的功能共享成为了可能。比如自己的应用程序需要展示一个网页,只需要调用系统的浏览器来打开这个网页即可,添加intent.setData(Uri.parse("http://www.baidu.com"))这个方法。而如果想要自己的活动也能响应网页的Intent,在<intent-filter>标签里添加<data android:scheme="http"/>,通过android:scheme指定了数据的协议必须是http,这要这个活动就能响应一个打开网页的Intent了。

三、活动之间传递数据

3.1 向下一个活动传递数据

    在启动下一个活动时传递数据的方法很简单,Intent中提供了一系列putExtra()方法的重载,可以把想要传递的数据暂存在Intent中,启动另一个活动后,再把数据从Intent中取出即可,测试例子如下:

    修改FirstActivity中的代码,使其向SecondActivity传递一个字符串,代码如下:

firstButton.setOnClickListener(new View.OnClickListener()
{
     @Override
     public void onClick(View v)
     {
           String data = "Hello SecondActivity, I am FirstActivity!";
           Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
           intent.putExtra("extra_data", data);
           startActivity(intent);
     }
});

    修改SecondActivity中的代码,使其接收来自FirstActivity一个字符串,代码如下:

public class SecondActivity extends AppCompatActivity
{

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);
        Intent intent = getIntent();
        String data = intent.getStringExtra("extra_data");
        Log.d("SecondActivity", data);
    }
}

3.1 返回数据给上一个活动

    Activity中还有一个startActivityForResult()方法也是用于启动活动的但这个方法期望在活动销毁时能够返回一个结果给上一个活动。startActivityForResult()方法接收两个参数,第一个参数还是Intent,第二个参数是请求码,用于在之后的回调中判断数据的来源,下面是一个例子:

    修改FirstActicity中按钮的点击事件,代码如下:

firstButton.setOnClickListener(new View.OnClickListener()
{
     @Override
     public void onClick(View v)
     {
          Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
          startActivityForResult(intent, 1);
     }
});

    由于使用的是startActivityForResult()方法来启动SecondActivity的,在SecondActivity被销毁之后会回调上一个活动的onActivityResult()方法,因此需要在FirstActivity中重写这个方法,代码如下:

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
    switch (requestCode)
    {
        case 1:
            if (resultCode == RESULT_OK)
            {
                String returnData = data.getStringExtra("data_extra");
                Log.d("FirstActivity", returnData);
            }
            break;
        default:
            break;
    }
}

    修改SecondActivity的点击事件代码,使其向FristActivity返回数据,代码如下:

public class SecondActivity extends AppCompatActivity
{
    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);

        Button secondButton = (Button) findViewById(R.id.second_button);
        secondButton.setOnClickListener(new View.OnClickListener()
        {
            @Override
            public void onClick(View v)
            {
                Intent intent = new Intent();
                intent.putExtra("data_extra", "Hello FirstActivity, I am SecondActivity!");
                setResult(RESULT_OK, intent);
                finish();
            }
        });
    }
}

    接下来需要实现用户按下Back键也能实现相同的效果,修改SecondActivity中的代码:

@Override
public void onBackPressed()
{
    Intent intent = new Intent();
    intent.putExtra("data_extra", "Hello FirstActivity, I am SecondActivity!");
    setResult(RESULT_OK, intent);
    finish();
}

四、活动的生命周期

    Android使用任务(Task)来管理活动的,一个任务就是一组存放在栈里的活动的集合,这个栈称为返回栈(Back Stack).栈是一种后进先出的数据结构,在默认情况下,每当启动一个新的活动,它会在返回栈中入栈,并处于栈顶的位置。每当按下Back键或调用finish()方法去销毁一个活动时,处于栈顶的活动就会出栈,这时前一个入栈的活动就会重新处于栈顶的位置。系统总是显示处于栈顶的活动给用户。

4.1 活动的状态

    每个活动在其生命周期中最多可能会有4中状态:

    运行状态:当一个活动位于返回栈的栈顶时,这个活动就处于运行状态。系统最不愿意回收的就是处于运行状态的活动,这会给用户带来极差的体验。

    暂停状态:当一个活动不再处于栈顶位置,但仍然可见时,这个活动就进入了暂停状态。比如对话框式的活动之占用屏幕中间的部分区域,后面可见的活动就处于暂停状态。

    停止状态:当一个活动不再处于栈顶位置,也不可见时,这个活动就进入了停止状态。当其他地方需要内存时,处于停止状态的活动可能会被系统回收。

    销毁状态:当一个活动从返回栈中移除后就处于销毁状态。系统首先会回收处于销毁状态的活动,从而保证手机内存充足。

4.2 活动的生存期

    Activity类中定义了七个回调方法,覆盖了活动生命周期的每一个环节,分别如下:

    onCreate():在活动第一次创建的时候被调用,可以在这个方法中完成初始化操作。

    onStart():这个方法在活动由不可见变为可见的时候调用。

    onResume():这个方法在活动准备好和用户进行交互的时候调用。此时的活动一定位于返回栈的栈顶,并且处于运行状态。

    onPause():这个方法在系统准备去启动或回复另一个活动的时候调用。通常在这个方法中释放掉一些消耗CPU的资源,以及保存一些关键数据,但这个方法的执行速度要快,不然会影响到新的栈顶活动的使用。

    onStop():这个方法在活动完全不可见的时候调用。如果启动的新活动是对话框式的活动,那么onPause()方法会得到执行,而onStop()方法不会执行。

    onDestroy():这个方法在活动销毁之前调用,之后活动变为销毁状态。

    onRestart():这个方法在活动由停止状态变为运行状态之前调用,即活动被重新启动了。

    

活动的生命周期图

    下面通过一个测试例子来体验活动的生命周期:

    创建MainActivity活动,代码如下:

public class MainActivity extends AppCompatActivity
{
    private static final String TAG = MainActivity.class.getSimpleName();

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        Log.d(TAG, "onCreate");
        setContentView(R.layout.activity_main);
        Button normalButton = (Button) findViewById(R.id.normal_button);
        Button dialogButton = (Button) findViewById(R.id.dialog_button);
        normalButton.setOnClickListener(new View.OnClickListener()
        {
            @Override
            public void onClick(View v)
            {
                Intent intent = new Intent(MainActivity.this, NormalActivity.class);
                startActivity(intent);
            }
        });
        dialogButton.setOnClickListener(new View.OnClickListener()
        {
            @Override
            public void onClick(View v)
            {
                Intent intent = new Intent(MainActivity.this, DialogActivity.class);
                startActivity(intent);
            }
        });
    }
    @Override
    protected void onRestart()
    {
        super.onRestart();
        Log.d(TAG, "onRestart");
    }
    @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");
    }
}
    布局activity_main如下:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:orientation="vertical"
              android:layout_width="match_parent"
              android:layout_height="match_parent">
    <Button
        android:id="@+id/normal_button"
        android:text="启动全屏活动"
        android:textSize="20sp"
        android:textColor="#FF0000"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>
    <Button
        android:id="@+id/dialog_button"
        android:text="启动对话框式活动"
        android:textSize="20sp"
        android:textColor="#FF0000"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>
</LinearLayout>

    创建NormalActivity活动,代码如下:

public class NormalActivity extends AppCompatActivity
{
    private static final String TAG = NormalActivity.class.getSimpleName();
    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        Log.d(TAG, "onCreate");
        setContentView(R.layout.activity_normal);
    }
    @Override
    protected void onRestart()
    {
        super.onRestart();
        Log.d(TAG, "onRestart");
    }
    @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");
    }
}
 布局activity_normal如下:
<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:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="This is a normal activity"/>

</LinearLayout>
    创建DialogActivity活动,代码如下:
public class DialogActivity extends AppCompatActivity
{
    private static final String TAG = DialogActivity.class.getSimpleName();
    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        Log.d(TAG, "onCreate");
        setContentView(R.layout.activity_dialog);
    }
    @Override
    protected void onRestart()
    {
        super.onRestart();
        Log.d(TAG, "onRestart");
    }
    @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");
    }
}

    布局acitivity_dialog如下:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:orientation="vertical"
              android:layout_width="match_parent"
              android:layout_height="match_parent">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="This is a dialog activity"/>

</LinearLayout>

    启动应用程序,进入MainActivity,可以看到如下打印的日志:


    可以看到,当MainActivity第一次被创建时会依次执行onCreate()-->onStart()-->onResume()方法。接着点击“启动全屏活动按钮”,启动NormalActivity,可以看到如下打印的日志:


    可以看到,启动NormalActivity时会先执行MainActivity的onPause()方法使其失去焦点,然后NormalActivity依次执行onCreate()-->onStart()-->onResume()方法去创建活动,最后MainActivity执行onStop()方法进入暂停状态。接着点击Back键返回MainActivity,日志打印如下:


    可以看到,返回MainActivity时会先执行NormalActivity的onPause()方法使其失去焦点,然后MainActivity依次执行onRestart()-->onStart()-->onResume()方法去重新获得焦点,最后NormalActivity执行onStop()-->onDestroy()方法销毁。接着点击“启动对话框式活动”按钮,启动DialogActivity,日志打印如下:


    可以看到,启动DialogActivity时会先执行MainActivity的onPause()方法使其失去焦点,然后DialogActivity依次执行onCreate()-->onStart()-->onResume()方法去创建活动,但MainActivity不执行onStop()方法,因为MainActivity此时还是可见的。接着点击Back键返回MainActivity,日志打印如下:


    可以看到,返回MainActivity时会先执行DialogActivity的onPause()方法使其失去焦点,然后MainActivity只执行onResume()方法去重新获得焦点,最后DialogActivity执行onStop()-->onDestroy()方法销毁。

    根据以上的测试例子,可以得到以下的结论:

  1.  活动第一次创建会依次执行onCreate()-->onStart()-->onResume()方法去创建
  2.  无论是启动新活动还是回到旧活动,当前活动都先执行onPause()方法失去焦点,接着下一个活动再执行onCreate()-->onStart()-->onResume()新建onReStart()-->onStart()-->onResume()或只执行onResume()重建,最后当前活动执行onStop()暂停或onStop()-->onDestroy()销毁。

    进入暂停状态的活动有可能会被系统回收,想要保存临时数据,可以使用Activity中的onSaveInstanceState()回调方法,代码如下:

@Override
protected void onSaveInstanceState(Bundle outState) 
{
    super.onSaveInstanceState(outState);
    String tempData = "Something you just typed";
    outState.putString("data_key", tempData);
}
    想要对保存的数据进行恢复,onCreate()方法的Bundle类型参数会带有之前保存的全部数据,只需要通过相应的取值方法取出即可,代码如下:
@Override
protected void onCreate(Bundle saveInstanceState)
{
    super.onCreate(saveInstanceState);
    if(saveInstanceState != null)
    {
        String tempData = saveInstanceState.getString("data_key");
        Log.d(TAG, tempData);
    }
}

    Intent还可以结合Bundle一起用于传递数据,首先可以把需要保存的数据都保存在Bundle对象中,然后再把Bundle对象存放到Intent里。到了目标活动之后先从Intent中取出Bundle对象,然后再从Bundle对象中一一取出数据。

五、活动的启动模式

    活动的启动模式共有四种:分别是standard、singleTop、singleTask和singleInstance,可以在AndroidManifest.xml中通过给<activity>标签制定android:launchMode属性来选择启动模式。

5.1 standard模式

    standard模式是活动的默认启动模式,在不进行显式指定的情况下,所有活动都会自动使用这种启动模式。在standard模式下,每当启动一个新的活动,它就会在返回栈中入栈,并处于栈顶位置。对于使用standard模式的活动,系统不会在乎这个活动是否已经存在于返回栈中,每次启动都会创建该活动的一个新实例。

    修改FirstActivity中onCreate()方法的代码,如下所示:

@Override
protected void onCreate(Bundle savedInstanceState)
{
    super.onCreate(savedInstanceState);
    Log.d(TAG, this.toString());
    setContentView(R.layout.activity_first);
    Button activityButton = (Button) findViewById(R.id.activity_button);
    activityButton.setOnClickListener(new View.OnClickListener()
    {
        @Override
        public void onClick(View v)
        {
            Intent intent = new Intent(FirstActivity.this, FirstActivity.class);
            startActivity(intent);
        }
    });
}

    运行程序,在FirstActivity界面连续点击两次按钮,可以看到如下日志的打印:


    可以看出,点击一次按钮就会创建出一个新的FirstActivity实例,此时返回栈中会存在3个Activity实例,因此需要点击3词Back键才能退出程序,standard模式的原理图如下所示:


5.2 singleTop模式

    当活动的启动模式指定为singleTop时,在启动活动时如果发现返回栈的栈顶中已经是该活动,则认为可以直接使用它,不会创建新的活动实例;但如果栈顶不是该活动,仍然会创建新的活动实例。

    修改AndroidManifest.xml中FirstActivity的启动模式,如下所示:

<activity
     android:name=".FirstActivity"
     android:label="This is FirstActivity"
     android:launchMode="singleTop">
     <intent-filter>
          <action android:name="android.intent.action.MAIN"/>
          <category android:name="android.intent.category.LAUNCHER"/>
     </intent-filter>
</activity>

    修改FirstActivity中onCreate()方法的代码,如下所示:

@Override
protected void onCreate(Bundle savedInstanceState)
{
    super.onCreate(savedInstanceState);
    Log.d(TAG, this.toString());
    setContentView(R.layout.activity_first);
    Button activityButton = (Button) findViewById(R.id.activity_button);
    activityButton.setOnClickListener(new View.OnClickListener()
    {
        @Override
        public void onClick(View v)
        {
            Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
            startActivity(intent);
        }
    });
}

    修改SecondActivity中onCreate()方法的代码,如下所示:

@Override
protected void onCreate(Bundle savedInstanceState)
{
    super.onCreate(savedInstanceState);
    Log.d(TAG, this.toString());
    setContentView(R.layout.activity_first);
    Button activityButton = (Button) findViewById(R.id.activity_button);
    activityButton.setOnClickListener(new View.OnClickListener()
    {
        @Override
        public void onClick(View v)
        {
            Intent intent = new Intent(SecondActivity.this, FirstActivity.class);
            startActivity(intent);
        }
    });
}

    运行该程序,在FirstActivity界面点击按钮进入到SecondActivity,然后在SecondActivity界面点击按钮重新回到FirstActivity,打印的日志如下:


    可以看出,系统创建了两个不同的FirstActivity实例,按下Back键会回到SecondActivity,再次按下Back键又会回到FirstActivity,再按一次Back键才会退出程序,singleTop模式的原理图如下所示:


5.3 singleTask模式

    使用singleTop模式可以解决重复创建栈顶活动的问题,当活动的启动模式指定为singleTask时,每次启动该活动时系统会首先在返回栈中检查是否存在该活动的实例,如果发现已经存在则直接使用该实例,并把在这个活动之上的所有活动全部出栈,如果没有发现就会创建一个新的活动实例。

    修改AndroidManifest.xml中FirstActivity的启动模式,如下所示:

<activity
     android:name=".FirstActivity"
     android:label="This is FirstActivity"
     android:launchMode="singleTask">
     <intent-filter>
          <action android:name="android.intent.action.MAIN"/>
          <category android:name="android.intent.category.LAUNCHER"/>
     </intent-filter>
</activity>

    在FirstActivity中添加onReStart()方法的代码,如下所示:

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

    最后在SecondActivity中添加onDestroy()方法的代码,如下所示:

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

    运行该程序,在FirstActivity界面点击按钮进入到SecondActivity,然后在SecondActivity界面点击按钮重新回到FirstActivity,打印的日志如下:


    可以看出,在SecondActivity中启动FirstActivity时,会发现返回栈中已经存在一个FirstActivity实例,并且在SecondActivity的下面,于是SecondActivity从返回栈中出栈,而FirstActivity重新成为栈顶活动,因此FirstActivity的onRestart()方法和SecondActivity的onDestroy()方法执行,现在只需要按一下Back键就会退出程序,singleTop模式的原理图如下所示:


5.4 singleInstance模式

    singleInstance模式比较特殊,指定为singleInstance模式的活动会启动一个新的返回栈来管理这个活动,可以解决其他程序和本程序共享活动实例的问题。

    修改AndroidManifest.xml中SecondActivity的启动模式,如下所示:

<activity
     android:name=".SecondActivity"
     android:launchMode="singleInstance">
</activity>

    修改FirstActivity中添加onCreate()方法的代码,如下所示:

@Override
protected void onCreate(Bundle savedInstanceState)
{
    super.onCreate(savedInstanceState);
    Log.d(TAG, "Task is " + getTaskId());
    setContentView(R.layout.activity_first);
    Button activityButton = (Button) findViewById(R.id.activity_button);
    activityButton.setOnClickListener(new View.OnClickListener()
    {
        @Override
        public void onClick(View v)
        {
            Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
            startActivity(intent);
        }
    });
}

    接着在SecondActivity中修改onCreate()方法的代码,如下所示:

@Override
protected void onCreate(Bundle savedInstanceState)
{
    super.onCreate(savedInstanceState);
    Log.d(TAG, "Task is " + getTaskId());
    setContentView(R.layout.activity_first);
    Button activityButton = (Button) findViewById(R.id.activity_button);
    activityButton.setOnClickListener(new View.OnClickListener()
    {
        @Override
        public void onClick(View v)
        {
            Intent intent = new Intent(SecondActivity.this, ThirdActivity.class);
            startActivity(intent);
        }
    });
}

    最后在ThirdActivity中修改onCreate()方法的代码,如下所示:

@Override
protected void onCreate(Bundle savedInstanceState)
{
    super.onCreate(savedInstanceState);
    Log.d(TAG, "Task is " + getTaskId());
    setContentView(R.layout.activity_third);
}

    运行该程序,在FirstActivity界面点击按钮进入到SecondActivity,然后在SecondActivity界面点击按钮进入到回到ThirdActivity,打印的日志如下:


    可以看出,SecondActivity的Task id不同于FirstActivity和ThirdActivity,这说明Second存放在一个单独的返回栈里,而且这个栈只有SecondActivity这一个活动,singleInstance模式的原理图如下所示:


六、活动的最佳实践

6.1 知晓当前是在哪一个活动

    如果程序中的活动过多或者是接手别人的代码,知道当前是在哪一个活动中就会非常重要。新建一个BaseActivity类,不需要在AndroidManifest中注册,让其继承自AppCompatActivity,重写onCreate()方法,代码如下:

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

    在onCreate()方法中获取了当前实例的类名并打印出来,接着让BaseActivity成为程序中所有活动的父类,这样就可以在新活动创建的时候打印出活动的类名,也就知晓了当前在哪个活动。

6.2 随时随地退出活动

    用一个专门的集合类对所有的活动进行管理,下面就来实现一下:

public class ActivityCollector
{
	public static List<Activity> activitys = new ArrayList<>();

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

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

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

    在活动管理器中,通过一个List来暂存活动,然后提供一个addActivity()方法用于向List添加一个活动,一个removeActivity()方法用于从List中移除一个活动,finishAll()方法用于销毁所有的活动。

    接下来修改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);
    }
}

还可以在销毁所有活动的代码后面加上杀掉当前进程的代码,以保证完全退出程序。杀掉进程的代码如下:

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

6.3 启动活动的最佳写法

    在BaseActivity中添加actionStart()方法,该方法实现如下:

public static void actionStart(Context context, Bundle bundle, Class<?> activity)
{
    Intent intent = new Intent(context, activity);
    intent.putExtra("bundle", bundle);
    context.startActivity(intent);
}

    在actionStart()方法中,传递了Bundle对象,该对象包含所有需要传递的数据,并将该对象暂存在Intent中,在目标活动中就可以取出了。


猜你喜欢

转载自blog.csdn.net/qq_35523015/article/details/80912554
今日推荐