Android开发 | 探究Activity

简析Intent与活动Activity

微信公众号

本文亦可关注公众号阅读:

/images/wechat.webp
公众号:代码之火

一、Intent

1.1 Intent简介

Intent主要用于组件间的通信,它是一个消息,它可以包含数据,可以被传递到另一个组件。Intent一般用于启动活动、启动服务,以及发送广播等。

1.2 显示Intent

显示Intent即通过Intent的构造函数显示提供启动目标的上下文及启动目标本身,然后通过startActivity()方法启动目标。

1
2
3
4
5
6
7
8
Button btn_testIntent = (Button) findViewById(R.id.btn_testIntent);
btn_testIntent.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        Intent intent = new Intent(MainActivity.this, TestIntentActivity.class);
        startActivity(intent);
    }
});

Intent构造函数有多个,其中最常用的是Intent(Context packageContext, Class<?> cls),其中context是上下文,cls是目标类。

1.3 隐式Intent

隐式Intent并不明确指出目标活动,而是通过actioncategory消息,让系统分析得到合适的目标活动。

1
2
3
4
5
6
<activity android:name=".testIntentActivity">
    <intent-filter>
        <action android:name="com.cosyspark.testIntent.ACTION_START" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>

action标签内容表示可以响应com.cosyspark.testIntent.ACTION_START消息,category标签内容表示附加内容,还必须可以响应 category标签内容android.intent.category.DEFAULT的消息。

如果某个活动注册了actioncategory标签,那么只有同时匹配这两个标签的Intent才能得到响应。

此时的按钮点击事件可以写成:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
btn_testIntent.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        Intent intent = new Intent();
        intent.setAction("com.cosyspark.testIntent.ACTION_START");
        // 因为该activity的category标签为default,不写category标签时,系统会自动将default标签加入到intent中,故此写法能也能匹配到该活动。
        // 如果addCategory()添加的category未在<intent-filter>标签中声明,那么启动程序会崩溃,因为该问题会导致无法找到响应该intent的活动。
        //intent.addCategory("android.intent.category.DEFAULT");
        startActivity(intent);
    }
});

1.3.1 Intent.ACTION_VIEW

Intent.ACTION_VIEW为Android系统内置动作,常量值为android.intent.action.VIEW,具体传值方法如下:

使用浏览器打开链接

1
2
3
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("https://cosyspark.space));
startActivity(intent);

通过在<intent-filter>标签中添加<data>标签可以指定细化setData()的解析的数据类型,如:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
<activity android:name=".testIntentActivity">
    <intent-filter>
        <action android:name="com.cosyspark.testIntent.ACTION_START" />
        <category android:name="android.intent.category.DEFAULT" />
        <data android:scheme="https" />

        <!-- data android:host="cosyspark.space" /> 指定主机名 -->
        <!-- data android:port="443" />  指定端口号 -->
        <!-- data android:path="/test" />  指定域名后的路径- -->
    </intent-filter>
</activity>

拨号

1
2
3
4
5
6
7
8
9
btn_testIntent.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        Intent intent = new Intent(Intent.ACTION_DIAL);
        intent.setData(Uri.parse("tel:10086"));
        // tel指定data的协议类型,10086表示拨号的号码,如果没有指定号码,那么系统会自动拨号到10086。
        startActivity(intent);
    }
});

1.4 Intent传递数据

通过Intent在活动间传输数据、参数等。

1
2
3
Intent intent = new Intent(MainActivity.this, TestIntentActivity.class);
intent.putExtra("key", "value"); // 将key为"key"的数据传递给TestIntentActivity
startActivity(intent);

获取Intent传输数据的值:

1
2
Intent intent = getIntent();
String value = intent.getStringExtra("key");

二、返回栈

returnStack.png
返回栈

Android是通过任务(task)来管理活动的,一个任务是一组放在栈中的活动的集合,这个栈就叫返回栈。启动新活动时会将新活动压栈,销毁活动时栈顶活动将被弹出(finish())。

2.1 活动的状态

  • 运行
  • 暂停
  • 停止
  • 销毁

2.2 活动的生存期

