安卓基础组件概念篇|青训营笔记
这是我参与「第四届青训营 」笔记创作活动的第1天
1.Android 需求引入
需求-图片浏览器
- 实现一个图片浏览app(Activity+Fragment)
- 旋转屏幕场景(Activity生命周期)
- 内置升级能力(Service使用)
- 单一首页(SingleTask)
- 相关图片(SingleTop)
- 扫描所有图片(ContentProvider)
- 提供图片选择能力给系统(Intent)
1.1 Activity基本用法:
- 声明在程序清单里(Androidmanifest.xml)
- kotlin或java将MainActivity的类文件写出
- 声明布局文件layout/activity.main.xml 注册->布局->绑定
相册列表页:GridView+Adaptor
相册图片页:GridView+Adaptor(换数据源)
大图页:Viewpager+Adaptor
问题:接个电话就crash了?->生命周期
原因:页面被回收导致本地变量被置空
问题解决:
添加判空逻辑避免空指针问题
在页面回收生命周期中储存数据,页面重建时进行恢复
1.1.1 Activity生命周期
- onCraete():创建时回调,一般在此处创建视图和绑定数据
- onStart(): 已启动,即将进入前台
- onResume(): 与用户开始交互,位于Activity栈顶(程序开始可见)
- onPause(): Activity失去焦点或已暂停,Activity页面部分可见,下一个生命周期是onResume()或onStop()
- onStop(): Activity不再可见,下一个回调是onRestart()或onDestory()
- onRestart():重启已停止的Activity,下一个回调是onStart()
- onDestory(): 销毁Activity,释放该Activity的所有资源
- onSaveInstanceState(): 在非正常关闭时回调,用于保存数据,不支持持久化数据(系统回收界面)
- onRestoreInstanceState()/onCreate():用于恢复数据
Case1部分遮挡:
部分遮挡:弹出dialog或请求授权等等 ->onPause() 遮挡恢复:重新回到onResume()。
Case2全遮挡:
页面全遮挡:->onStop() 遮挡恢复: ->onRestart()->onStart()->onResume()
Case3+4:配置改变场景
Case3配置改变场景(1):
销毁:Resumed()->onSaveIntanceState()->onPause()->onStop()->onDestory()
Case4配置改变场景(2):
重建:onCreate()->onStart()->onRestpreInstanceState()->onResume()
配置改变但不重建Activity:AndroidManifest配置Activity节点的configChange属性
- local:语言改变
- fontScale:字体大小改变
- orientation:旋转屏幕
- keyboardHidden:键盘显示隐藏 配置改变:onConfigurationChanged()
引子:加入主页按钮功能
问题:不特殊处理情况下,加入首页按钮之后,点击会在当前页面栈加入新首页,返回后页面会消失
预期:点击首页按钮回到首页,上面的页面全部退出
解决:将首页的launchmode设置为singleTask
1.1.2Activity启动模式
-standard:默认模式,允许重复
-singleTop:不允许连续重复 ->onNewIntent()
-singleTask: 不允许同个栈内重复
-singleInstance:整个系统不允许重复 (整个安卓系统只有一个)
例子:通讯录,银行登录界面
注:引自Android 关于SingleInstance Activity的注意事项 - 掘金 (juejin.cn)
-
启动顺序为:ActivityA->ActivityB(SingleInstance )->ActivityC ,点击Back退出顺序:C-》A-》B !!!
-
启动顺序为:ActivityA->ActivityB(SingleInstance ),点击HOME键再切回应用,展示A而不是B。
-
以该模式启动的Activity单独位于一个栈
思考:图库app需要每一个页面都是activity吗?
1.2Fragment
原因:解决页面碎片化 优点:速度快,进行组件分离
1.2.1Fragment基本用法
-
创建Fragment布局文件
-
创建Fragment子类,加载布局文件
-
Activity加载Fragment
静态加载:布局中绑定
动态加载:FragmentManager加载
1.2.2Fragment生命周期
- onAttach(): Fragment和Activity关联时调用
- onCreateView():当Fragment创建视图时调用
- onActivityCreated():Activity的onCreate()方法已返回时调用
- onDestoryView():当Fragment中的视图被移除时调用
- onDetach():Fragment和Activity取消关联时调用
CASE1启动:
启动:onAttach()->onCreate()->onCreateView()->onActivityCreated()->onStart()->onResume()->Resumed
CASE2退出:
退出: Resumed->onPause()->onStop()->onDestoryView()->onDestory()->onDetach()
CASE3部分遮挡:
部分覆盖:Resumed->onPause()->Paused
CASE4部分遮挡恢复:
部分遮挡恢复:Paused->onResume()->Resumed
CASE5完全覆盖:
完全覆盖:Resumed->onPause()->onStop()->onDestoryView()
CASE6完全遮挡恢复:
完全遮挡恢复: onCreateView()->onActivityCreated()>onStart()->onResume()->Resumed
注:Fragment生命周期可以通过FragmentTransaction.setMaxLifecycle手动干预
1.2.3Fragment与Activity交互
组件获取
- Fragement获取Activity中的组件:getActivity().finViewById(R.id.xxx)
- Activity获取fragment中的组件:getFragmentManager.findFragmentById(R.id.fragment_xxx)
数据获取
1.Activity传数据给Fragment:setArguments(Bundle bundle) 常用于启动
2.Fragment传数据给Activity:
a.通过对象直接传递(方法调用/接口调用) 直接getActivity
b.通过viewmodel/handler/broadcast/eventbus等通信
1.3 Service
服务
1.3.1 Service基本用法
- 注册:AndroidManifest中使用<service.../>的标签
- 创建:建立相应的Service实现类
- 加载:startService()/bindService()
1.3.2 Service生命周期
常用
- onStart()
- onBind()
- onCreate()
- onDestory()
1.3.3 Service与Activity通信
1.定义Binder子类,并实现getService()方法,返回Service对象
2.实现Service类onBind()方法,返回上述Binder对象
3.实例化ServiceConnection对象,实现onServiceConnected()方法,从中获取到Service实例
4.Activity中调用bindService()方法,并传递步骤3的ServiceConnecttion对象,将流程跑起来
5.Activity既可以通过调用Service实例中的方法进行直接通信
1.4 Broadcast
WHAT:没电,充电等等提示广播
1.4.1 Broadcast基本用法
静态广播
- 注册:AndroidManifest中使用<receiver.../><intent-filter.../>
- 创建:建立相应的BroadcastReceiver实现类
- 接受:在步骤2类onReceive()中接收广播
- 发送:Context.sendBroadcast()
动态广播
注册:Context.registerReceiver() 有生命周期限制
1.4.2 Broadcast常用系统广播 配合权限实现
- Intent.ACTION_CONNECTIVITY_CHANGE 网络发生变化
- Intent.ACTION_BATTERY_CHANGED 电量发生变化
- Intent.ACTION_SCREEN_ON 开屏
- Intent.ACTION_SCREEN_OFF 关屏
- Intent.ACTION_PACKAGE_INSTALL 安装应用程序
- Intent.ACTION_BOOT_COMPLETED 系统启动完成
- Intent.ACTION_PACKAGE_ADDED 安装程序
- Intent.ACTION_PACKAGE_REPLACED 程序更新
- Intent.ACTION_PACKAGE_REMOVED 卸载程序
1.5 ContentProvider
用于数据通信
1.5.1 基本用法
生产者
-
注册:AndroidManifest中使用<provider.../>
属性:anthorities/exported/readPermission/writePermission
-
创建:建立相应的ContentProvider实现类
方法:onCreate/getType/insert/delete/update/query
消费者
- 声明:AndroidManifest中声明权限
- 使用:context.getContentResolver() 方法:insert/delete/update/query 增删改查
Intent
部分控件通过Intent启动 “意图”
- Context.startActivity(Intent)
- Context.startService(Intent)
- Context.startBroadcast(Intent)
1.6.1用法
1.显式Intent
setComponent/setClass指定具体类 2.隐式Intent
- Action 动作
- Data 数据
- Category 类别
- Type 数据类型
- Component 组件
- Extra 扩展信息
- Flag 标志位 实现不了SingleInstance
1.6.2系统能力
-
电话:Intent(Intent_Action_DIAL,Uri.parse("tel:10010"))
-
短信:Intent(Intent_Action_SENDTO,Uri.parse("smsto:10010")) 数据头区别邮件短信
-
网页:Intent(Intent_Action_View,Uri.parse("https:www.baidu.com"))
-
邮件:Intent(Intent_Action_SENDTO,Uri.parse("mailto:someone@domain.com"))
-
地图:Intent(Intent_Action_View,Uri.parse("geo:39.9,116.3")) 经纬度
-
拍照:Intent(MediaStore.ACTION_IMAGE_CAPTURE)
-
设置:Intent(android.provider.Settings.ACTION_SETTINGS)
-
市场:Intent(Intent.ACTION_View,Uri.parse("market://details?id="+packageName))
使用:startActivity(Intent)
Android通信组件
多线程/多进程通信
2.1Handler
线程间通信:主线程通信
2.1.1基本用法
- 创建:新建Handler,实现handleMessage(Message)
- 构建Message:what/setData()
- 发送:子线程调用Handler.sendMessage(Message)发送Message
- 处理: 在Handler的handleMessage(Message msg)主线程更新UI
2.1.2核心原理
message query: 消息队列
2.2Binder
进程间通信:进程绑定
共享内存:数据拷贝次数 0 Linux进程隔离 内核空间才可以
Binder: 数据拷贝次数 1 效率高 CS架构 通信时Binder也隔离
Android Binder通信一次拷贝你真的理解了吗? - IT先森的个人空间 - OSCHINA - 中文开源技术交流社区
Socket: 数据拷贝次数 2
2.2.1基本用法
服务端
- 定义一个AIDL文件
- 实现描述的接口,编写service
- 如果有实体类,需要提供实体类(jar包形式)
客户端
- 拿到AIDL文件
- 绑定服务,获得接口持有对象
2.2.2核心原理
CS架构 Binder驱动 ServiceManager进程 代理模式 匿名共享内存
注:looper有唤醒机制,不会一直占用