
一:View
一、 通用介绍
1、px dp dpi sp
- px是物理像素点,dpi 对角线每英寸像素点,
- dp,与px的像素比,Android规定在160dpi的设备上1dp=1px...以此类推。可以解决不同机型大小不一致的问题;
- sp,一般给文字设置,用于文字随系统字体大小变化,不需要这个效果可以设置dp。
- 分辨率讲的是px像素量比值,如1080p的分辨率是宽度108016/9=19201080,得到高度1920。只靠分辨率还不能确定dpi(像素密度),还受屏幕尺寸变量影响。
- 去几x文件判断的是dpi最大值与上一个最大值的区间,320,480,640对应从小到大三类x右侧闭区间。
- 安卓默认的分辨率对应dpi: 听说你还在用dp做屏幕适配?
- 所以会有x 720,xx 1080,xxx 2k的说法。
- 标准屏 iphone 6为界:375x667
- 360x800也是蛮常见的
2、动态设置View的高度和宽度,ViewTreeObserver使用
3、 Android ViewTreeObserver 原理详解
4、获取View的位置
5、descendantFocusability:控制父/子布局获得焦点 descendantFocusability属性的简介和用处
6、一些点击事件防穿透可以使用这个
android:clickable="true"
android:focusable="true"
7、子布局可越界:android:clipChildren="false"
- 用法是这样的,只写一个就行了,写的位置和第一个父布局关系不大,关键在于想在那个模块里显示出来,在顶层的那个模块中写一个就行
9、include
mBindView.includeAdd.root.showOrHide(list.isEmpty())
这个root还蛮关键的,对include,点击事件与可见都要用这个
10、raw和Asset轻读一下 Android 应用开发中的 assets 目录
二、 ImageView
1、src的执行时机在onbackgroud后: 彻底记住ImageView的background和src的区别
2、新的圆角图片方式(见Cons中)
8、Android:screenOrientation属性
- unspecified,默认值,由系统决定,不同手机可能不一致
- landscape,强制横屏显示
- portrait,强制竖屏显示
- sensor,根据物理传感器方向转动,用户90度、180度、270度旋转手机方向,activity都更着变化
9、格式
- android:scaleType="centerCrop"
以填满整个ImageView为目的,将原图的中心对准ImageView的中心,等比例放大原图,直到填满ImageView为止(指的是ImageView的宽和高都要填满),原图超过ImageView的部分作裁剪处理。
- android:scaleType="fitXY"
把原图按照指定的大小在View中显示,拉伸显示图片,不保持原比例,填满ImageView.
- fitCenter:
把图片按比例扩大/缩小到View的宽度,居中显示
三、 ConstraintLayout
基本思想:某个控件的某处关于某个对象的某处对齐
1、基本模块:史上最全ConstraintLayout使用详解
- 百分比偏移:bias
- 链式,常用的packed:chainStyle
- packed模式如果设置两个共同居中,若隐藏其中一个,另外一个会自动居中
- 参考线:Guideline
- 分组:Group与app:constraint_referenced_ids:
- 圆角图片:ImageFilterButton和ImageFilterView
- roundPercent接受的值类型是0-1的小数
- round=可以设置具体圆角的大小
- altSrc来设置第二个图片资源
- crossfade设置堆叠效果
2、 宽高比:Android中使控件保持固定宽高比的几种方式
- 父布局为Cons;
- 样例:需要计算高,dp_0;宽比高为3:4;
<androidx.appcompat.widget.AppCompatImageView
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintDimensionRatio="h,3:4"
android:id="@+id/cover"
app:layout_constraintTop_toTopOf="parent"
android:layout_width="match_parent"
android:layout_height="@dimen/dp_0"
android:background="@drawable/ic_cover_album"
android:scaleType="centerCrop" />
3、 实现权重
- 使用属性:app:layout_constraintHorizontal_weight="x" (以宽为例)
- 确立view间上下(对应height=0dp)/左右(weight="0dp")联动关系即可。
4、 改变约束关系
- 代码中使用updateLayoutParams改变布局及相关参数:约束布局(ConstraintLayout)的一些技巧
- 指定16:9视频宽拉伸,长度自适应:
view.updateLayoutParams<ConstraintLayout.LayoutParams> { height = 0 dimensionRatio = "h,9:16" }
- 代码中使用:ConstraintLayout.LayoutParams.UNSET 可以清除约束关系
5、 与其他View的联动
- ConsttratLayou中用0dp拉升后,maxwidth就无效了
- ScrollView
-
ConstraintLayout 布局中有ScrollView 时,ScrollView 的宽高要设置为0dp 才可以正确的约束布局;
-
配合使用:生效的 ,自动往外拓12dp
android:layout_height="wrap_content"
android:paddingBottom="12dp"
6、 动态调整宽高:
val viewWidth = if (toastState == STORAGE_LESS) R.dimen.dp_349 else R.dimen.dp_343
控件名.apply {
val lp = layoutParams
lp.width = resources.getDimensionPixelSize(viewWidth)
lp.setMargins(0, 0, 0, 1800)
layoutParams = lp
}
- padding是view内部的属性,可以直接调整;margin是layoutParams与外界关系的属性;
- 写法二:
//方式二直接通过getLayoutParams获取属性修改
button.getLayoutParams().width=250
button.getLayoutParams().height = 250
7、常见设置
-
左对齐不管是根据左边控件的左边还是右边,左边隐藏了,一律会变成ss这种;左边控件原本的padding不会继承(合理),margin也不会被右边控件继承(挺好的)
-
虽然控件左边的为Gone,但本身左边的margin仍然保留,这个时候可以用
app:layout_goneMarginStart="xdp"相对控件隐藏时控制间距
- app:flow_wrapMode="chain" 好东西,自动换行
- 实现竖排很横排的方式没,在2.0.4版本加入
9、ConstraintLayout不支持-margin的替代方案
- 使用
Guideline
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_begin="50dp" />
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button"
app:layout_constraintTop_toBottomOf="@id/guideline"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
- 使用对子view使用偏移属性translationY
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button"
android:translationY="-50dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
10、切正式环境后,显示Log
四、 ScrollView
1、 只能有一个子View
五、 FloatingActionButton基本使用及踩坑记录
1、图标尺寸
1、floatingactionbutton src图标不居中解决_weixin_41650019的博客-CSDN博客
- app:fabCustomSize=“50dp” 实测有效 2、app:maxImageSize 的属性即可直接设置图标大小了,不需要android:scaleType【实测会偏大】
六、 RecycleView
2、 RecyclerView滚动条_recyclerview 滚动条
3、 添加分割线
六、Plus 滑动冲突
1、CoordinatorLayout和RecyclerView嵌套滑动冲突解决
- isNestedScrollingEnabled 有些时候Refreshu嵌在里面监听发现是Recycleview处理的,但UI不生效,用这个试试。
3、Android中的dispatchTouchEvent()、onInterceptTouchEvent()和onTouchEvent()
七、ProgressBar(进度条)和SeekBar(拖动条)
1、Android之ProgressBar(进度条)和SeekBar(拖动条
八、Navgation与侧滑DrawerLayout
1、基本使用解说
- 选中样式:样式
- 详解:DrawerLayout 侧滑栏
九、ToolBar
1、基本使用:细节解说
十、popWindow
十一、Tablayout
1、Android TabLayout 优雅设置调整指示线tabIndicator 圆角样式和宽度_tablayout tabindicator写法
- 这种方式颜色不会生效,需要再设定:app:tabIndicatorColor="#008AFF"
十二、Spinner
- 列选择器
十三、OpenGL
- 3D图像函数库
十四、RadioButton
十五、SeekBar
十六、TextClock
- 好东西,小组件连ConstraintLayout都不支持,竟然支持这个
- Android数字时钟神一般的实现——TextClock_textclock
十七、RemoteViews
- 蛮常见的,小组件经常会用到,Notification可能会用到
- 这个View不支持Databinding和ConstraintLayout
- 在代码中,无法使用FindViewByID,可以用类似setTextViewText这种
- 不支持设置background
- 不支持设置Tint
十八、下拉控件Spinner
二:生命周期
1、Android 的singleTask和singleInstance的一点思考
- 四种启动模式的特征,onNewIntent会在复用的时候调用。
- 关于SingleTask如果设置给最初的入口Activity
- 如果在当前页按Home键回到桌面再点击APP回来,会优先把栈里的Activity拉起入口Activity,就算被销毁了也会拉起来(销毁拉起来之后不会清除中间的Activity)
- (尽量不要在你的入动(ACTION_MAIN和CATEGORY_LAUNCHER)上使用singleTask,以防其用户点击启动器将你的应用程序带到前台时,在同一taskAffinity中被Android销毁)
- 如果在
MainActivity已经存在于任务栈中时启动,MainActivity会被复用,而位于其之上的其他 Activity 会被清除。 - 如果按任务栏再点击应用会先执行当前页面的onStoped,然后正常onresume,因为没触发App点击图标
- 如果是singleInstance,不会原本有没有销毁,走APP图标都会把其他的Activity弹出,只剩入口Activity
- 关于跳Activity清除中间Activity的方法
Intent intent = new Intent(this, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
2、 通俗易懂:Handler后传篇一: 为什么Looper中的Loop()方法不能导致主线程卡死?
- 常规死循环不会导致anr,anr的原因是死循环后其他需要分发的时间超过了规定时间5s。
- Handler死循环中有个判断,如果消息为空会return,阻塞状态。不会分发,取到消息队列后才处理分发。
3、 Android源码—为什么onResume方法中不可以获取View宽高
- 一般获取宽高会发现都是0,加个view.post就好了(ps这里面是异步的)。postDelay同理,后面的代码也会先执行;
- 文章中说明了oncreate setContentView属于解析xml,执行完Activity的
onResume后调用了wm.addView(decor, l)。
4、 Android 启动模式FLAG_ACTIVITY_CLEAR_TOP
- Intent.FLAG_ACTIVITY_CLEAR_TOP 挺好用的:销毁目标Activity和它之上的所有Activity,重新创建目标Activity。
5、如何在一个Activity里销毁另外一个Activity
- 伴生对象 -> init -> 主构造函数 -> 次构造函数
- 反编译可以看到效果,PS,Java代码转kotlin,构造函数的方法会默认转进init
8、view的contex一般都是Activity;
9、关于Activity和Fragment的销毁
-
Fragment【存在自身和UI双重生命周期】
super.onDestroyView()前:保存状态、停任务super.onDestroyView()后:清 UI 引用、解绑 listener
-
Activity
- 所有清理都在
super.onDestroy()前做,最后再调用super.onDestroy()
- 所有清理都在
四:四大组件
Activity、Service、Broadcase receiver、Content provider
一、Activity
- 基础的就不写了 把一些通用的放这里吧
1、Fragment 片段
2、不要直接用构造方法传值(DialogFragment在系统切权限后如果有构造方法会闪退)
- 解法1:单例类存储
- 解法2: Viewmodel
2、Intent
1、普通使用
1、装载使用:Android中Bundle传递数据和对象_android bundle传递对象
- 好处:若有多个Intent装载相同的参数时2,bundle相当于把其抽出装载;
- intent可以通过传每个intent一直传递activity,bundle也行;
2、PendingIntent
1、PendingIntent理解_者文的博客-CSDN博客
- 将某个动作的触发时机交给其他应用或某个View
- PendingIntent的使用场景主要用于闹钟、通知、桌面部件
二、Service
1、 Service生命周期总结 | HurryYu
1、启动方式
1、startService【持久后台运行之一】:startService(new Intent(this, MyService.class))
- 生命周期
- 第一次调用startService时,onCreate与OnStartCommand都会被执行;
- 再继续调用startService方法,只有onStartCommand会被执行(service是单例,重复调用没关系)
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
return START_STICKY
}
-
START_STICKY:如果服务被系统在 onStartCommand() 返回后杀死,系统将重新创建服务并调用 onStartCommand(),但不会重新传递最后的意图。相反,系统会用一个空的意图调用它,除非有挂起的意图启动服务。
-
START_NOT_STICKY:如果服务在 onStartCommand() 返回后被系统杀死,则系统不会重新创建服务,除非有新的明确的服务启动请求
-
该启动方式,
app杀死、Activity销毁没有任何影响,服务不会停止销毁; -
stopService(intent);可按需放在Activity的onDestory中,调用这个就能销毁;
2、bindService【通过Binder控制Service服务】: public boolean bindService(Intent, ServiceConnection, int)
- 参数说明:第二参需要传一个监听器(成功连接/断开连接),第三个参数是一个int类型的参数,表示绑定服务的操作选项(一般传入BIND_AUTO_CREATE 自动创建service)
- 生命周期:
- 多次调用,第一次onCreate和onBind执行,后续俩都不执行,且不会回调onServiceConnected;
- 在Activity的onDestroy生命周期方法中,仍然需要调用unbindService,不然会ServiceConnectionLeaked Crash(必须调用且只能调一次);
- 客户端
Activity销毁时, 没有调用unbindService()方法 ,Service也会停止销毁; - onBind方法中返回一个IBinder接口的实现,而Binder类实现了IBinder接口,因此,我们可以继承Binder类,在类中提供Service与外界的交互方法即可回调onServiceConnected;
2、 两种方式混合启动【持久化控制Servie服务】
1、混合启动的合理性:startService开启后与调用者毫无关联,不会随着调用者的销毁而销毁。bindService可以与调用者绑定实现一些交互,但是与调用者共生死,混合启动可以做到既能提供与调用者的交互,又不会与调用者一起销毁;
2、调用顺序:会影响生命周期:看完这篇Service你还不会,来找我 - 掘金 (juejin.cn)
2、线程说明:
- 一个服务(service)运行在 主线程中,服务并不创建自己的线程,也不在隔离进程中运行(除非你指定)。 这意味着,如果你的服务要执行CPU费时操作或阻塞操作,你需要在服务中创建新的线程来执行该操作;
3、前台服务
1、Android startService和bindService混合使用、以及前台服务;_bindservice转换成前台服务
三、Broadcase receiver 广播
1、只在本页面执行的话就在start()和stop()进行注册和销毁【对应,如果重复注册会crash】 2、如果想在后续页面收到的话就在oncreate()和ondestory()进行注册和销毁,设置为主线程的话,activity只要在栈里没销毁,就能更新UI,
四、Content provider
五、上架相关
六、异常处理
七、概念定义
1、 重写与重载
- 覆写/重写:方法名字/参数相同,方法内容不同
- 重载:名字相同,参数个数和类型不同
2、并发与并行
- 并发:一个处理器同时处理多个任务;逻辑上同时发生;
- 并行:多个处理器或多核处理器同时处理多个任务;物理上同时发生;
3、关于boolean类型命名 有些框架序列化方法会自动生成is;话说接口里好像一般用0,1;自己写的方法名有is没关系;
八:系统级
SDK 平台版本说明 | Android 开发者 | Android Developers
- Android 13-API 33
- Android 9-API 28
- Android 7.0-API 24
一、清单文件
1、configChanges属性
2、sharedUserId
一般每个apk都具有一个userid,Android会根据userid来给它分配一个Linux用户ID进行管理,并为之创建一个独立沙箱;相同的sharedUserId可以进行资源共享。
3、Android Gradle manifestPlaceholders 的妙用
- build配置进manifestPlaceholders
4、明文,密文
- Android P使用明文明文/密文拓展阅读
- 配置清单文件那个最暴力好用,实测,Android 12也ok
1、关于android:sharedUserId=“android.uid.system“ 的使用
- 声明为系统进程级,享有控制系统权限。
- 所用的硬件厂商签名
5、获取App标识包名applicationId
1、Android查看包名和获取包名获取包名_吴庆森的博客-CSDN博客
二、权限
1、Android权限列表permission说明:www.cnblogs.com/jxldjsn/p/6…
2、补充说明
三、 跳转
1、 Kotlin 实现Activity之间的跳转
- 包含应用内核应用外
- startActivity(Intent(this@MainActivity, TestActivity::class.java))
- kotlin写法:this@MainActivity
- Java写法:MainActivity.this
2、通过文件唤起应用:
1、参考:android 多媒体文件关联之MIME TYPE_android unsupported mime type audio/*_
四、软键盘: InputMethodManager
1、 软键盘api:Android-软键盘一招搞定(实践篇)
2、 监听状态:Android 监听键盘弹出收起
五、进程保活与杀死
1、进程保活
2、杀死进程
1、结束当前进程:android.os.Process.killProcess(android.os.Process.myPid());
- 一般Servie运行在当前进程的主线程中
2、退出Java虚拟机:System.exit(0)
- 0表示正常退出,1是异常退出
- 退出虚拟机了,程序运行环境没了,软件也退出了。
六、 app图标控制
1、Android应用图标微技巧,8.0系统中应用图标的适配_guolin的博客-CSDN博客
七、ABI
Application Binary Interface,应用二进制接口:为何大厂APP如微信、支付宝、淘宝、手Q等只适配了armeabi-v7a/armeabi?
1、 想使用native(C/C++) 类库,必须对要支持的处理器架构提供对应编译包。每个处理器架构需要我们提供一个或多个包含native代码的.so文件(支持后会有个文件夹,里面存放多个so库文件)
1、build.gradle里经常能看到适配这些,例如bugly。安卓当前支持七种ABIs
- mips, mips64, X86, X86–64, arm64-v8a, armeabi, armeabi-v7a
- 用户可能只需要一种,但代码中写了多少,打包的时候就会打多少,体积浪费;
- Google支持传多种架构包,支持每个系统下对应的,国内的就一般了。
八、微信小程序APP拉起小程序功能 / 功能介绍
九、Google安装器
十、Android之防截屏
- 通过window.setFlag即可实现。
- 其两个参数设置的值都是一样的,内部是二进制移位操作,嗯,,比较深
十一、Release调试
1、抓包配置文件
2、打开日志Log:清单文件里 buildtype中release配置:debuggable true
十二、签名
apksigner | Android 开发者
1、工具位置

2、语法
- 普通签名相关:
--ks选项指定密钥库文件(.jks)--key可以指定私钥(.pk8)--cert可以指定证书文件(.x509.pem)
- 轮替签名:支持新的签名文件轮替;
3、通常情况,您只会使用一个 signer 为 APK 签名。如果您需要使用多个 signer 为 APK 签名,请使用 --next-signer 选项将要应用于每个 signer 的常规选项集分隔开
十三、注解
十四、远程连接控制Android
1、桌面程序
1、Scrcpy工具:adb连接或电脑获取屏幕显示
- 通过ip连接设备并唤起系统桌面,并非针对单一App;
2、网页控制
1、DeviceFarmer
1、 git及安装说明:DeviceFarmer/stf: Control and manage Android devices from your browser. (github.com)
- 接入文章参考1[Linux]:搭建设备管理平台-STF(Device Farmer)
- 参考2[mac]:基于 STF 的 iOS 远程真机控制,踩坑经验分享
2、ya-webadb/Tango
1、演示文档:探戈 (ya-webadb.vercel.app)
- 基于Scrcpy实现;
- 数据线可以直接连接查看;
- 使用无线需要额外的软件来桥接连接(暂不明)
2、git:yume-chan/ya-webadb: ADB in your browser (github.com)
十五、热修复
1、热修复初探
- 两种原理
- 目的:下发热补丁包修复bug;
2、实践参考:Android热修复—阿里的新一代热修复技术Sophix