Android基础知识总结(1)


最近两个月学习Android看了几本书,在继续往下学之前觉得有必要总结一下学到的知识,博客的内容主要来自于看的几本书和他人的博客。
注:看的几本书是《第一行代码 Android 第2版》,《Android编程权威指南第3版》,《Android进阶之光》,《Android开发艺术探索》。

1.Activity的生命周期

1.任务和返回栈

Tasks and Back stack 详解:https://www.jianshu.com/p/833de0674f80
Android Task相关属性详解:https://www.jianshu.com/p/6dc5154b08b8
实验
1.activityA的launchMode设置为singleTask,调用activity顺序是:A=>A=>B=>A,打印日志:

10-09 14:28:15.776 15610-15610/pers.peng.test D/activity-A: onCreate taskId=1366
10-09 14:28:15.776 15610-15610/pers.peng.test D/activity-A: onStart taskId=1366
10-09 14:28:21.376 15610-15610/pers.peng.test D/activity-A: onNewIntent taskId=1366
10-09 14:28:22.686 15610-15610/pers.peng.test D/activity-B: onCreate taskId=1366
10-09 14:28:22.686 15610-15610/pers.peng.test D/activity-B: onStart taskId=1366
10-09 14:28:23.076 15610-15610/pers.peng.test D/activity-A: onStop taskId=1366
10-09 14:28:23.906 15610-15610/pers.peng.test D/activity-A: onNewIntent taskId=1366
10-09 14:28:23.906 15610-15610/pers.peng.test D/activity-A: onStart taskId=1366
10-09 14:28:24.296 15610-15610/pers.peng.test D/activity-B: onStop taskId=1366
10-09 14:28:24.296 15610-15610/pers.peng.test D/activity-B: onDestroy taskId=1366

A和B位于同一个返回栈中,在B跳转到A时,不会新建A的实例,而是重用已存在于栈中的实例A,并将其上面的activity全部弹出,将A移到栈顶。此时按返回键,会退出程序。

2.activityA的launchMode设置为singleInstance,调用activity顺序是:A=>A=>B=>C=>A,打印日志:

10-09 14:57:05.466 16406-16406/pers.peng.test D/activity-A: onCreate taskId=1398
10-09 14:57:05.466 16406-16406/pers.peng.test D/activity-A: onStart taskId=1398
10-09 14:57:07.826 16406-16406/pers.peng.test D/activity-A: onNewIntent taskId=1398
10-09 14:57:09.046 16406-16406/pers.peng.test D/activity-B: onCreate taskId=1399
10-09 14:57:09.046 16406-16406/pers.peng.test D/activity-B: onStart taskId=1399
10-09 14:57:09.756 16406-16406/pers.peng.test D/activity-A: onStop taskId=1398
10-09 14:57:10.426 16406-16406/pers.peng.test D/activity-C: onCreate taskId=1399
10-09 14:57:10.426 16406-16406/pers.peng.test D/activity-C: onStart taskId=1399
10-09 14:57:10.816 16406-16406/pers.peng.test D/activity-B: onStop taskId=1399
10-09 14:57:12.056 16406-16406/pers.peng.test D/activity-A: onNewIntent taskId=1398
10-09 14:57:12.056 16406-16406/pers.peng.test D/activity-A: onStart taskId=1398
10-09 14:57:12.856 16406-16406/pers.peng.test D/activity-C: onStop taskId=1399

指定为singleInstance的activity会在单独的任务中打开,且是该任务唯一仅有的成员。按返回键返回的顺序是:A=>C=>B=>退出程序。

2.Activity的生命周期分析

