第三章 探究Activity
-
使用Menu
-
src/main/res/menu文件夹下创建menu文件(menu_activity.xml)
<?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"> <item android:id="@+id/app_bar_search" android:icon="@drawable/ic_search_black_24dp" android:title="Search" app:showAsAction="ifRoom" app:actionViewClass="android.widget.SearchView" /> <item android:id="@+id/add_item" android:title="Add" /> </menu>
-
重写onCreateOptionsMenu()方法
override fun onCreateOptionsMenu(menu: Menu?): Boolean { menuInflater.inflate(R.menu.menu_activity, menu) return true }
-
重写onOptionsItemSelected()方法
override fun onOptionsItemSelected(item: MenuItem): Boolean { Toast.makeText(this, "$item.title 被点击了", Toast.LENGTH_SHORT).show() return super.onOptionsItemSelected(item) }
-
-
Intent
-
显式Intent
startActivity(Intent(this, MenuActivity::class.java))
-
隐式Intent
-
action
<activity android:name=".chapter3.MenuActivity"> <intent-filter> <action android:name="com.youngly.firstlineofcode.ACTION_START"/> </intent-filter> </activity>
startActivity(Intent("com.youngly.firstlineofcode.ACTION_START"))
-
category
<activity android:name=".chapter3.MenuActivity"> <intent-filter> <action android:name="com.youngly.firstlineofcode.ACTION_START"/> <category android:name="android.intent.category.DEFAULT"/> <!-- 当添加category时,默认的category需要加上 --> <category android:name="com.youngly.firstlineofcode.MENU_CATEGORY"/> </intent-filter> </activity>
val intent = Intent("com.youngly.firstlineofcode.ACTION_START") intent.addCategory("com.youngly.firstlineofcode.MENU_CATEGORY") startActivity(intent)
-
data
val intent = Intent(Intent.ACTION_VIEW) intent.data = Uri.parse("https://www.baidu.com") startActivity(intent)
-
android:scheme 用于指定数据的协议部分,例子中https部分
-
android:host 用于指定数据的主机部分,例子中www.baidu.com部分
-
android:port 用于指定数据的端口部分,一般紧随在主机名之后
-
android:path 用于指定主机名和端口之后的部分,如一段网址中跟在域名之后的内容
-
android:mimeType 用于指定可以处理的数据类型,允许使用通配符的方式指定
拓展deeklink
<activity android:name=".chapter3.DeeplinkActivity" android:label="deeplinkActivity"> <intent-filter> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.BROWSABLE" /> <data android:host="link" android:scheme="fl" /> </intent-filter> </activity>
val intent = Intent(Intent.ACTION_VIEW) intent.data = Uri.parse("fl://link") startActivity(intent)
-
-
-
返回数据
val intent = Intent(this, ReturnResultActivity::class.java) startActivityForResult(intent, 1) override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) val s = "requestCode = $requestCode, resultCode = $resultCode, data.string = ${ data?.getStringExtra("data_return") }" Toast.makeText(this, s, Toast.LENGTH_SHORT).show() }
override fun onBackPressed() { val intent = Intent() intent.putExtra("data_return", "hello") setResult(RESULT_OK, intent) super.onBackPressed() }
-
-
生命周期
-
Activity状态
- 运行状态,处于栈顶
- 暂停状态,例如弹出对话窗
- 停止状态,不处于栈顶,并且完全不可见
- 销毁状态,从栈中移除
-
生命周期
- onCreate(),初次创建调用,主要工作完成初始化操作,比如加载布局,绑定事件
- onStart(),由不可见到可见的时候调用
- onResume(),位于栈顶,并处于运行状态。
- onPause(),启动或恢复另一个Activity时调用,将一些消耗CPU的资源释放,以及保存一些关键数据,不能执行耗时操作,不然会影响新的栈顶Activity使用
- onStop(),完全不可见时调用
- onDestory(),被销毁之前调用
- onRestart(),停止状态切换为运行状态之前调用
-
-
启动模式
按下多任务键,看到的是Task(任务栈),多任务里看到的Task并不一定是存活的。
不同Task之间可以叠起来,Task叠加只适用于前台Task,前台叠加的多个Task在进入后台的第一时间就会被拆开。
Task由前台进入后台的两种方式:
-
按home键回到桌面
-
按最近任务键查看最近任务
属性:android:allowTaskReparenting="true"
属性:android:taskAffinity=""
Activity的taskAffinity默认取自Application的taskAffinity,Application的taskAffinity默认是包名。每个Task也有taskAffinity,值取自栈底的Activity的taskAffinity。
- 默认情况下,Activity会直接进入当前Task
- 但对于设置了android:launchMode="singleTask"的Activity,系统会先对比Activity和当前Task的taskAffinity是否相同
- 如果相同,正常入栈
- 如果不同,Activity会寻找和它的taskAffinity相同的Task后入栈,如果找不到,系统会为它创建一个新的Task
taskAffinity和最近任务列表
- 最近任务列表会列出现有的Task
-
它们的taskAffinity不一样
-
当多个Task具有相同taskAffinity的时候(App中有Activity配置android:launchMode="singleInstance"),最近任务列表只会显示最新展示过的那一个,
-
-
standard
默认启动模式,每启动一个新Activity都会放到栈顶。不同的Task中打开同一个Activity,Activity会被创建多个,并放进每个task中。例如电话App提供添加联系人界面,某个应用在添加联系人时,会将新建的添加联系人界面添加到自己的栈中。
-
singleTop
有新的页面启动请求时,当目标Activity处于当前栈顶时,会调用Activity的
onNewIntent()
方法,但不创建新实例; -
singleTask
设置了
singleTask
为启动模式的Activity,它在启动的时候,会先在系统中查找是否存在属性值affinity
等于它自己的属性值taskAffinity
的任务栈存在;如果存在这样的任务栈,它就会在这个任务栈中启动,否则就会在新任务栈中启动。因此,如果我们想要设置了启动模式为singleTask
的Activity在新的任务栈中启动,就要为它设置一个独立的taskAffinity
属性值。如果设置启动模式为singleTask
的Activity不是在新的任务栈中启动,它会在已有的任务栈中查看是否已经存在相应的Activity实例,如果存在,就会把位于这个Activity实例上面的其他Activity全部结束掉,最终这个Activity实例会位于任务栈的顶端。例如,邮件app提供编辑邮件的Activity,某个应用新建邮件创建编辑邮件的Activity,会新建一个task并将Activity放入其中,此时页面切换动画是应用间切换动画。
-
singleInstance
相比于singleTask的全局唯一,singleInstance是全局全栈都唯一。
多用于开放给外部App来共享使用
-
-
Kotlin课堂
-
标准函数
-
with
val with = with(StringBuilder()) { append("start eating fruit\n") for (s in listOf) { append("$s ") } append("\nate all fruit") // 返回值 toString() }
-
run
val run = StringBuilder().run { append("start eating fruit\n") for (s in listOf) { append("$s ") } append("\nate all fruit") // 返回值 toString() }
-
apply
val apply = StringBuilder().apply { append("start eating fruit\n") for (s in listOf) { append("$s ") } append("\nate all fruit") // 无返回值 }
-
-
定义静态方法
-
单例类
object DisplayUtil { fun dp2Px(dp: Float) = TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_DIP, dp, Resources.getSystem().getDisplayMetrics() ) }
-
伴生类
class SingleTopActivity : AppCompatActivity() { ...... companion object { fun actionStartSelf(context: Context) { val intent = Intent(context, SingleTopActivity::class.java) context.startActivity(intent) } } }
1、2两种方案只是提供了一些语法特性来支持类似于静态方法调用的写法,如果确实需要定义真正的静态方法,Kotlin提供了两种实现方式:注解和顶层方法
-
注解
@
JvmStatic
注解只能加载单例类或伴生类的方法上object DisplayUtil { @JvmStatic fun dp2Px(dp: Float) = TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_DIP, dp, Resources.getSystem().getDisplayMetrics() ) }
-
顶层方法
创建Kotlin文件
fun dp2Px(dp: Float) = TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_DIP, dp, Resources.getSystem().getDisplayMetrics() )
-
-