Android 启动模式
1/standard: 标准模式
特点: 无论栈内是否存在, 都会重新创建一个新的 Activity
使用场景: 详情页面
2/singleTop: 栈顶复用模式
特点: 如果栈顶存在就复用, 否则就重新创建
使用场景: 消息推送页面, 详情页面
3/singleTask: 栈内复用模式
特点: 如果栈内存在就复用, 并清理掉之上的所有页面
使用场景: app 主页
4/singleInstance: 单实例模式
特点: 当前模式创建的页面会存放在单独的栈内, 创建时会寻找是否存在单纯的栈并且目标在栈内, 存在就复用, 不存在就创建一个新的栈和新的页面, 并将页面放至新的栈内
使用场景: 这个经常使用于系统中的应用,比如Launch、锁屏键的应用等等,整个系统中仅仅有一个!所以在我们的应用中一般不会用到。了解就可以。
5/复用 Activity 关键点
singleTop/singleTask/singleInstance
模式下复用 Activity 时, 被复用的 Activity 会先调用 onNewIntent
方法, 此方法有一个需要注意的地方就是调用 setIntent()
方法更新 intent
, 否则 getIntent()
获取到的就是旧的.
屏幕适配
1/使得布局元素自适应屏幕尺寸
在常用的布局中尽量使用 wrap_content/match_parent
还有”线性布局”和”约束布局”里的”权重”.
尽量使用”约束布局”来优化减少布局层级
2/根据屏幕的配置来加载相应的UI布局
使用限定符来辅助适配.
限定符类型: 尺寸限定符/最小宽度限定符/布局别名/屏幕方向限定符
常用方式: 尺寸限定符/最小宽度限定符
- 尺寸限定符: 根据目标硬件的具体尺寸匹配
res/**-高度x宽度
, 对于没有匹配到的会使用默认的文件 , 所需匹配文件相对较多 最小宽度限定符: 根据目标硬件的对应的最大宽度 dp 匹配
res/**-sw最大宽度dp
, 对于没有匹配到的会就近向下匹配 , 所需匹配文件相对较少3/关于图片适配
Android SDK会根据屏幕密度自动选择对应的资源文件进行渲染加载(自动渲染)
假设你只在xhpdi文件夹下有对应的图片资源文件(mdpi文件夹是空的),那么SDK会去xhpdi文件夹找到相应的图片资源文件,然后将原有大像素的图片自动缩放成小像素的图片,于是大像素的图片照样可以在小像素分辨率的手机上正常显示。
所以理论上来说只需要提供一种分辨率规格的图片资源就可以了, 根据市场统计 xhdpi 应该是首选.4/主流屏幕适配框架(AndroidAutoSize)
原理: 主要是通过替换 DisplayMetrics 类中的三个主管缩放的属性, 来匹配设计稿的设计尺寸.
density
: 逻辑密度densityDpi
: 每英寸的屏幕密度scaledDensity
: 字体的缩放密度
三者通常都是相同的. AAS 框架主要就是通过计算和修改这三个参数来进行屏幕适配.
优点:
- 使用成本非常低,操作非常简单
- 侵入性非常低,该方案和项目完全解耦
- 可适配三方库的控件和系统的控件
缺点:
- 这个方案依赖于设计图尺寸,但是项目中的系统控件、三方库控件、等非我们项目自身设计的控件,它们的设计图尺寸并不会和我们项目自身的设计图尺寸一样
5/参考
https://blog.csdn.net/u010349644/article/details/83619912
Android 消息机制
Android 消息机制涉及的类包含 Handler/Message/MessageQueue/Looper/ThreadLocal
Handler 关联 Message 和 MessageQueue, 通过 Handler 将 Message 发送到 MessageQueue, 由 MessageQueue 进行排序管理, 后由 looper 轮询从 MessageQueue 处获取 Message. looper 的获取跟 ThreadLocal 关联, ThreadLocal 会为每个线程创建 map 用来进行线程间数据隔离, 获取 looper 的时候通过 ThreadLocal 判断所在线程, 获取所在线程的 looper.
Android 消息机制关联的四大概念:
- ThreadLocal
- MessageQueue
- Looper
- Handler
1/ThreadLocal
作用: 线程间数据隔离, ThreadLocal 中存储的数据只能在当前线程中获取
使用示例: ```java import java.util.concurrent.atomic.AtomicInteger;
public class ThreadId { // Atomic integer containing the next thread ID to be assigned private static final AtomicInteger nextId = new AtomicInteger(0);
// Thread local variable containing each thread's ID
private static final ThreadLocal<Integer> threadId =
new ThreadLocal<Integer>() {
@Override protected Integer initialValue() {
return nextId.getAndIncrement();
}
};
// Returns the current thread's unique ID, assigning it if necessary
public static int get() {
return threadId.get();
}
}
关键方法:
- set/get: 设置/获取
- initialValue: 设置默认值
- remove: 清空本地存储
<a name="PpmRP"></a>
### 2/MessageQueue
作用: 用来管理 Message, Message 之间是单链表结构存储的<br />关键方法:
- next: 取出 message 链表的下一个值
- quit: 退出, 销毁消息链表
- enqueueMessage: 排序插入 message 到链表
- remove**: 从消息链表中删除 message
<a name="hzZqr"></a>
### 3/Looper
作用: 用于通过 MessageQueue 循环获取 Message, 通过 Message.target.dispatchMessage 回调, 将 Message 交于 Handler 处理. _**Looper会在没有消息的时候阻塞当前线程,释放CPU资源,等到有消息到来的时候,再唤醒主线程**_<br />使用示例:
```java
class LooperThread extends Thread {
public Handler mHandler;
public void run() {
Looper.prepare();
mHandler = new Handler() {
public void handleMessage(Message msg) {
// process incoming messages here
}
};
Looper.loop();
}
}
关键方法:
- prepare: 初始化方法, 创建一个 looper, 并将 looper 与所在线程通过 ThreadLocal 关联起来
-
4/Handler
作用: 发送/接收处理 Message
使用示例:class TestActivity extends AppCompatActivity {
public Handler mHandler;
public void xxx() {
mHandler = new Handler() {
public void handleMessage(Message msg) {
// process incoming messages here
}
};
}
}
关键方法:
obtainMessage: 创建 Message
- sendXXX: 发送 Message
5/Handler 如何处理线程切换的?
handler 创建于子线程之外, 属于共享变量, handler 可在子线程里发送消息, 在 looper 的 loop 方法里将 message 分发给 handler 的 handleMessage 方法. 由于 handleMessage 方法在主线程内, 所以就自然完成了子线程到主线程的线程切换.Bitmap
1/内存计算方式
Android 中的图片会根据屏幕密度对图片进行对应的缩放, 相同的图片在 res 中不同的 dpi 文件夹中被加载到内存后所占的大小都不相同. 关键在于计算出图片在 Android 中进行缩放后的实际加载尺寸和加载图片所用的格式.
像素点大小:
常见的像素点有
- ARGB_8888:4个字节
- ARGB_4444、ARGB_565:2个字节
资源文件位置:
不同dpi对应存放的文件夹
实际尺寸计算方式:
横向像素点 = 图片宽度 (设备独立像素密度/对应 dpi 文件夹的最大值) + 0.5f
纵向像素点 = 图片高度 (设备独立像素密度/对应 dpi 文件夹的最大值) + 0.5f
内存大小 = 横向像素点 纵向像素点 像素点所占大小
2/图片压缩方式
2.1/质量压缩
特点: 质量压缩不会减少图片的像素,它是在保持像素的前提下改变图片的位深及透明度等,来达到压缩图片的目的,这也是为什么该方法叫质量压缩方法。那么,图片的长,宽,像素都不变,那么bitmap所占内存大小是不会变的。
/**
* 质量压缩方法
* @param image
* @return
*/
public static Bitmap compressQuality(Bitmap image) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
// 质量压缩方法,这里100表示不压缩,把压缩后的数据存放到baos中
image.compress(Bitmap.CompressFormat.JPEG, 100, baos);
int quality = 90;
// 循环判断如果压缩后图片是否大于100kb,大于继续压缩
while (baos.toByteArray().length / 1024 > 100) {
// 重置baos即清空baos
baos.reset();
// 这里压缩options%,把压缩后的数据存放到baos中
image.compress(Bitmap.CompressFormat.JPEG, quality, baos);
// 每次都减少10
quality -= 10;
}
image.recycle();
// 把压缩后的数据baos存放到ByteArrayInputStream中
ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());
// 把ByteArrayInputStream数据生成图片
Bitmap bitmap = BitmapFactory.decodeStream(isBm, null, null);
return bitmap;
}
2.2/采样率压缩
特点: 采样率压缩是改变了图片的像素,他是通过先读取图片的边,然后在自己设定图片的边,然后根据设定,读取图片的像素。在读取的时候,并不是所有的像素都读取,而是由选择的。所以这种方式减少了像素的个数,能改变图片在内存中的占用大小。
/**
* 采样率压缩
*/
public void compressInSampleSize() {
BitmapFactory.Options options = new BitmapFactory.Options();
// 根据实际宽高计算出的采样率, 一般为 2 的次幂
options.inSampleSize = 2;
Bitmap bm = BitmapFactory.decodeFile("文件 path", options);
}
2.3/缩放压缩
特点: 将 bitmap 通过 Matrix 设置缩放参数, 之后进行缩放
Matrix matrix = new Matrix();
matrix.setScale(0.5f, 0.5f);
bm = Bitmap.createBitmap(bit, 0, 0, bit.getWidth(),
bit.getHeight(), matrix, true);
Log.i("wechat", "压缩后图片的大小" + (bm.getByteCount() / 1024 / 1024)
+ "M宽度为" + bm.getWidth() + "高度为" + bm.getHeight());
2.4/RGB 压缩
BitmapFactory.Options options2 = new BitmapFactory.Options();
options2.inPreferredConfig = Bitmap.Config.RGB_565;
bm = BitmapFactory.decodeFile(Environment
.getExternalStorageDirectory().getAbsolutePath()
+ "/DCIM/Camera/test.jpg", options2);
Log.i("wechat", "压缩后图片的大小" + (bm.getByteCount() / 1024 / 1024)
+ "M宽度为" + bm.getWidth() + "高度为" + bm.getHeight());
3/图片高效加载方式
Bitmap的高效加载在Glide中也用到了,思路:
- 获取需要的长和宽,一般获取控件的长和宽。
- 设置
BitmapFactory.Options
中的inJustDecodeBounds
为true,可以帮助我们在不加载进内存的方式获得Bitmap
的长和宽。 - 对需要的长和宽和Bitmap的长和宽进行对比,从而获得压缩比例,放入
BitmapFactory.Options
中的inSampleSize
属性。 - 设置
BitmapFactory.Options
中的inJustDecodeBounds
为false,将图片加载进内存,进而设置到控件中。