1.常见情况下的生命周期分析
(1)启动activityA,跳转到activityB,按返回键返回到activityA,A的方法回调如下:onCreate->onStart->onResume->onPause->onStop->onRestart->onStart->onResume
(2)启动activityA,弹出dialog,按返回键回到activityA,A的方法回调如下:onCreate->onStart->onResume->onPause->onResume
(3)启动activityA,按返回键结束程序,A的方法回调如下:onCreate->onStart->onResume->onPause->onStop->onDestroy
(4)启动activityA,按home键回到启动界面,A的方法回调如下:onCreate->onStart->onResume->onPause->onSaveInstanceState->onStop
(5)启动activityA,旋转屏幕,A的方法回调如下:onCreate->onStart->onResume->onPause->onSaveInstanceState->onStop->onDestroy->onCreate->onStart->onResume

onStart和onResume,onPause和onStop的区别?
答:onStart和onStop是从Activity是否可见这个角度来回调的,而onResume和onPause是从Activity是否位于前台这个角度来回调的,除了这种区别,在实际使用中没有其他明显区别。
假设当前Activity为A,如果从A中跳转到ActivityB,那么B的onResume和A的onPause哪个先执行?
答:回调顺序为:A onPause->B onCreate->B onStart->B onResume->A onStop
为了使新Activity尽快显示,是否要把所有资源回收放在onStop中?
答:不是。如果在Activity A中打开了如照相机等独占设备,需要在onPause中释放,否则Activity B将不能正常启动照相机。所以一般在onPause中进行关闭独占设备,关闭动画等,防止Activity B需要用到这些资源,而在onStop中释放其他资源。

关于每个回调方法的详细信息见:https://developer.android.google.cn/reference/android/app/Activity

2.异常情况下的生命周期分析
异常情况主要包括旋转屏幕,按home键,内存不足导致低优先级的Activity被杀死等,这些情况下onSaveInstanceState会被调用,如果activity销毁重建还会调用onRestoreInstanceState。onSaveInstanceState会在onPause或onStop之前执行,onRestoreInstanceState会在onStart和onResume之间执行。在onSaveInstanceState和onRestoreInstanceState中,系统自动为我们做了一定的恢复工作。当Activity在异常情况下需要重新创建时,系统会默认为我们保存当前Activity的视图结构,并且在Activity重启后为我们恢复这些数据,比如文本框中用户输入的数据,ListView滚动的位置等。

如果当某项内容发生改变后,我们不想系统重新创建Activity,可以给Activity指定configChanges属性。比如不想让Activity在屏幕旋转的时候重新创建,就可以给configChanges属性添加orientation这个值,如下所示。
android:configChanges=“orientation”
如果想指定多个值,可以用“|”连接起来。系统配置中所含的项目是非常多的。configChanges的项目和含义见:https://blog.csdn.net/weixin_36039900/article/details/80166786
——《Android开发艺术探索》

2.其他

Activity标签属性:https://www.cnblogs.com/tsingke/p/9074628.html

1.层级导航

在activityB标签下增加:android:parentActivityName=".activityA",从activityA跳转到activityB,点击activityB actionbar上的返回箭头返回到activityA,activityA的方法回调如下:onCreate->onStart->onResume->onPause->onSaveInstanceState->onStop->onDestroy->onCreate->onStart->onResume。
在activityA标签下增加:android:launchMode="singleTop",从activityA跳转到activityB,点击activityB actionbar上的返回箭头返回到activityA,activityA的方法回调如下:onCreate->onStart->onResume->onPause->onSaveInstanceState->onStop->onNewIntent->onRestart->onStart->onResume。

2.IntentFilter的匹配规则

IntentFilter中的过滤信息有action,category和data。隐式调用的Intent可以设置一个action,多个category和一个data。如果activityA的intent-filter如下:

<intent-filter>
    <action android:name="pers.peng.test.action.A"></action>
    <action android:name="pers.peng.test.action.B"></action>
    <category android:name="pers.peng.test.category.A"></category>
    <category android:name="pers.peng.test.category.B"></category>
    <category android:name="android.intent.category.DEFAULT"></category>
    <data android:scheme="http"/>
    <data android:mimeType="image/*"/>
    <data android:mimeType="audio/*"/>
</intent-filter>

