关于安卓学习的博客将是根据第一行代码Android的学习总结,内容将不会面面俱到,而是挑选重要的知识进行梳理。
3. Activity
3.1 Activity的基本用法
在创建Activity时的两个选项:
- Generate Layour File:自动为当前Activity创建一个布局文件(Layout)。
- Launcher Activity:自动将当前Activity设置为当前项目的主Activity。
布局文件XML中命名语法:
- 引用id:@id/id_name
- 定义id:@+id/id_name
给当前Activity加载布局的方式:
- 在重写父类onCreate函数时调用
setContentView(layout id)。值得注意的是项目中添加的任何资源都会在R文件中根据名称的路径生成一个相应的资源id。 - 使用binding.root的方式调用layout。
setContentView(binding.root)
在AndroidManifest文件中注册的说明:我们可以在AndroidManifest中对各个Activity进行配置,包括加载方式、主题等,还可以制定MainActivity等。
- 通过android:name来指定Activity。
- 指定MainActivity的方式为在
<activity>标签内部添加<intent-filter>标签并在里面设置<action>和<category>。我认为可以理解为将当前Activity与触发MainActivity的Intent绑定,即设置当前Activity为MainActivity。
使用Toast进行消息提醒:
- 弹出Toast的函数
Toast.makeText(context, text, length).show()。一般Toast设置在Button等控件的触发函数内。makeText函数需要三个参数。第一个是Toast要求的上下文,可以设置为当前Activity,即this。第二个参数是Toast显示的内容,第三个参数是显示的时常。
使用binding获取布局控件的步骤:
- 在项目gradle文件中加入代码
buildFeatures {
viewBinding true
}
-
获取对应布局类实例:
val binding = FirstLayoutBinding.inflate(layoutInflater)或者
val binding = FirstLayoutBinding.inflate(LayoutInflater.from(this)) -
直接从binding中获取控件。
binding.button1.setOnClickListener{...}
在Acticity中使用Menu:
- 在res目录下创建menu文件夹
- 在menu文件夹下创建Menu的XML文件例如‘main’
- 在main.XML中通过增加
<item>设置下拉菜单 - 重写Activity的
onCreateOptionMenu()方法。其中menuInflater用到了Kotlin简化get/set的语法糖 - 重写Activity的
onOptionItemSelect方法,使用when语句设置点击Menu中Item的响应
3.2 Intent与Activity
Intent是Android程序中各组件进行交互的一种重要方式,不仅可以指明当前组件想要执行的操作,还可以在不同组件之间传递数据。
显式Intent
- 使用Intent的构造函数
Intent(context, Class<?> cls) - 在控件的Listener中调用函数
startActivity(intent)来显式启动目标Activity
隐式Intent
通过指定<action>和<category>的方式交由系统决定启动对应的Activity。
- 对于配置Activity的
<action>和<category>,可以在AndroidManifest.XML文件中对应<activity>的<intent-filter>条目内进行指定。 - 使用Intent的构造函数
Intent(action :String)来创建Intent,并使用函数Intent.addCategory(category :String)来增加category。 - 注意事项:一个Activity可以设置一个action和多个category。当没有Activity符合当前Intent的要求时,系统会被报错。
- 隐式Intent的扩展:Intent的action有很多玩法,例如可以启动其他的程序。eg.使用Intent.ACTION_VIEW + intent.data = uri的方法打开浏览器。注意此时要在对应Activity中设置
<data>标签并进行一些scheme,host,port等的规定。
binding.button1.setOnClickListener {
val intent = Intent(Intent.ACTION_VIEW)
intent.data = Uri.parse("https://www.baidu.com")
startActivity(intent)
}
使用Intent向下传递数据
上层Activity在Intent中保存数据,下层Activity从启动自身的Intent中获取数据。
- 在创建Intent后使用函数
Intent.putExtra(key, value)来保存数据。 - 下层Activity根据Kotlin的语法糖直接获取intent并选择调用其函数
intent.getStringExtra(key),intent.getIntExtra(key),intent.getBooleanExtra(key)来获取数据。
返回数据给上层Activity
- 上层Activity使用
startActivityForResult(intent, requestCode)启动下层Activity。 - 下层Activity调用
intent.putExtra(key, value)保存数据 - 下层在调用销毁函数
finish()之前调用函数setResult(resultCode, intent)来配置结果码,一般是RESULT_OK/RESULT_CANCELED。 - 上层Activity重写函数
onActivityResult(requestCode, resultCode, intent)来根据requestCode确定下层Activity的intent,根据resultCode确定下层的处理结果,进而处理intent中保存的数据。 - 额外知识:使用back按键返回时Activity会调用
onBackPressed()函数,可以重写该函数并在此之前设置serResult(),从而使back键返回也能附带intent数据。
Activity的生存周期
Activity状态
Android使用task来管理Activity,一个task就是一组存放在返回栈里的Activity。每个Activity在其生存周期中最多会有四种状态,分类的根据是Activity在返回栈中的位置和Activity的可见行,并且系统在回首内存是会对不同状态的Activity采用不同的优先级。
| Activity状态 | 描述 |
|---|---|
| 运行状态 | Activity处于站顶,即运行状态(交互状态) |
| 暂停状态 | Activity不再处于栈顶,但仍可见 |
| 停止状态 | Activity不再处于栈顶,也不可见 |
| 销毁状态 | Activity从返回栈中移除 |
Activity的生存期
Activity类中定义了七个方法用以改变运行状态。状态转移图
stateDiagram-v2
[启动Activity] --> onCreate()
onCreate() --> onStart()
onStart() --> onResume()
onResume() --> [Activity运行中]
[Activity运行中] --> onPause():另一个Activity来到站顶
onPause() --> onStop():Activity不再可见
onStop() --> [杀掉进程]:优先级更高的应用需要内存
[杀掉进程] --> onCreate():返回应用
onStop() --> onDestory()
onDestory() --> [关闭Activity]
onPause() --> onResume()
onStop() --> onRestart():返回该Activity
onRestart() --> onStart()
markdown怎么才能让状态图不这么乱...
Activity的三种生存期
- 完整生存期。onCreate() -> onDestory()
- 可见生存期。onStart() -> onStop()
- 前台生存期。onResume() -> onPause()
应对Activity被回收
为防止未手动销毁的Activity因内存不足被系统回收引起的数据丢失问题,可通过重写回调函数onSaveInstance(Bundle),并将数据通过函数Bundle.putString(key, val)及其类似函数存储在Bundle类对象中,在onCreate()阶段重新赋值即可。
Activity的启动模式
- standard模式:每次启动都会创建一个该Activity的新实例。
- singleTop模式:在启动Activity时如果发现返回栈已经是该Activity,则直接使用当前栈顶的Acticity。
- singleTask模式:每次启动Activity时若返回栈中存有该Activity,则将该Activity之上的所有其他Activity出栈。
- singleInstance:启用单独的返回栈(task)来管理该Activity,任何应用程序以singleInstance的方式启动该Activity时都会访问这个返回栈,从而解决共享Activity实例的问题。
Activity的最佳实践
创建Activity的基类BaseActivity并继承AppCompatActivity()。我们可以在BaseActivity中新增一些功能,从而更好地处理实际的Activity。
- 确定当前的界面对应的Activity:在BaseActivity的onCreate()函数中加入Log.d("BaseActivity", javaClass.simpleName)。根据日志信息确定当前Activity。
- 一键退出程序:创建单例类
object ActivityCollector,使用类中list管理所有的Activity,内部实现finishAll()函数销毁所有不处于isFinishing的Activity。BaseActivity在onCreate()和onDestroy()时在list中增删Activity实例。这样若想一键退出程序时,直接调用ActivityCollector.finishAll()+killProcess(pid)即可。 启动Activity的最佳写法:为了明确创建Activity需要的参数,我们可以在Acticity中添加静态函数actionStart(context, param1, param2)实现(在Kotlin中可以通过companion object结构体实现)。在actionStart()函数内部可以创建Intent并传入参数,随后使用context.startActivity(intent)启动自身Activity,再配合onCreate()即可完成Activity的创建和初始化。在上层Activity调用时,即可通过TargetActivity.actionStart(this, param1, param2)启动该Activity。即函数actionStart()作为启动Activity的接口函数显式地声明需要的参数。