Day2
安卓的四大组件:activity,service,content provider,broadcast receiver.
Acvtivity
基本概念
(1)一个Activity通常就是一个单独的屏幕(窗口)。
(2)Activity之间通过Intent进行通信。
(3)android应用中每一个Activity都必须要在AndroidManifest.xml配置文件中声明,否则系统将不识别也不执行该Activity。
几乎所有的Activity子类都会实现两种方法:
- onCreate: 是初始化界面的地方。可以使用setContentView定义UI资源,使用findViewById来检索UI控件。
- onPause: 是对于用户离开界面的处理。重要的是,这时用户所有的更改都应该提交(通常发送给持有数据的ContentProvider
生命周期
生命周期如下:
- OnCreate:
在第一次创建活动时调用,在这里完成所有的常规静态设置的位置:创建视图,将数据绑定到列表。 - OnRestart:
在重新启动时调用,总是跟着OnStart() - OnStart:
当界面对用户变成可见时调用。如果活动进入前台,则跟随执行onResume方法,如果隐藏,则执行onStop,此时。Activity可见但是没有在前台 - onResume:
当界面对用户变成可见时调用,如果界面进入前台,则跟随onResume方法,如果隐藏,则执行onStop方法。 - onPause:
onPause()方法在系统即将开始显示之前的界面时调用。 这通常用于将未保存的更改进行保存,并保存为持久化数据,并且会执行例如停止动画和其他可能消耗CPU的内容等。此方法的实现必须非常快速,因为在此方法返回之前,下一个界面不会显示.(就是界面转换的时候)
如果界面返回到前台,则跟随onResume();如果对用户不可见,则使用onStop() - onStop:
onStop()方法会在当界面对用户不再可见时调用,因为另一项界面正在显示并要去覆盖这个界面。 这可能是因为一项新的界面正在开始,其他的界面会被显示为前台界面,或者这个界面正在被摧毁 - onDestroy:
在你的界面被销毁前被最后调用的方法。 这可能是因为界面正在结束(有人在其中调用finish()方法因为系统会暂时销毁此Activity界面的实例以节省空间,你可以使用isFinishing()方法区分内存空间是否节省资源的这两种情况)。
任务和任务栈
任务是指在执行特定作业时与用户交互的一系列 Activity。 这些 Activity 按照各自的打开顺序排列在堆栈(即任务栈)中。
- 设备主屏幕是大多数任务的起点。当用户触摸应用启动器中的图标(或主屏幕上的快捷方式)时,该应用的任务将出现在前台。 如果应用不存在任务(应用最近未曾使用),则会创建一个新任务,并且该应用的“主”Activity 将作为堆栈中的根 Activity 打开。
当前 Activity 启动另一个 Activity 时,该新 Activity 会被推送到堆栈顶部,成为焦点所在。 前一个 Activity 仍保留在堆栈中,但是处于停止状态。Activity 停止时,系统会保持其用户界面的当前状态。 用户按“返回”按钮时,当前 Activity 会从堆栈顶部弹出(Activity 被销毁),而前一个 Activity 恢复执行(恢复其 UI 的前一状态)。 堆栈中的 Activity 永远不会重新排列,仅推入和弹出堆栈:由当前 Activity 启动时推入堆栈;用户使用“返回”按钮退出时弹出堆栈。 因此,返回栈以“后进先出”对象结构运行。 下图 通过时间线显示 Activity 之间的进度以及每个时间点的当前返回栈,直观呈现了这种行为。
Intent
Intent(意图)主要用于 Android 各组件之间的交互,它可以指明当前组件想要执行的动作,也可以传递数据。一般来说,Intent 常被用来启动 Activity、Service 以及 BroadCastReceiver。
Intent 分为显式 Intent 和隐式 Intent,先来了解一下显示 Intent。
显式Intent
在参数中明确设置要跳转的组件的包名和类名,并跳转。叫做显式Intent.
mBtnIntent.setOnClickListener(new View.OnClickListener() {
@Override public void onClick(View pView) {
Intent lIntent = new Intent(MainActivity.this, SecondActivity.class);
startActivity(lIntent);
}
});
隐式Intent
不明确指明想要启动哪一个组件,而是在清单文件下相应组件标签配置的intent-filter内容,通过设置Action,Data,Category,让系统自动筛选本次要启动的组件。
传递数据
使用putExtra方法即可。
Intent lIntent = new Intent(MainActivity.this, SecondActivity.class); lIntent.putExtra(“intent_data”, “hello_second_activity”);
startActivity(lIntent);
//接收 MAinActivity 传递来的数据
String intentStr = getIntent().getStringExtra(“intent_data”);
Toast.makeText(SecondActivity.this, intentStr, Toast.LENGTH_LONG).show();
第一个是key,第二个是value。接收信息的方法使用getIntent,然后调用getStringExtra方法,传入key。
传送一个类的方法如下:
/* 向 ThirdActivity 发送实体类数据 */
private void intentBean() {
IntentTestBean lIntentTestBean = new IntentTestBean();
lIntentTestBean.setName(“ginkwang”);
lIntentTestBean.setAge(“24”);
lIntentTestBean.setSex(“男”);
Intent lIntent = new Intent(SecondActivity.this, ThirdActivity.class);
Bundle lBundle = new Bundle();
lBundle.putSerializable(“intent_bean”, lIntentTestBean);
lIntent.putExtras(lBundle); startActivity(lIntent);
}
//接收 SecondActivity 传递的实体类数据
IntentTestBean lIntentTestBean = (IntentTestBean) getIntent().
getSerializableExtra(“intent_bean”);
if (lIntentTestBean != null) {
Toast.makeText(ThirdActivity.this, lIntentTestBean.toString(), Toast.LENGTH_LONG).show();
}
需要把类序列化传输。还有一个类型强制转换。
说完了传递数据,接下来讲一下 Intent 返回数据给上一个活动。
利用 Intent 返回数据,就不能用 StartActivity 启动活动了。Activity 中提供了一个 startActivityForResult 方法,此方法也可用于启动活动,并在活动销毁时传递数据给上一个活动。这正是我们想要的!
startActivityForResult 方法接收两个参数,第一个还是携带数据的 Intent,第二个是请求码,用于回调时对数据来源的判断。
看一下启动活动的代码:
Intent lIntent = new Intent(MainActivity.this, SecondActivity.class);
lIntent.putExtra(“intent_data”, “hello_second_activity”);
startActivityForResult(lIntent, 1);
和之前几乎一样,就是把 startActivity 换成了 startActivityForResult,请求码设置为1。
然后看一下 SecondActivity 中返回数据的代码:
//向 MainActivity 返回数据
Intent lIntent = new Intent();
lIntent.putExtra(“return_data”, “hello_main_activity”);
setResult(RESULT_OK, lIntent);
finish();
还是新建一个 Intent 对象,但不给它指定任何意图,仅仅用作传递数据。接着调用 setResult 方法,此方法专门用于向上一个活动传递数据,接收两个参数,第一个是 Intent,第二个是处理结果,一般使用 RESULT_OK 或 RESULT_CANCELED。最后调用 finish 方法销毁当前活动。
之后还要在 MainActivity 中重写一个 onActivityResult 用作回调:
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case 1://判断请求码是否为1,缺失是否从 SecondActivity 返回的
if (resultCode == RESULT_OK) {//再判断结果值看是否返回结果成功
String resultData = data.getStringExtra(“return_data”);
Toast.makeText(MainActivity.this, resultData, Toast.LENGTH_LONG).show();
}
break;
}
}
Fragment
基本概念
Fragment可以理解为一个具有自己生命周期的控件,有自己的处理输入事件的能力,自己的生命周期,但是必须依赖于Activity,能够互相通信并被托管。同时还可以在手机和平板显示不同的界面。
他的特性有:
- 模块性:将复杂的activity代码拆分成一个个的frament,获得更好的组织性和可维护性
- 可复用性:将行为或UI部分放在多个fragment中,可以在多个activity之间共享
- 可适应性:将UI的部分表示为不同的fragment,根据屏幕的方向和尺寸使用不同的布局
生命周期
fragment的生命周期如下图,可以看到其完全依赖于Activity,在其创建后才能开始,在结束后才能结束。
以下是fragmen各个事件的触发时机。
- onAttach :当fragment被依附到相应的activity上时被调用。
- onCreate :当一个新的fragment实例被初始化时调用,通常发生在它被附加到相应activity上后被调用 - fragment有一点像是病毒。
- onCreateView :当fragment创建了view层级中它自己的部分时,也就是被添加到了activity的view层级的时候被调用。
- onActivityCreated :当fragment的activity完成了它的 onCreate 事件之后调用。
- onStart :当fragment变为可见状态后调用。fragment只会在它的activity启动之后才会启动,且通常都是activity一启动之后,它就启动。
- onResume :当fragment变为可见且可交互的状态后调用。fragment resume只会在它的activity resume之后,且通常都是activity一resume之后,它就resume。
但稍等,fragment还未完成。下列的生命周期的事件将在你移除一个fragment的时候发生: - onPause :当fragment变为不可交互的状态时触发。它仅会在一个fragment将被移除或替代的时候,或其activity被pause的时候发生。
- onStop :当fragment变为不可见的状态时触发。它仅会在一个fragment将被移除或替代的时候,或其activity被停止的时候发生。
- onDestroyView :当fragment的view和创建在 onCreateView 中的相关资源从activity的view层级中被移除并销毁的时候触发。
- onDestroy :当fragment执行最后的清理时调用
- onDetach :当fragment从所在的activity中移除的时候调用
正如你所看到的,fragment的生命周期始终伴随着activity的生命周期。但它还有一些相应于view层级,状态,附加/分离于activity的额外的事件。
注意:Fragment只有在View被创建之后才能通过findviewbyid找到控件的实例,也就是只有在onViewCreated中才能使用findviewbyid方法
创建
有动态和静态两种办法,静态在xml文件中直接添加
和添加控件差不多。但是要用name属性来指定相关的Fragment类。id是必须的,tools:layout是用来预览的。
动态创建首先xml文件中只保留宽高和id属性。然后在Acticity中的onCreate中声明一个Fragment,使用FragmentTranscation的add方法或者replace方法,放进framelayout中。
在Fragment定义的时候要创建一个静态的newInstance,实现一个无参数的公开类型空构造器。
public class MainActivity: AppCompatActivity() {
override fun onCreate(Bundle savedInstanceState ) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val fragment: TestFragment = TestFragment()
val manager: FragmentManager = getSupportFragementManager() //v4
val transaction : FragmentTransactions = manager.beginTransaction()
transaction.add(R.id.frame_layout,fragment).commit()
消息传递
使用Bundle来携带数据进行传递。
传递在fragment的定义newInstance函数中传入消息,使用Bundle的putstring方法传入并返回fragment对象,而取出数据在onCreate中,使用Bundle的getString方法得到数据。
其他的使用和Activity差不多。更多细节还是继续使用的时候补充。