隐式调用的Intent的匹配规则如下:
action:Intent中的action要存在且必须和过滤规则中的任何一个action相同即可匹配成功,针对上面的过滤规则,只能使用 intent.setAction("pers.peng.test.action.A")intent.setAction("pers.peng.test.action.B") 。另外,action区分大小写。
category:Intent中的category必须是过滤规则中category的子集,如果过滤规则中有<category android:name="android.intent.category.DEFAULT"/>,intent中可以没有category,因为系统在调用startActivity或startActivityForResult的时候会默认为Intent加上"android.intent.category.DEFAULT"。
data:data的语法如下所示:

<data android:scheme="string"
      android:host="string"
      android:port="string"
      android:path="string"
      android:pathPattern="string"
      android:pathPrefix="string"
      android:mimeType="string"/>

data包括两部分:mimeType和URI。data的匹配规则和action类似,Intent中必须含有data数据且要和过滤规则中的某一个data相同。针对上面的过滤规则,只能使用 intent.setDataAndType(Uri.parse("http://xxx"),"audio/xxx")intent.setDataAndType(Uri.parse("http://xxx"),"image/xxx")
除此以外,还需要注意两点:
1.如果过滤规则中同时存在mimeType和URI,要为Intent指定data,只能调用setDataAndType方法,不能先调用setData再调用setType,因为这两个方法彼此会清除对方的值,这个看源码就很容易理解,比如setData:

public Intent setData(Uri data){
        mData = data;
        mType = null;
        return this;
}

setType同理。如果过滤规则中没有指定URI,可以使用setType,也可以使用intent.setDataAndType(Uri.parse("content://xxx"),"xxx/xxx")intent.setDataAndType(Uri.parse("file://xxx"),"xxx/xxx"),因为content和file是没有指定URI时的默认值。
2.intent-filter中的data有两种写法,除了上面的那种,还可以写成:

<data android:scheme="http" android:mimeType="image/*"/>
<data android:mimeType="audio/*"/>

两种写法是一样的,不要以为可以使用setType("audio/xxx")

Android中Action和Category常量表:https://cloud.tencent.com/developer/article/1330887

最后,当我们通过隐式方法启动一个Activity的时候,可以做一下判断,看是否有Activity能够匹配我们的隐式intent,如果不做判断可能会出错。判断方法有三种:采用PackageManager的resolveActivity方法和queryIntentActivities或者Intent的resolveActivity方法,它们的方法原型如下:
public abstract List< ResolveInfo > queryIntentActivities(Intent intent,int flags);
public abstract ResolveInfo resolveActivity(Intent intent,int flags);
public abstract ComponentName resolveActivity(PackageManager pm);

flags使用MATCH_DEFAULT_ONLY这个标记位。
——《Android开发艺术探索》

3.Activity,Application和Context

Android 成长笔记1——activity与context:https://www.jianshu.com/p/3172baa3d74d
Application中的Context和Activity中的Context各自的使用场景:

copy别人的话:凡是跟UI相关的,都应该使用Activity做为Context来处理;其他的一些操作,Service,Activity,Application等实例都可以。
在Android中,可以通过继承Application类来实现应用程序级的全局变量,这种全局变量方法相对静态类更有保障,直到应用的所有Activity全部被destory掉之后才会被释放掉。
示例(kotlin):

class App : Application() {
    companion object {
        var instance: App by DelegatesExt.notNullSingleValue()
    }
    override fun onCreate() {
        super.onCreate()
        instance = this
    }
}
object DelegatesExt {
    fun <T> notNullSingleValue() = NotNullSingleValueVar<T>()
}
class NotNullSingleValueVar<T> {

    private var value: T? = null

    operator fun getValue(thisRef: Any?, property: KProperty<*>): T =
        value ?: throw IllegalStateException("${property.name} not initialized")

    operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
        this.value = if (this.value == null) value
        else throw IllegalStateException("${property.name} already initialized")
    }
}

不要忘记要在Manifest中application标签下加上android:name=".App"

4.Activity进出场动画

Android Activity切换动画(进入和退出):https://www.jianshu.com/p/8bda45eef4f1

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值