1. Activity概念
Activity,即活动,是一种可以包含用户界面的组件,主要用于和用户进行交互
活动提供应用程序绘制其UI的窗口。此窗口通常填充屏幕,但可能小于屏幕并浮动在其他窗口的顶部。通常,一个活动在应用程序中实现一个屏幕。
多数应用包含多个屏幕,即多个活动,一般会指定一个活动为主要活动,即用户启动程序显示的第一个屏幕。
2. Activity基本用法
2.1 注册声明
所有的活动都要在AndroidManifest.xml中进行注册才能生效活动的注册声明要放在<application>
标签内,在<activity>
标签中是用了android:name来指定具体注册哪一个活动。
<font color=red>配置主活动的方法</font>就是在<application>
标签内加入<intent-filter>
标签。这个标签内包含<action>和两个可选标签<category>、<data>。这些标签元素组合在一起以指定您的活动可以响应的意图类型。
示例:
<activity android:name=".ExampleActivity" android:icon="@drawable/app_icon">
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/plain" />
</intent-filter>
</activity>
如果时配置成主活动的话,为:
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
2.2 权限声明
除非两个活动在其清单中具有相同的权限,否则父活动无法启动子活动。如果为父活动声明uses-permission元素,则每个子活动必须具有匹配的uses-permission元素。
示例:
<manifest>
<activity android:name="...."
android:permission=”com.google.socialapp.permission.SHARE_POST”
/>
如果父活动声明了该权限,则子活动也必须声明该权限,否则父活动无法启动子活动。
2.3 销毁一个活动
销毁一个活动只需要按back键即可。Activity类提供了一个finish()方法,活动调用这个方法就可销毁当前活动。
2.4 Intent使用
Intent是Android程序中各组件之间进行交互的一种重要方式,不仅可以指明当前组件想要执行的动作,还可以在不同组件之间进行传递数据。被用于启动活动,启动服务以及发送广播等场景。
2.4.1 使用显式Intent
Activity类中提供一个startActivity()
方法,专门用于启动活动。
显示启动的三种方法:
-
基本用法
Intent intent = new Intent(FirstActivity.this, SecondActivity.class); startActivity(intent);
-
通过Intent的ComponentName启动
ComponentName cn = new ComponentName("com.baiheng.activitytest","com.baiheng.activitytest.ThirdActivity"); Intent intent = new Intent(); intent.setComponent(cn); startActivity(intent);
-
通过初始化Intent时指定包名
Intent intent = new Intent("android.intent.action.MAIN"); intent.setClassName("com.baiheng.activitytest", "com.baiheng.activitytest.ThirdActivity"); startActivity(intent);
2.4.2 使用隐式Intent
不明确指出我们想要启动哪一个活动,指定一系列抽象的action和category等信息,交由系统分析这个Intent,这个通过Intent的Intent-filter是实现。
<activity android:name=".SecondActivity">
<intent-filter>
<action android:name="com.baiheng.activitytest.action.START" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
Intent intent = new Intent();
intent.setAction(Intent.ACTION_START); intent.addCategory(Intent.CATEGORY_DEFAULT);
startActivity(intent);
每个Intent只能指定一个action,但是却能指定多个category。
在<intent-filter>
标签中再配置一个<data>
标签,用于更精准地指定当前活动能够响应什么类型的数据。<data>
标签中主要可以配置一下内容:
- android:scheme:用于指定数据的协议部分,如示例:http
- android:host:用于指定数据的主机名部分,如示例www.baidu.com
- android:port:用于指定数据的端口部分,一般紧随在主机名之后
- android:path:用于指定主机名和端口之后的部分,如一段网址跟在主机名之后的内容
- android:mimeType:用于指定可以处理的数据类型,允许使用通配符的方式进行指定。
只有<data>
标签中指定的内容和Intent中携带的Data完全一致,当前活动才能够相应该Intent。一般不会在<data>
标签中指定过多内容。
2.4.3 使用隐式Intent启动其他程序
使用隐式Intent不仅可以启动程序内的活动,还可以启动其他程序的活动。
示例:
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("http://www.google.com.hk"));
startActivity(intent);
Uri.parse
将一个网址字符串解析成一个Uri对象。
<activity android:name=".ThirdActivity">
<intent-filter tools:ignore="AppLinkUrlError">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="http" />
</intent-filter>
</activity>
3. Activity 间数据传递
一个App一般包含多个Activity,涉及到Activity之间的数据传递。关于如何传递不同的数据类型在Intent部分详解,这里介绍一下两种传递方式
3.1 向下传递数据
Intent中提供了一些列putExtra()
方法的重载,可以把想要传递的数据暂存在Intent中,启动了另一个活动后,把这些数据从Intent中取出来就可以。
示例:在FirstActivity中:
String data = "Hello SecondActivity";
Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
intent.putExtra("extra_data", data);
startActivity(intent);
SecondActivity:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.second_activity);
Intent intent = getIntent();
String data = intent.getStringExtra("extra_data");
Log.d("SecondActivity", data);
}
3.2 返回数据给上一个活动
Activity中还有一个startActivityForResult()
方法也适用于启动活动,但是该方法期望活动销毁的时候返回一个结果给上一个活动。
该方法接收两个参数,一个是Intent,第二个参数是请求码,用于之后在回调中判断数据的来源。
FirstActivity:
Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
startActivityForResult(intent,1);
SecondActivity:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.second_activity);
Button button2 = (Button) findViewById(R.id.button_2);
button2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent();
intent.putExtra("data_return","Hello FirstActivity");
setResult(RRSULT_OK, intent);
finish();
}
});
}
最后在FirstActivity中重写这个方法得到返回数据:
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
switch(requestCode) {
case 1:
if (resultCode == RESULT_OK) {
String returnedData = data.getStringExtra("data_return");
Log.d("FritstActivity",returnedData);
}
break;
default:
}
}
如果是通过back键返回,则可以通过在SecondActivity中重写onBackPressed()
来解决:
@Override
public void onBackPressed() {
Intent intent = new Intent();
intent.putExtra("data_return","Hello FirstActivity");
setResult(RESULT_OK, intent);
finish();
}
4. Activity生命周期
4.1 返回栈
Android中的活动是可以层叠的。每启动一个新的活动,就会覆盖原来的活动之上,点击Back键就会销毁最上面的活动。
Android是使用任务(Task)来管理活动的,一个任务就是一组存放在栈里的活动的集合,这个栈也称作返回栈(Back Stack)。系统总是会显示处于栈顶活动给用户。
image4.2 活动状态
每个活动在其生命周期中最多可能会有4中状态:
-
运行状态:
活动位于返回栈的栈顶时,这时活动就处于运行状态。
-
暂停状态:
活动不处于栈顶时,但是仍然可见,活动就进入暂停状态。
-
停止状态:
活动不处于栈顶位置,且完全不可见,就进入停止状态。处于停止状态的活动有可能会被系统回收
-
销毁状态:
活动从返回栈中移除后就变成了销毁状态。
4.3 生命周期
Activity类中定义了7种回调方法,覆盖了活动生命周期的每一个环节:
-
onCreate()
:完成活动的初始化操作,比如加载布局,绑定事件 -
onStart()
:在活动由不可见变为可见的时候调用 -
onResume()
:在活动准备好和用户进行交互时调用。该活动一定处于返回栈栈顶,且处于运行状态 -
onPause()
:系统准备去启动或者恢复另一个活动的时候调用。该方法的执行速度一定要快,否则会影响到新的栈顶活动的使用 -
onStop
:在活动完全不可见时调用,与前者的区别时启动的新活动是一个对话框式的活动,那么onPause()方法会得到执行,而该方法不会 -
onDestory()
:在活动被销毁之前调用,之后活动变为销毁状态 -
onRestart()
:由停止状态变为运行时状态之前调用,活动被重新启动。
除了onRestart()方法之外,其他都是两两相对的,活动分为3中生存期:
-
完整生存期:活动在
onCreate()
和onDestrory()
之间经历的就是完整生存期 -
可见生存期:活动在
onStart()
和onStop
之间经历的就是可见生存期。活动对于用户总是可见的,即便有可能无法和用户进行交互。 -
前台生存期:活动在
onResume()
和onPause()
之间经历的就是前台生存期。活动总是处于运行状态,此时活动可以和用户进行交互
[图片上传失败...(image-12888f-1565323303532)]
4.4 活动被回收
如果一个活动进入停止状态,有可能被系统回收,其中的数据在回收时可能得不到保存。
Activity中提供了一个onSaveInstanceState()
回调方法,这个方法可以保证活动被回收之前一定被调用,可以通过这个方法来保存数据。
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
String tempData = "Something you just typed";
outState.putString("data_key", tempData);
}
数据的取值可以在onCreate()
方法中取出
if (savedInstanceState != null) {
String tempData = savedInstanceState.getString("data_key");
Log.d(TAG, tempData);
}
5. 横竖屏切换
App横竖屏切换的时候会销毁当前的Activity然后重新创建一个,横竖屏切换时Activity走下述生命周期:
onPause-> onStop-> onDestory-> onCreate->onStart->onResume
禁止横竖屏自动切换的话,在AndroidManifest.xml中为Activity添加一个属性:android:screenOrientaiton
6. 启动模式
启动模式一共有4种,分别是:standard
,singleTop
,singleTask
和singleInstance
。可以再AndroidManifest.xml中通过<activity>
标签指定android:launchMode属性来选择启动模式。
6.1 standard
默认模式,每当启动一个新活动,就会在返回栈中入栈,并处于栈顶位置。该模式的活动无论这个活动是否在返回栈中存在,每次启动都会创建该活动的新实例。
6.2 singleTop
当活动指定为singleTop模式,启动活动时如果发现返回栈的栈顶已经是该活动,则认为可以直接使用它,不会再创建新的活动实例。
6.2 singleTask
当活动的启动模式指定为singleTask,每次启动该活动系统首先会在返回栈中检查是否存在该活动的实例,如果发现就直接使用,并把这个活动之上的所有活动统统出栈。如果没有发现就创建一个新的活动实例。
6.4 singleInstance
指定为singleInstance模式的活动会启用一个新的返回栈来管理这个活动(如果singleTask模式指定了不同的taskAffinity,也会启动一个新的返回栈)。这种模式解决了其他程序和我们的程序共享一个活动的实例
7. 简单技巧
7.1 快速定位某个界面对应的活动
新建一个Java类:BaseActivity,继承AppCompatActivity,重写onCreate()方法。
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d("BaseActivity", getClass().getSimpleName());
}
在oncreate()
方法中获取了当前实例的类名,然后将项目中所有活动的父类都不再继承AppCompatActivity,而是继承BaseActivity,这样查看日志,,每当进入一个活动的界面,该活动的类名就被打印出来。
7.2 随时退出程序
按home键只是将程序挂起,并没有退出程序,如果程序需要一个注销或者退出的功能,只需要一个专门的集合类对所有的活动进行管理就可以。
新建一个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();
}
}
}
}
修改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);
}
}
如果需要在某个地方退出程序,调用ActivityCollector.finishAll()
方法就可以。
可以再销毁所有活动代码的后面加上杀掉当前进程,确保程序完全退出:
android.os.Process.killProcess(android.os.Process.myPid());
7.2启动活动最佳写法
如果你的模块需要将一些重要数据传递给另一个模块,例如两个字符串参数,但是你不清楚启动这个活动需要传递哪些数据,只需在启动活动添加一个actionStart()
方法。
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.startActivities(intent);
}
如果你想要启动该活动,只需:
button1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
SecondActivity.actionStart(FirstActivity.this, "data1", "data2");
}
}
网友评论