Activity相关
label 标签
<activity
android:name=".TestActivity"
android:label="Label Name"
/>
label 指定标题栏内容、Launcher的应用程序显示的名称。
menu 简单创建
- res 文件夹下创建
menu
文件夹 - 创建menu文件
- 重写
onCreateOptionsMenu
用于显示,并绑定menuInflater - 重写
onOptionsItemSelected
用于监听事件
具体文件:
xml
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/add_item"
android:title="1 item"/>
<item
android:id="@+id/second_item"
android:title="2 item"/>
</menu>
activity 的文件:
// 展示 Menu , menuInflater 指的是 getMenuInflater(), 用于创建菜单。
override fun onCreateOptionsMenu(menu: Menu?): Boolean
{
menuInflater.inflate(R.menu.menu_second, menu)
// true 表示显示Menu,反之不显示
return true
}
// 展示的 menu 用此方法响应。
override fun onOptionsItemSelected(item: MenuItem): Boolean
{
when(item.itemId)
{
R.id.add_item -> Unit
R.id.second_item ->Unit
}
// 改为 true
return true
}
Intent 简述
显式Intent
Intent的“意图非常明显”,故称之。
fun goto()
{
val intent = Intent(this, TestActivity::class.java)
startActivity(intent)
}
隐式Intent
隐式Intent依靠对 AndroidManifest.xml 的 activity 的标签添加<intent-filter>
,在标签intent-filter下依靠action
和category
实现activity的启动。
它并不直接声明activity,而是提供action
和category
让系统分析用于启动。
- 添加标签
<activity
android:name=".TestActivity"
android:label="Label Name"
android:exported="true">
<intent-filter>
<action android:name="TestActivity_ACTION"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
android 12开始,需要添加android:exported="true"
用于支app,这里声明了action为TestActivity_ACTION
,category为默认的android.intent.category.DEFAULT
也就是可以不提供category。
代码(二者等价):
// 方法1
startActivity(Intent("TestActivity_ACTION"))
// 方法2
startActivity(
Intent("TestActivity_ACTION").run {
addCategory("android.intent.category.DEFAULT")
}
)
- 每个 intent 由
一个
action 和 任意数量category
配合而成。 - 如果无法匹配,则报错。
更多隐式操作
Intent还可以启动其他程序Activity传递数据
即Data
标签
启动Activity传递数据
传递数据
private fun goto()
{
val intent = Intent(this, TestActivity::class.java)
intent.putExtra("key", "value")
startActivity(intent)
}
在启动的activity获取数据:
override fun onCreate(savedInstanceState: Bundle?)
{
super.onCreate(savedInstanceState)
val data = intent.getStringExtra("key")
}
退出某个activity返回值
Intent 传递数据
Intent 传递 基本类型数据
一些基本数据类型,譬如Int
、String
可以直接调用intent的内置函数:putExtra
放入,用getStringExtra、getIntExtra等读取。但传递一个对象,则无法支持。
Intent Serializable传递
Serializable序列化与反序列化,是Java保留下来的产物,效率相对较低,而且使用面窄,这里只给出一般用法,不建议使用。
工作原理:序列化与反序列化传输,虽然数据完全一致,但二者并不是同一对象。
需要传输的对象:
class Person : Serializable
{
var name = ""
val age = 0
}
传输方式:
private fun putData()
{
val person = Person().apply {
name = "Frank Miles"
age = 33
}
val intent = Intent(this, TestActivity::class.java)
intent.putExtra("data", person)
startActivity(intent)
}
获取方式
val person = intent.getSerializableExtra("data") as Person
Intent Parcelable 传递
与上者不同的是,Parcelable 是将一个完整的对象进行分解,分解的每一部分都是Intent所支持传输的基本数据类型,这样就支持了。
class Person() : Parcelable
{
var name = ""
var age = 0
constructor(parcel: Parcel) : this()
{
name = parcel.readString() ?: ""
age = parcel.readInt()
}
override fun describeContents() = 0
override fun writeToParcel(dest: Parcel, flags: Int)
{
// 顺序必须相同于createFromParcel所引用的 构造器
dest.writeString(name)
dest.writeInt(age)
}
companion object CREATOR : Parcelable.Creator<Person>
{
override fun createFromParcel(parcel: Parcel) = Person(parcel)
override fun newArray(size: Int): Array<Person?> = arrayOfNulls(size)
}
}
- 实现接口,必须要重写二个方法,writeToParcel中需要我们将字段一一写出,顺序一定要和createFromParcel实现的相同
- 必须提供名为CREATOR的匿名实现类。
这样,读取方法是:
val person = intent.getParcelableExtra("data") as Person
传输方法是相同的
另外,Kotlin提供了更为简单的用法:@Parcelable 注解,但传输的数据必须封装在主构造器中才行。
不过现在创建的kotlin项目一般都不会自动引入了.因为直接使用id去读取控件是会有额外的开销.所以官方已经不推荐这种写法了.
需要自动引入kotlin-android-extensions
才行。
@Parcelize
class Person(var name : String, var age : Int) : Parcelable {}
额外要注意的是
kotlin-android-extensions
kotlin-parcelize
这两个不可以同时引入,否则会报以下错误
‘kotlin-parcelize’ can’t be applied together with ‘kotlin-android-extensions’
底层Activity被销毁,临时数据保存方法
当Activity 1 进入 Activity 2 后,某种原因,Activity 1被销毁,则Activity 2返回时,会调用Activity 1的onRestart()
重新创建,此时部分数据会丢失:比如输入框文字、
解决方法:使用onSaveInstanceState()
保存数据于Bundle
,于onCreate()
中读取。
class TestActivity : AppCompatActivity()
{
override fun onCreate(savedInstanceState: Bundle?)
{
super.onCreate(savedInstanceState)
if(savedInstanceState != null) {
val value = savedInstanceState.getString("key")
}
}
override fun onSaveInstanceState(outState: Bundle)
{
super.onSaveInstanceState(outState)
outState.putString("key", "value")
}
}
拓展:Intent也可以保存Bundle用于传递。
屏幕旋转时保存数据方法
不建议用上述方法,而是使用Jetpack ViweModel存储数据。
Activity的启动模式
- 有四种:standard、singleTop、singleTask和singleInstance
- 在activity标签指定
android:launchMode
- 安卓管理Activity依靠栈来实现。
- standard,默认模式,不管Activity是否存在栈中,都会重新创建一个。
- singleTop,如果创建的活动和栈顶相则不创建,否则依然创建。
- singleTask,如果创建的活动存在,则把他拉至栈顶,否则创建。
- singleInstance,单独用一个栈来管理,便于共享活动。
kotlin 之 with/run/apply
- with
函数
,参数一是上下文指定,二是lambda表达式,返回最后一行值
val res = with(obj) {
// 也就是 obj.get("value"),返回的也是此函数的值
get("value")
}
-
run
不能直接调用,依附于对象
,返回最后一行作为值
-
apply
同run,但返回本体