Android 四大组件之Activity特征及交互
创建Activity
定义类继承自Activity类;
2)在manifest的Application节点中声明<activity>节点;
生命周期
onCreate():
当activity是被创建时候,会自动运行该方法。该方法做一些初始化动作,比如创建views,设置数据到list等等,该方法提供了一个Bundle类型的变量,该变量中有这个activity以前的状态信息,前提是以前存过这些信息。这个方法执行完后执行的是onStart()方法;若在onCreate方法中加入finish()方法,onCreate下一个运行onDestroy方法
onRestart():
把activity从onStop状态唤醒时,会用onRestart方法,该方法优先于再次运行的onStart,运行完onRestart之后运行onStart。若在onRestart()方法中加入finish()语句,则还是会继续运行onStart及后面的状态方法直到onDestroy运行完
onStart():
当activity对用户可见时会调用onStart,当activity在前台显示时,会运行onResume;当activity还没在前台显示就被隐藏(停止状态)了会运行onStop(),比如在onStart方法中用了finish()方法的话,onStart()之后就会直接运行onStop->onDestroy。
onResume():
当activity开始与用户交互时,会调用onResume,并且为了用户操作此时该activity位于activity栈的顶部。经过某些操作后该方法执行完后执行的是onPause()
onPause():
当一个activity运行到onResume方法后,不管是这个activity要销毁还是要暂停或停止,都会调用该方法。这个方法之后有可能是onResume也有可能是onStop,若是在这个activity-A中打开一个不完全覆盖这个activity-A的新activity-B,那么activity-A就会是onPause状态,当activity-B退出时,activity-A就直接运行onResume(前提是onPause的方法执行完了,否则会等onPause方法执行完后才运行onResume方法,所以不建议在这个方法中执行CPU密集的操作)。若是需要退出activity-A,那么下一个就会执行onStop。onPause()用于提交未保存发生变化了的持久化数据,及停止动画及其他其他比较消耗CPU的事件(比如广播接收器,传感器(比如GPS),或者消耗电量的资源),这是为了更好的运行新的activity
onStop():
当这个activity完全看不见的时候,会调用onStop方法,因为另一个activity会调用onResume并且覆盖这个activity。以下三种情况都会使这个activity调用onStop()方法,第一种是一个新的activity被执行,第二种是一个已经存在的activity被切换到最前端,第三种是这个activity要被销毁。如果通过用户召回这个activity,那么会调用onRestart方法;若这个activity要被销毁,则调用onDestroy方法
onDestroy():
当activity销毁前会调用该方法,比如发生如下情况:activity调用了finish()方法来结束这个activity,或者因为系统为了节省空间而临时销毁这个activity,这两个情况可以通过isFinishing()方法判断
总结:
当用户自己退出程序的时候,建议在onStop方法中保存数据;
当用户打开一个新的activity的时候,建议通过onSaveInstanceState来保存数据;这里在网上看到很多人说应该放在onPause里保存,其实我觉得在打开新的一个activity的时候,或者将程序至于后台的时候,都会默认调用onSaveInstanceState方法,而且在这种暂停的状态下,Android的内存管理机制也不太会杀死这种状态的activity。而用onPause保存的时候,若是下一个执行onResume的方法的话,会影响速度,当然数据量小的话也感觉不出来。
先打开ActivityA ,然后再打开ActivityB的生命函数调用流程
Activity的四种启动模式
1 Standard模式
Standard模式是Android的默认启动模式,你不在配置文件中做任何设置,那么这个Activity就是standard模式,这种模式下,Activity可以有多个实例,每次启动Activity,无论任务栈中是否已经有这个Activity的实例,系统都会创建一个新的Activity实例。
2 SingleTop模式
SingleTop模式和standard模式非常相似,主要区别就是当一个singleTop模式的Activity已经位于任务栈的栈顶,再去启动它时,不会再创建新的实例,如果不位于栈顶,就会调用调用onCreat()创建新的实例,现在把配置文件中FirstActivity的启动模式改为SingleTop,我们的应用只有一个Activity,FirstActivity自然处于任务栈的栈顶。这里有一个新的问题,对于每次启动Activity,我们该如何分别处理。答案就是onNewIntent()函数,虽然系统不会调用onCreat(),但会调用onNewIntent,我们可以在这个函数做相应的处理。
SingleTop模式下自己启动自己时的周期函数
3 SingleTask模式
SingleTask模式的Activity在同一个Task内只有一个实例,如果Activity已经位于栈顶,系统不会创建新的Activity实例,执行onNewIntent(),但Activity已经存在但不位于栈顶时,系统就会把该Activity之上的其他activity移除任务栈(相当于将改activity显示到栈顶),执行onNewIntent()。
4 SingleInstance模式
singleInstance模式是单例的,singleTask只是任务栈内单例,系统里是可以有多个singleTask Activity实例的,而singleInstance Activity在整个系统里只有一个实例,启动一singleInstanceActivity时,系统会创建一个新的任务栈,并且这个任务栈只有他一个Activity。
SingleInstance模式并不常用,如果我们把一个Activity设置为singleInstance模式,你会发现它启动时会慢一些,切换效果不好,影响用户体验。它往往用于多个应用之间,例如一个电视launcher里的Activity,通过遥控器某个键在任何情况可以启动,这个Activity就可以设置为singleInstance模式,当在某应用中按键启动这个Activity,处理完后按返回键,就会回到之前启动它的应用,不影响用户体验。
启动Activity的方式
通过意图(Intent)来启动一个Activity;
显示启动
显示启动一般用于自己调用自己的情况(在当前应用找),这样的启动方式比较快速,创建Intent后指定包名和类名;
Intent intent = new Intent(this, OtherActivity.class);
startActivity(intent); // 启动新的Activity
或者:
Intent intent = new Intent();
intent.setClassName("com.itheima.activity", "com.itheima.activity.OtherActivity"); // 包名、全类名
startActivity(intent); // 启动新的Activity
隐式启动
相比于显式Intent,隐式Intnet则含蓄了许多,它并不明确指出我们想要启动哪一个活动,而是指定一系列更为抽象的action和category等信息,然后交由系统去分析这个Intent,并帮我们找出合适的活动去启动。
Activity 中 Intent Filter 的匹配过程 :
// 电话
Intent intent = new Intent();
intent.setAction(Intent.ACTION_CALL); // 设置动作
intent.setData(Uri.parse("tel://123456")); // 设置数据
// 音频/视频,设置type
intent.setAction(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.parse("file:///mnt/sdcard/daqin.mp3"), "audio/*"); // 设置数据和数据类型,将启动音频播放器(vedio)
为隐式启动配置意图过滤器
显式意图是指在创建意图时指定了组件,而隐式意图则不指定组件,通过动作、类型、数据匹配对应的组件;
在清单文件中定义<activity>时需要定义<intent-filter>才能被隐式意图启动;
<intent-filter>中至少配置一个<action>和一个<category>,否则无法被启动;
<intent-filter>中的<action>、<category>、<data>都可以配置多个,Intent对象中不用全部匹配,每样匹配一个即可启动;
Intent对象中设置的action、category、data在<intent-filter>必须全部包含Activity才能启动;
如果一个意图可以匹配多个Activity,Android系统会提示选择;
每个Intent中只能指定一个action,但却能指定多个category;类别越多,动作越具体,意图越明确
在Intent添加类别可以添加多个类别,那就要求被匹配的组件必须同时满足这多个类别,才能匹配成功。操作Activity的时候,如果没有类别,须加上默认类别
当Intent匹配成功的组件有多个时,显示优先级高的组件,如果优先级相同,显示列表让用户自己选择
优先级从-1000至1000,并且其中一个必须为负的才有效
注:系统默认的浏览器并没有做出优先级声明,其优先级默认为正数。
区别
显式启动:直接指定要跳转的Activity类名,不用过滤,效率高,适用于同一个应用中的不同Activity跳转
隐式启动:需要过滤,相对耗时,但可以找到所有之匹配的应用。适用于不同应用之间的Activity跳转。
Activity之间的数据传递
使用Intent.putExtra()方法装入一些数据, 被启动的Activity可在 onCreate方法中getIntent()获取;
可传输的数据类型: 1.基本数据类型(数组), 2. String(数组), 3. Bundle(Map), 4.Parcelable Serializable(Bean),
基本类型:
Intent intent = new Intent(this, OtherActivity.class);
intent.putExtra("name", "张飞"); // 携带数据
intent.putExtra("age", 12);
startActivity(intent);
一捆数据:
Intent intent = new Intent(this, OtherActivity.class);
Bundle b1 = new Bundle();
b1.putString("name", "赵云");
b1.putInt("age", 25);
intent.putExtra("b1", b1);
序列化对象(须实现序列化接口):
4、关闭时返回数据
基本流程:
使用startActivityForResult(Intent intent, int requestCode) 方法打开Activity;
重写onActivityResult(int requestCode, int resultCode, Intent data) 方法;
新Activity中调用setResult(int resultCode, Intent data) 设置返回数据之后,关闭Activity就会调用上面的onActivityResult方法;
onActivityResult()发生在onStart()之前
不要通过 Intent 在 Android 基础组件之间传递大数据(binder transaction 缓存为 1MB),可能导致 OOM
Activity与Fragment之间传值
第一种就是在activity中建一个bundle,把要传的值存入bundle,然后通过fragment的setArguments(bundle)传到fragment,在fragment中,用getArguments接收,
具体代码如下
activity:
FragmentTransaction ft=fm.beginTransaction();
OneFragment oneFragment=new OneFragment();
ft.replace(R.id.frame,oneFragment,"f1");
Bundle bundle=new Bundle();
bundle.putString("dad","kkk");——这里的kkk就是要传的值
oneFragment.setArguments(bundle);
ft.commit();
OneFragment oneFragment=new OneFragment();
ft.replace(R.id.frame,oneFragment,"f1");
Bundle bundle=new Bundle();
bundle.putString("dad","kkk");——这里的kkk就是要传的值
oneFragment.setArguments(bundle);
ft.commit();
下面是fragment代码
Bundle bundle=getArguments();
String s=bundle.getString("dad");
Log.e("kkkkkk",s);
String s=bundle.getString("dad");
Log.e("kkkkkk",s);
第二种就是在activity中定义一个public的方法,将要传递的值以return的方式返回,在fragment的onAttach方法中,调用这个方法得到值
具体代码如下
activity:
//注意返回类型
public String rr(){
return "lll";
}
return "lll";
}
fragment代码:
//这里s是一个全局的String类型变量
@Override
public void onAttach(Context context) {
super.onAttach(context);
Log.i("fragment_111111111","onAttach");
s=((MainActivity)context).rr();
}
public void onAttach(Context context) {
super.onAttach(context);
Log.i("fragment_111111111","onAttach");
s=((MainActivity)context).rr();
}
/**
* Activity传值到Fragment
* 并接收从Fragment返回的值
* @author James
*
*/
public class MainActivity extends Activity {
private Button btn_send;
private MyFragment myFragment;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn_send = (Button)findViewById(R.id.button);
FragmentManager manager = getFragmentManager();
FragmentTransaction transation = manager.beginTransaction();
myFragment = new MyFragment();
transation.add(R.id.layout_container_fragment, myFragment);
transation.commit();
//Activity传值,通过Bundle
Bundle bundle = new Bundle();
bundle.putString("MainActivity", "Hello,Fragment");
//首先有一个Fragment对象 调用这个对象的setArguments(bundle)传递数据
myFragment.setArguments(bundle);
//点击按钮接受Fragment传回来的值
btn_send.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Bundle bundle = myFragment.getArguments();
String result = bundle.getString("MyFragment");
Toast.makeText(MainActivity.this, result, Toast.LENGTH_LONG).show();
}
});
}
}
/**
*@author James
*@date 2016年7月12日
*@Version 1.0
*/
public class MyFragment extends Fragment{
private Button btn_fragment;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.activity_fragment, container, false);
btn_fragment = (Button)view.findViewById(R.id.button_fragment);
//点击按钮接收Activity传过来的值
btn_fragment.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Bundle bundle = getArguments();
String result = bundle.getString("MainActivity");
Toast.makeText(getActivity(), result, Toast.LENGTH_LONG).show();
}
});
//Fragment回传值给Activity
getArguments().putString("MyFragment", "Hello,Activity");
return view;
}
}
也可通过RxJava或EventBus进行传递