活动的回调方法:

  • onCreate() 活动初始化:加载布局、绑定事件等
  • onStart() 活动启动:使活动由不可见变为可见时调用
  • onResume() 活动即将和用户交互时调用,活动处于栈顶
  • onPause() 活动离开需启动另一个活动时调用
  • onStop() 活动不可见时调用。若新活动是对话框式的活动,则旧活动会调用onPause()方法,因为旧活动仍可见
  • onDestroy() 活动销毁前调用
  • onRestart() 活动由停止状态变为运行状态时调用

活动的生存期:

  • 完整生存期:onCreate() ~ onDestroy()
  • 可见生存期:onStart() ~ onStop()
  • 前台生存期:onResume() ~ onPause()
lifeCycle.png
活动的生存期

2.3 活动被回收

如果活动被系统回收,那么之前该活动保存的数据将丢失(例如活动A记录了用户输入的用户名和密码的表单,切换到另一个活动B后又返回活动A,之前未保存活动A数据的话,活动A的表单数据可能会被清空。因为一旦活动A被回收,从活动B返回至活动A时将重新调用活动A的onCreate()方法。)此时可以通过在活动A中调用onSaveInstanceState()方法保存活动A数据,然后通过Bundle恢复活动A数据。

活动A调用onSaveInstanceState()方法保存活动中某些数据:

1
2
3
4
5
6
7
8
@Override
protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    String username = mUsernameEditText.getText().toString();
    String password = mPasswordEditText.getText().toString();
    outState.putString("username", mUsername);
    outState.putString("password", mPassword);
}

活动A修改onCreate()方法:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    mUsernameEditText = (EditText) findViewById(R.id.username_edit_text);
    mPasswordEditText = (EditText) findViewById(R.id.password_edit_text);
    if (savedInstanceState != null) {
        mUsername = savedInstanceState.getString("username");
        mPassword = savedInstanceState.getString("password");
        mUsernameEditText.setText(mUsername);
        mPasswordEditText.setText(mPassword);
    }
}

三、活动的启动模式

AndroidManifest.xml中的启动模式:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
<activity android:name="com.example.myapplication.MainActivity"
    android:label="@string/app_name"
    android:launchMode="singleTask"
    <!-- android:launchMode="singleInstance" -->
    <!-- android:launchMode="singleTop" -->
    <!-- android:launchMode="singleTask" -->
    android:theme="@style/AppTheme" >
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>

3.1 standard(默认)

每当启动一个活动,该活动都会被压入返回栈,不论占中存在该活动与否

standard.png
默认模式

3.4 singleTop

当启动的活动本身在栈顶时,将不会压入返回栈,而是直接使用栈顶活动。

singleTop.png
singleTop模式

3.2 singleTask

首先检查返回栈中是否存在该活动,若不存在则将新活动压栈;否则将存在的活动上面的其他活动全部弹出,使已经存在的活动处于栈顶。

singleTask.png
singleTask模式

3.3 singleInstance

有且仅有该活动拥有一个独立的返回栈,与之前的活动不共用同一个返回栈。

singleInstance.png
singleInstance模式

四、判断当前活动类名

使某些活动继承于一个自定义的类,而该类继承于某些活动原来的父类,从而不改变某些活动原来的类特征;在自定义类中重写onCreate()方法,添加调用getClass().getSimpleName()方法,以便判断当前活动的类名。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
public class MyActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        /*
        // ...
        // ...
        */
        Log.i("MyActivity", getClass().getSimpleName());
    }
}

五、自定义活动管理器

随时随地结束当前活动,结束程序。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
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();
            }
        }
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
public class MyActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        /*
        // ...
        // ...
        */
        ActivityCollector.addActivity(this);
    }
    @Override
    protected void onDestroy() {
        super.onDestroy();
        ActivityCollector.removeActivity(this);
    }
}

调用活动管理器结束程序:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
public class MyActivity extends Activity {
super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        /*
        // ...
        // ...
        */
        ActivityCollector.addActivity(this);
    }
Button button = findViewById(R.id.btn_exit);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                ActivityCollector.finishAll();
                // 结束当前程序进程,当且仅限结束当前程序的pid,无法结束其他程序的进程
                // android.os.Process.killProcess(android.os.Process.myPid());
            }
        });
}
给作者倒杯卡布奇诺 ~
Albresky 支付宝支付宝
Albresky 微信微信