本章主要讲述了如何新建一个 Acitivity ,并在两个 Activity 之间传递数据,最后挑战练习是如何在重建 Activity 时保留数据。
GitHub 地址:
第五章未完成挑战
第五章完成挑战问题1,2
第五章完成所有挑战问题
1. 新建一个 Activity
最好的方法是使用 Android Studio 自带的创建方法,若要手动创建,一定要有三个环环相扣的地方需要建立:
- 一个 JAVA 类:即 Activity 类, 可以视需求继承 Activity 或者其他的衍生类
- 一个布局文件:对于任意一个 Activity 来说,都需要加载一个布局文件,在 res/layout 文件夹下新建一个布局文件,并在代码中使用 setContentView() 方法加载布局
- ★★★★★ 一定要在 AndroidManifest.xml 中声明新的 Activity!
2. 启动Activity
Activity 类中的一个函数 public void startActivity(Intent intent)
, 调用该方法时,启动 Activity 的请求直接发给了操作系统的 ActivityManager。ActivityManager 负责创建 Activity 实例并调用其 onCreate()方法。示意图如下:
基于Intent的通信
Intent 对象是 component 用来与操作系统通信的一种媒介工具。Intent 类提供了多种构造方法以满足不同的使用需求, 这章使用的就是最简单的启动一个新的 Activity 的构造方法。
component 就是四大组件:Activity, Service, Broadcast Receiver, Content Provider
public Intent(Context packageContext, Class<?> cls)
//Class 对象必须已经在 AndroidManifest.xml 中声明才可以使用,否则将抛出 ActivityNotFoundException
3. Activity 间的数据传递
3.1 使用 Intent Extra
在使用 Intent 对象启动另一个 Activitiy 的时候使用了其构造方法,如果要让另一个 Activity 知道前一个 component 需要展示什么(比如用户到底点击了哪个按钮随之要展示什么详情),就需要在 Intent 中说明。使用 Intent 对象方法public Intent putExtra(String name, <Type> data)
将数据存到 Intent 对象内部,然后给操作系统。
这整个过程有点像送信:
- 一个 component 应该先准备一个信封(Intent),在信封上写好发件人和收件人(显式 Intent 的构造方法)。
- 接着写信(Intent Extra),装到信封里(Intent),用 startActivity() 方法把信投递给操作系统的 ActivityManager。
- ActivityManager 看到收件人的地址,去找到收件人,敲他家的门(调用其 onCreate() 方法),然后把信给他。
这样,一个 Activity 就被启动了。
一般来说,我们会在一个 Activity 中写入自己的启动方法或者一个『用于获取启动本 Activity 的 Intent 对象』的方法,因为这样的话,其他 component 在启动时能够清楚地知道需要什么参数。比如可以写一个
public static void actionStart(Context, Extra)
函数,传入参数是本 Activity 的上下文,和需要传递的额外信息,这样别的 component 在启动时,只需要调用该静态方法即可。
3.2 从子 Activity 获取返回结果
还是用送信来类比,如果一封信被另一个 Activity 收到了,他拆了信看完以后就丢弃了,并不会回信。那么如果发信者想要收信者回信,需要先跟 ActivityManager 说好,而且还要约定一个暗号,以便回信时不会弄错,然后 ActivityManager 再投递信,敲门并告诉另一个 Activity 应该回信。
也就是说,如果启动另一个 Activity 并希望其在退出时返回结果,那么应该使用下面的方法,即先跟 ActivityManager 说好,暗号就是 requestCode 。
public void startActivityForResult(Intent intent, int requestCode)
自己也要做好准备接受消息,即重写方法
protected void onActivityResult(int requestCode, int resultCode, Intent data)
这个多出来的 resultCode 顾名思义,就是结果的正确与否,一般会使用 Activity.RESULT_OK 或者 Activity.RESULT_CANCELED 来标志, 或者自定义常量 Activity.RESULT_FIRST_USER 以便根据 Activity 返回结果来做出不同操作。如果下一个 Activity 不设置结果的话(也就是不回信),用户退出该 Activity 时会默认返回 RESULT_CANCELED。
而回信的人只需要写信即可,直接使用 Activity 的方法:
public final void setResult(int requestCode, Intent data)
//或者
public final void setResult(int requestCode)
回传的数据也是使用 Intent 封装的。
3.3 最后大概总结一下这个过程:
如果需要在启动另一个 Activity 时传递数据,就使用 Intent 的 putExtra() 方法
如果还需要返回结果,就要使用 startActivityForResult() 函数, 需要事先规定好 requestCode
同时父 Activity 需要重写 onActivityResult() 函数,对返回的结果进行处理
子 Activity 若要回传数据,调用 setResult() 方法将数据放入即可。
注: SharedPreferences 有时也能起到传递信息的作用,但是一般只用来保存基本类型的数据,所以作用有限,就像把东西放在一个共有的环境里,大家都知道那里有东西,谁需要都可以去取。
4. Activity 的使用与管理
对于一个应用来说,启动时系统只是先启动了其中的一个 Activity,这个 Activity 理应已经在 AndroidManifest.xml 文件中声明为 Launcher Activity。
对于所有应用,其 Activity 共享同一个『回退栈』。如果没有重写 onBackPressed() 函数的话,按下返回键就将当前 Activity 弹出栈顶,或者自己调用了 Activity.finish() 函数时也同样会弹出栈顶。
5. 章末挑战
- 用户作弊后,可以旋转 CheatActivity 来清除作弊痕迹。
这个问题比较好处理,问题原因是由于旋转时需使用新的布局文件,重新调用了 onCreate() 方法,从而导致作弊痕迹丢失。那么重写 onSaveInstanceState() 方法,将其保存,在 onCreate() 中对数据进行恢复即可。
- 作弊返回后, 用户可以旋转 QuizActivity 来清除 mIsCheater 变量值。
同上
- 用户可以不断单击NEXT按钮,跳到偷看过答案的问题,从而使作弊记录丢失。
由于每道题有每道题的作弊记录,所以我的思路是采用一个 boolean 数组记录作弊情况,并且这个数组也应该在旋转的时候进行保存,在应用启动期间长期存在即可。如果有长期保存的需求,就要用到 SharedPreferences 或者数据库了。
GitHub Page: kniost.github.io
简书:http://www.jianshu.com/u/723da691aa42