Bitmap源码解析与抛弃google提供的压缩算法
Android程序员如何切合移动互联网的“星辰和荆棘”
http://ddrv.cn/a/213673
Bitmap图片压缩,大图加载防止OOM
https://dandanlove.blog.csdn.net/article/details/105677102
史上最全!押题率90%的 Android 中高级工程师面试复习大纲及真题答案整理(中篇)
https://www.it610.com/article/1344194310530215936.htm
RGB介绍
Bitmap压缩
inSampleSize BitmapFactory.Options
Bitmap局部解码
为了防止加载 Bitmap 的时候造成 OOM 崩溃,我们首选要知道:
一张图片加载到 Bitmap 的时候的占用的是怎么内存计算;
占用内存过高的时候怎么进行图片压缩减小内存占用;
Bitmap OOM RGB介绍 RGB介绍
RGB8位
ALPHA_8–每个像素占1个字节,存储透明度信息,没有颜色信息。
RGB_565–每个像素占2个字节存储颜色信息,R
ARGB_8888 透明度
图片占用内存的计算
图片占用内存的计算
34
Bitmap BitmapFactory.decodeFile
Bitmap 所占内存大小计算方式:图片长度 x 图片宽度 x 一个像素点占用的字节数。
45
decodeByteArray
OutOfMemory()
decodeByteArray
decodeResource decodeFile
BitmapFactory.Options
inJustDecodeBounds = true
outMimeType
读取位图尺寸和类型
java.lang.OutOfMemory
内存中如果加载一张 500*500 的 png 高清图片.应该是占用多少的内存?
png 图片应该有alpha通道,所以 Bitmap.Config 是 ARGB_8888 。4个8位一种占用32位。
最终答案: 500 * 500 * 4 = 1000000Bytes = 0.95MB
Bitmap.Config = ARGB_8888
0.95MB
像素密度
,Android 系统必须缩放位图,使其在每个屏幕上占据相同的可见空间,从而导致缩放失真,如模糊。
Android使edittext弹出的软键盘位于输入框下面而不是覆盖输入框
https://blog.csdn.net/qq_36982160/article/details/82802152
提供三个方法:
1:在你的activity中的oncreate中setContentView之前写上这个代码
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
1
1
2:在项目的AndroidManifest.xml文件中界面对应的里加入:
android:windowSoftInputMode="stateVisible|adjustResize" //这样会让屏幕整体上移android:windowSoftInputMode="adjustPan" //这样键盘会覆盖屏幕
1
1
3:把顶级的layout替换成ScrollView,或者说在顶级的Layout上面再加一层ScrollView的封装。这样就会把软键盘和输入框一起滚动了,软键盘会一直处于底部。
getWindow.setSoftInputMode .LayoutParams.SOFT_INPUT_ADJUST_PAN
android:windowSoftInputMode SOFT_INPUT_ADJUST_PAN
23个密度级别提供一个版本
MDPI HDPI ldpi mdpi hdpi xhdpi xxhdpi
像素密度
@drawable/xxx时,系统都会根据屏幕的 dpi 选择适当的位图。如果您没有为某个密度提供特定于密度的资源,那么系统会选取下一个最佳匹配项并对其进行缩放以适合屏幕。
实测:1520 x 2688 大小为 334.28KB 图片,屏幕密度为480的手机;
放在 drawable-xxdpi 下加载到 Bitmap 中占用内存为 16343040(1520*2688*4),因为图片不需要进行缩放,所以只需要计算 ARGB_8888 占用的字节数就行;
放在 drawable-mdpi 下加载到 Bitmap 中占用内存为 147087360(1520*3*2688*3*4) ,因为 mdip 到 xxdpi 图片的宽高分别会放大4倍;
nodpi 目录中的资源被视为与密度无关,系统将不会对它们进行缩放。
android 获取ListView的Item中多个Edittext的输入值
https://blog.csdn.net/k571039838k/article/details/92086459
34
1520 x 2688 drawable-mdpi ARGB_888888
因为 mdip 到 xxdpi 图片的宽高分别会放大4倍;
nodpi
Bitmap压缩
压缩原理
其一是下 采样压缩,其二是 质量压缩。 Bitmap
压缩Bitmap磁盘占用空间的大小
CompressFormat.WEBP
压缩Bitmap磁盘占用空间的大小 -写文件
压缩Bitmap占用内存的大小 -运行时
78尺寸的修改其实就是通过修改像素数,放大的过程称之为上采样,缩小的过程称之为下采样。
Bitmap inSampleSize inSampleSize
inSampleSize
您愿意分配用于加载此图片的内存量。//34
位图配置为=ARGB_8888
下面的方法用于计算样本大小值,即基于目标宽度和高度的 2 的幂:
inJustDecodeBounds = true
decodeSampledBitmapFromResource
options.inJustDecodeBounds = true
calculateInSampleSize options,reqWidth,reqHeight
Nearest Neighbour Resampling
45
createScaledBitmap Matrix
双线性采样 Bilinear Resampling
双线性采样 邻近采样算法
BitmapFactory.Options三件套
BitmapFactory.Options
inScaled inDensity inTargetDensity
BitmapFactory.Options三件套
inScaled inDensity inTargetDensity
加载到堆内存时已经缩放了大小了
inDensity (inTargetDensity)
inTargetDensity:目标图片的显示宽度
drawable-dpi
Bitmap局部解码
Bitmap BitmapRegionDecoder.newInstance encodeRegion
inPreferredConfig = sOptions
encodeRegion Bitmap.Config.ARGB_8888
mRegionDecoder.mRegionDecoder.decodeRegion Rect,sOptions
如何看待Android的Jetpack这一系列库?
https://www.zhihu.com/question/302221538/answer/915248040
Lifecycle入坑指南v LiveData/Room/ViewModel这些去年推出的优秀第一方组件,你也应该使用,这些也在JetPack里。
ViewModel、Room等组件早在
Room入坑详解
Activity
Foundation、Architecture、Behavior和UI。 Behavior和UI。
Foundation、Architecture、Behavior和UI。
Multidex记录一:介绍和使用
45
Security
Data Binding Lifecycles:LiveData
Paging:Room ViewModel(ViewModel)
WorkManager:()
WorkManager:
即使应用程序退出或设备重新启动,也可以轻松地调度预期将要运行的可延迟异步任务。
LiveData是 Repository
Behavior CameraX:
DownloadManager
Notifications Wear Auto。
Permissions
Preferences Sharing Slices
2.4、UI(界面组件):Ani
Animation & Transitions
Palette(23)
allprojects repositories {
}
implementation
android.arch.lifecycle.runtime lifecycle_version
common-java8 compiler
Architecture 相关组件的使用
Architecture
Android Jetpack架构组件 — Lifecycle入坑指南
https://mp.weixin.qq.com/s/pCljPZEApHTC70dclkKVIw
Lifecycle管理生命周期也是观察者模式,其中主要涉及到以下几个类:
LifecycleObserver、LifecycleOwner、
Lifecycle、LifecycleRegistry、State、Event。
LifecycleObserver、LifecycleOwner、
Lifecycle
Event枚举:
State Event
public enum Event {
ON_CREATE,
ON_START,
ON_RESUME,
ON_PAUSE,
ON_STOP,
ON_DESTROY,
ON_ANY
}
State、Event。
DESTROYED
public enum State {
DESTROYED,
INITIALIZED,
CREATED,
STARTED,
RESUMED;
public boolean isAtLeast(@NonNull State state) {
return compareTo(state) >= 0;
}
}
onSaveInstance
States Event
compiler common-java8 reactivestreams
34
MyObserver exceeds LifecycleObserver
onResume
OnLifecycleEvent Lifecycle.Event
lifecycle.addObserver MyObserver
Observer
Event44
本文主要是介绍了Lifecycle相关的API以及简单的使用。
在实际项目中还是要结合ViewModel和LiveData来使用。通过ViewModel来获取所需数据,
并通过观察LiveData对象将数据变化反映到视图中。
Lifecycle ViewModel LiveData
ViewModel来获取所需数据,并通过观察LiveData对象将数据变化反映到视图中。
Jetpack架构组件 — LiveData与ViewModel入坑详解
https://mp.weixin.qq.com/s/EbE8JcY3o5ftiDbCal5VzQ
EventBus
LiveData Activity Fragment
ViewModel
ViewModel将视图和逻辑进行了分离ViewModel
Activity onCreate (onResume)
Scope onClear
MutableLiveData
postValue
ViewModel UI LiveData
val secondViewModel = ViewModelProviders.of(this).get(SecondViewModel::class.java)
ViewModelProviders.of this
.observe.userData(Observer)
这里通过ViewModelProviders来获取ViewModelProvider在通过get方法来获取ViewModel实例。
ViewModelProviders
数据转换
如果我们想对从服务端获取到的数据进行修改可以使用Transformations操作符。分为Map和switchMap两种。switchMap需要返回一个LiveData对象。
Transformations.map
.observe(this,Observer)
Transformations.switchMap
switchMapData.value
MediatorLiveData
多个数据源 -多个observe
MutableLiveData
MediatorLiveData
.addSource
mediatorLiveData.value = info
MutableLiveData
secondViewModel.mediatorLiveData.observe this,Observer
onChanged(23)
postValue onChanged
postValue执行完成后onChanged方法将接受到回调并通知UI更新数据。
上文也34onChanged是监听data1和data2数据变化的
data1.postValue()
postValue执行完成后onChanged方法将接受到回调并通知UI更新数据。
扩展LiveData active 45
activiry_second
LiveData<BigDecimal>()
onActive方法被调用说明现在有活动着的观察者,所以添加监听以进行数据的更新。onInactive方法被调用说明没有活动的观察者所以要移除监听。
Android Jetpack架构组件 — Room入坑详解
https://mp.weixin.qq.com/s/Az6ckdXhI75j05Q6ZYGh-A
Room
room-runtime
room-compiler kapt annotationProcessor
@Database
RoomDatabase @Dao
@Dao。
public @abstract
Data Access Objects
Get Entity from db
Persist changes back to db
@Entity tableName
PrimaryKey ColumnInfo name = autoGenerate = true
Ignore ignoredColumns 参数来指定,效果是一样的。 ignoredColumns = true
Entity注解:
Entity
@Target ElementType.TYPE
RetentionPolicy.CLASS
Entity primaryKeys ignoredColumns indices tableName
PrimaryKey注解:
@Target({ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.CLASS)
public @interface PrimaryKey {
boolean autoGenerate() default false;
}
ColumnInfo注解:
Target ElementType = FIELD,METHOD
SQLiteTypeAffinity
default
IntDef BLOB REAL
NOCASE
UNSPECIFIED,BinaryTree
BINARY
Ignore注解:
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.CONSTRUCTOR})
@Retention(RetentionPolicy.CLASS)
public @interface Ignore {
}
Ignore
45
@Insert onConflict =
OnConflictStrategy.REPLACE
@Delete
@Update updateUserByUser
@Query("delete from user where userId = :id ")
fun deleteUserById(id:Long)
Query delete deleteUserById
update user
Database
首先定义一个抽象类继承RoomDatabase类,并添加注解 @Database 来标识:
Database RoomDatabase
abstract fun
companion object {
}
.databaseBuilder
.allowMainThreadQueries
Room.dataBaseBuilder
.allowMainThreadQueries
使用entities来映射相关的实体类,version来指明当前数据库的版本号
.allowMainThreadQueries
AppDatabase.getInstance this.userDao
生成的数据库在data/data/packageName/databases 目录中。
data/data/packageName/databases 目录中。