前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >《Android编程权威指南》之第二个activity

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

作者头像
用户8928967
发布2021-09-22 10:27:04
6320
发布2021-09-22 10:27:04
举报
文章被收录于专栏:用户8928967的专栏

本章,是为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)用来与操作系统通信的一种媒介工具。

代码语言:javascript
复制
// 启动 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,这种写法会比较方便,就是被打开这会告诉打开者是否需要携带参数,参数是什么。

代码语言:javascript
复制
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 中:

代码语言:javascript
复制
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 中:

代码语言:javascript
复制
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

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-08-28,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 妮K妮K妮 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、创建第二个activity
  • 二、启动 activity
    • 基于intent的通信
      • 显式intent与隐式intent
      • 三、activity 间的数据传递
        • 使用 intent extra
          • 从子activity获取返回结果
          • 四、activity的使用与管理
          • 五、挑战练习:堵住作弊漏洞
          • 六、挑战练习:按题记录作弊状态
          • 最后
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档