《Android编程权威指南》之第二个activity

本章,是为GeoQuiz应用添加第二个activity。

一、创建第二个activity

创建一个新的Activity,取名为CheatActivity,它对应的布局文件名为 activity_cheat,当然还有 activity 需要在 AndroidManifest.xml 注册。

  • 因此在创建的时候可选择直接 New Android Activity,这样 AS 可以自动帮我们生成布局文件以及注册代码。
create activity
  • 这里介绍一下布局预览,可以直接切换成横屏预览,偶尔有的布局可以不必特地为横屏再多写一套布局代码,如果直接横屏预览没有适配问题的话。
预览横屏效果
  • 再介绍了一个tools:text属性,在textview中使用这个,预览的时候能看到文字显示,实际运行不会显示,预览很方便!

  • AS快捷键Command+Shift+O(或Ctrl+Shift+N)快速打开文件。

二、启动 activity

startActivity(Intent)函数,调用请求实际上是发送给了操作系统的ActivityManager。ActivityManager负责创建Activity实例并调用其onCreate(Bundle?)函数,如图所示:

启动activity

基于intent的通信

intent 对象是 component (activity、service、broadcast receiver、content provider)用来与操作系统通信的一种媒介工具。

// 启动 CheatActivity
mBinding.btnCheat.setOnClickListener {                                  
    val intent = Intent(this, CheatActivity::class.java)               
    startActivity(intent)                                              
}                                                                      

在启动 activity 前,ActivityManager会确认指定的Class是否已在manifest配置文件中声明。如果已完成声明,则启动activity,应用正常运行。反之,则抛出ActivityNotFoundException异常,应用崩溃。这就是必须在manifest配置文件中声明应用的全部activity的原因。

显式intent与隐式intent

  • 显式intent:指定Context与Class对象,然后调用intent的构造函数来创建Intent。
  • 隐式intent:只要描述要完成的任务,操作系统就会找到合适的应用,并在其中启动相应的activity。

三、activity 间的数据传递

使用 intent extra

intent extra:activity间的通信与数据传递

在CheatActivity.kt中,写个伴生对象,拿到Intent,这种写法会比较方便,就是被打开这会告诉打开者是否需要携带参数,参数是什么。

private const val EXTRA_ANSWER_IS_TRUE = "answer_is_true";

class CheatActivity : AppCompatActivity() {

...

companion object {
        fun newIntent(packageContext: Context, answerIsTrue: Boolean): Intent {
            return Intent(packageContext, CheatActivity::class.java).apply {
                putExtra(EXTRA_ANSWER_IS_TRUE, answerIsTrue)
            }
        }
    }
}

这里涉及到了Kotlin伴生对象的概念,参考:https://www.kotlincn.net/docs/reference/object-declarations.html

从子activity获取返回结果

GeoQuiz应用内部的交互时序图

这里 startActivityForResult 已经被弃用了,当前 google 推荐registerForActivityResult 来替换它。具体详情参考官方文档:

https://developer.android.com/training/basics/intents/result?hl=zh-cn

因此,模仿案例,我的代码作了一点小修改。

MainActivity.kt 中:

class MainActivity : AppCompatActivity() {
···
  private val startForResult =
        registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
            if (it.resultCode == Activity.RESULT_OK) {
                quizViewModel.isCheater =
                    it.data?.getBooleanExtra(EXTRA_ANSWER_SHOW, false) ?: false
            }
        }
···

override fun onCreate(savedInstanceState: Bundle?) {
···
  mBinding.btnCheat.setOnClickListener {
            val answer = quizViewModel.currentQuestionAnswer
            startForResult.launch(CheatActivity.newIntent(this, answer))
        }
  }
}

CheatActivity.kt 中:

override fun onCreate(savedInstanceState: Bundle?) {
        ···
        mBinding.btnShowAnswer.setOnClickListener {
            val answerText = when {
                answer -> R.string.true_button
                else -> R.string.false_button
            }
            mBinding.tvAnswer.setText(answerText)

            val data = Intent().apply { putExtra(EXTRA_ANSWER_SHOW, isAnswerShown) }
            setResult(Activity.RESULT_OK, data)
        }
    }

这里代码还涉及到了 kotlin 中 apply 的使用
有关 kotlin 作用域函数语法详情参考:
https://www.kotlincn.net/docs/reference/scope-functions.html

四、activity的使用与管理

本小结要表达的就是,Android 管理任务和返回堆栈的方式是将所有接连启动的 Activity 放到同一任务和一个“后进先出”堆栈中。

然后从桌面点击应用图标启动的第一个activity,是在配置文件中,intent-filter元素节点被指定为launcher activity 的那个activity。

根据此特性,在我们的大多的项目中,都会封装一个统一管理acitivity的工具类,可以随时管理自己已打开的所有的activity,比如:https://www.jianshu.com/p/ed897d567b02

关于任务和返回堆栈详情参考:https://developer.android.com/guide/components/activities/tasks-and-back-stack?hl=zh-cn

五、挑战练习:堵住作弊漏洞

既然用户可以通过旋转CheatActivity来清除作弊痕迹,那么要解决此问题,当然就是利用前置知识,在设备旋转或者app被销毁也保存好此作弊痕迹数据就可以啦,其实跟前面也是一样的,用 ViewModel + onSaveInstanceState()的方式就OK。

六、挑战练习:按题记录作弊状态

当前,哪怕用户只在一道题上作弊,应用都会认为他们题题作弊。完善GeoQuiz应用,按题记录用户作弊情况。也就是说,如果用户偷看了某道题的答案,那就在他回答那道题时,弹出作弊警告消息。然后在继续答题过程中,如果用户不再作弊了,就给出答案正确与否的评判。

据我的审题噢,警告 Toast 在示例中就已经做了的,因此这个附加练习题,应该是本就有的功能。

在之前的章节,有个评分的挑战练习,我这里再改改评分逻辑,就是作弊的题目即使答对了,也不算作答对的题目数去计分,也就是作弊答对计0分。

最后

挑战练习都没有贴源码了,解决方案思路在此了。当然练习Demo和练习题都是要做一遍的。

个人实践代码地址:https://github.com/visiongem/AndroidGuideApp/tree/master/GeoQuiz

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,335评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,895评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,766评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,918评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,042评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,169评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,219评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,976评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,393评论 1 304
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,711评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,876评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,562评论 4 336
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,193评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,903评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,142评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,699评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,764评论 2 351

推荐阅读更多精彩内容