1、创建Activity
手动创建activity时,Android studio会帮我们自动在Android Manifest.xml中进行注册,比较人性化。
如果程序中没有声明任何一个活动作为主活动,这个程序也可以正常安装,只是无法在启动其中看到或打开这个程序(一般作为第三方服务供其它应用在内部进行调用,如支付宝快捷支付服务)。
在活动中获取布局文件中定义的元素,采用findViewById方式返回的是一个View对象,需要向下转型成相应元素类型。
在活动中使用Menu:
首先需要创建菜单文件(在res下新建Menu文件夹,在此文件夹中创建菜单资源文件如main):
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/add_item"
android:title="Add"/>
<item
android:id="@+id/remove_item"
android:title="Remove"/>
</menu>
然后在活动中重写如下方法(ctrl+O):
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main,menu);
//getMenuInflater()方法能够得到MenuInflater对象,再调用它的inflate()方法即可给当前活动创建菜单
//第一个参数指定创建菜单的资源文件,第二个参数菜单项添加的目标Menu对象
return true;//允许菜单显示出来,false则无法显示
}
要使菜单有用,还需定义菜单响应事件,重写如下方法:
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()){
case R.id.add_item:
Toast.makeText(this,"You clicked Add",Toast.LENGTH_SHORT).show();
break;
case R.id.remove_item:
Toast.makeText(this,"You clicked Remove",Toast.LENGTH_SHORT).show();
break;
default:
}
return true;
}
销毁活动有两种方法:按back键或在活动点击事件中调用finish()方法(效果一样)。
2、使用Intent跳转活动
使用显式Intent:
button1.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v) {
//Toast.makeText(FirstActivity.this,"You clicked Button 1", Toast.LENGTH_SHORT).show();
// finish();
Intent intent = new Intent(FirstActivity.this,SecondActivity.class);
startActivity(intent);
//意图:在FirstActivity这个活动的基础上打开SecondActivity这个活动;
// 然后通过startActivity()方法来执行这个Intent
}
});
使用隐式Intent:
不明确指出想要启动哪个活动,而是指定了一系列更为抽象的action和category等信息,然后交由系统去分析这个Intent找出合适的活动(可以响应这个隐式Intent的活动)去启动。可通过如下方法指定活动能响应的Intent:
<activity android:name=".SecondActivity">
<intent-filter>
<action android:name="com.example.jojo.activitytest.ACTION_START"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
action和category要能同时匹配才能启动。
在想启动此活动的活动中需作如下修改:
Intent intent = new Intent("com.example.jojo.activitytest.ACTION_START");
startActivity(intent);
android.intent.category.DEFAULT是一种默认的category,在调用startActivity()方法时会自动将这个category添加到intent中
每个intent中只能指定一个action,但可以指定多个category。
Intent传递数据有正向传递和反向传递两种方式,正向传递直接在intent上绑定数据即可,方向传递需使用startActivityForResult()方法来启动下一个活动(并通过onActivityResult()方法来接收传回的数据和结果码)
3、活动的生命周期
Android是使用任务(Task)来管理活动的,一个任务就是一组存放在栈里的活动集合。
每个活动在其生命周期中最多可能会有4种状态:运行状态(系统最不愿回收)、暂停状态(内存极低情况系统才考虑回收)、停止状态(会保存相应状态和成员变量,但当其他地方需要内存时,可能被回收)、销毁状态(系统最倾向于回收)
生命周期中对应的七个回调函数:onCreate()、onStart()、onRestart()、onResume()、onPause()、onStop()、onDestroy()
如果活动被回收,要保存临时数据和状态,可使用onSaveInstanceState()回调方法(保证在活动被回收之前一定会被调用)。此方法会携带一个Bundle类型参数(提供了一系列方法用于保存数据,如putString()/putInt(),每个保存方法需传入两个参数,即键/值对)。保存后恢复:onCreate()方法也有一个Bundle类型的参数(一般情况下为null,但如活动在被回收之前有通过onSaveInstanceState()保存数据,则此参数就会带有之前保存的全部数据,只需用相应方法取出即可)
4、活动的启动模式
可在AndroidManifest.xml中通过给<activity>标签指定android:launchMode属性来选择启动模式。
standard: 默认启动模式。每次启动都会创建该活动的一个新实例(不会在乎是否已在返回栈中存在),在返回栈中同一活动可能存在多个实例。
singleTop: 在启动活动时如果发现返回栈的栈顶已经时该活动,则认为可直接使用它,不会船建新的实例。不过当未处于栈顶时,还是会创建新实例。
singleTask: 让活动在整个应用程序上下文中只存在一个实例。每次启动活动时,系统首先会在返回栈中检查是否存在该活动实例,如存在则直接使用,并把此活动上的所有活动统统出栈,如没发现则创建新实例。
singleInstance: 会启用一个新的返回栈来管理这个活动(如果singleTask模式指定了不同的taskAffinity,也会启动一个新的返回栈)。如果程序中有一个活动是允许其他程序调用的,可以解决共享活动实例问题。由于每个应用程序都有自己的返回栈,同一个活动在不同返回栈中入栈时必然会创建新的实例,而此模式下,会有一个单独的返回栈来管理这个活动,不同应用程序访问此活动都共用同一个返回栈。
5、活动最佳实践
a、知晓当前是在哪个活动:
创建一个BaseActivity(Java Class,因不需在manifest中注册),然后需要让BaseActivity成为项目中所有活动的父类。修改其他活动的继承结构,替换成BaseActivity.
public class BaseActivity extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d("BaseActivity",getClass().getSimpleName());//获取当前实例的类名并打印出来
}
}
由于最终继承自AppCompatActivity,所有活动的功能不会受影响。
b、 随时随地退出程序:
如果活动较多需连按多次Back键才能退出,按Home键只能挂起。可以用一个专门的集合类管理所有活动。
新建以下类作为活动管理器:
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())
c、启动活动
当要启动的活动不是自己写的,但需传递参数的时候,可做如下处理,在被启动的活动中添加如下代码:
public class SecondActivity extends BaseActivity {
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);
}
这样就能清楚地知道启动此活动需要传递哪些数据,现在只需一行代码就可以启动此活动了。在启动点添加如下代码即可:
SecondActivity.actionStart(FirstActivity.this,"data1","data2");
给每个活动都添加类似启动方法,可节省被询问时间同时让启动更简单。