1. Glide
1.1 简介
-
Glide 是一个快速高效的 Android 开源媒体管理和图像加载框架,它将媒体解码、内存和磁盘缓存以及资源池封装到一个简单易用的界面中
-
支持拉取,解码和展示视频快照,图片,和GIF动画
-
Glide的Api十分灵活,开发者甚至可以插入和替换成自己喜爱的任何网络栈。默认情况下,Glide使用的是一个定制化的基于HttpUrlConnection的栈,但同时也提供了与Google Volley和Square OkHttp快速集成的工具库
-
Glide几乎能满足你对远程图片的拉取/缩放/显示的一切需求
1.2 权限
1.2.1 网络加载
通过网络连接加载图像,将INTERNET和ACCESS_NETWORK_STATE权限添加到你的AndroidManifest.xml
<uses-permission android:name="android.permission.INTERNET"/>
1.2.2 本地存储
要从DCIM或图片等本地文件夹加载图像,需要添加READ_EXTERNAL_STORAGE权限
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
要将 Glide 的缓存存储在公共 sdcard 上,需要使用 WRITE_EXTERNAL_STORAGE权限
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
1.3 性能
Glide 充分考虑了Android图片加载性能的两个关键方面:1.图片解码速度;2.解码图片带来的资源压力
为了让用户拥有良好的App使用体验,图片不仅要快速加载,而且还不能因为过多的主线程I/O或频繁的垃圾回收,导致页面的闪烁和抖动现象。
Glide使用了多个步骤来确保在Android上加载图片尽可能的快速和平滑:
-
自动、智能地下采样(downsampling)和缓存(caching),以最小化存储开销和解码次数
-
积极的资源重用,例如字节数组和Bitmap,以最小化昂贵的垃圾回收和堆碎片影响
-
深度的生命周期集成,以确保仅优先处理活跃的Fragment和Activity的请求,并有利于应用在必要时释放资源以避免在后台时被杀掉
1.4 简单用法
1.4.1 引入依赖
implementation("com.github.bumptech.glide:glide:4.12.0")
//注解处理器(Glide's annotation processor)是用来在编译时生成一些额外的代码
//以帮助Glide优化图片加载性能
implementation("com.github.bumptech.glide:compiler:4.12.0")
注意:加载网络图片,一定要在AndroidMainfest.xml文件中设置网络权限
1.4.2 相关属性
- 编写布局文件,在Activity中使用
Glide.with(context)
.asGif()//设置本次加载为 GIF 动态图
.load(url)//图片地址
.priority(Priority.HIGH)//设置加载的优先级(Priority.LOW、Priority.NORMAL、
//Priority.HIGH、Priority.IMMEDIATE)
.placeholder(R.drawable.placeholder)//占位符
.error(R.drawable.error)//加载错误显示的图片
.fallback(R.drawable.ic_launcher_background)//设置备用图片,参数可以是Id,也可以是Drawable对象
.thumbnail(0.1f)//缩略图,设置图片的缩略图大小,其中0.1f表示原始图像的10%大小
.transform(new CircleCrop())//设置图片形式,CircleCrop()将图片设置为圆形,
//RoundedCorners(50)将图片设置为圆角
.transition(DrawableTransitionOptions.withCrossFade())//设置淡入淡出的动画效果
.into(imageView)//显示图片对应ImageView控件的id
补充:
-
其中load()可以加载以下几种类型的图片资源
.load(String string) string可以为一个文件路径、uri或者url .load(Uri uri) uri类型 .load(File file) 文件 .load(Integer resourceId) 资源Id,R.drawable.xxx或者R.mipmap.xxx .load(byte[] model) byte[]类型 .load(T model) 自定义类型 -
fallback()和error()的区别:
-
fallback()方法:- 用于设置备用图片资源,在主请求(
load(imageUrl))失败时显示
- 用于设置备用图片资源,在主请求(
-
.error()方法:- 设置在加载出错时显示的图片资源。与
fallback()不同的是,error()主要用于处理加载失败的情况(例如网络错误或者无效的 URL),而fallback()则是在主请求无法加载时使用备用图片。
- 设置在加载出错时显示的图片资源。与
-
1.4.3 图片缓存
Glide使用双缓存策略来管理图片缓存。它在内存中缓存未经压缩的原始图片,提升加载速度,同时还会将压缩后的图片存储在磁盘中,节省内存和流量。
根据图片的URL或资源ID生成唯一的缓存键,以确保不同的图片不会混淆。此外,Glide支持自定义缓存的大小和有效期,以适应不同需求。
- 内存缓存
Glide使用内存缓存来存储最近使用的图像数据,以便快速访问。内存缓存基于LRU(Least Recently Used,最近最少使用)算法,保留最近加载的图像数据。当应用需要再次访问这些图像时,可以直接提供,从而避免频繁的网络请求和磁盘读取。
-
磁盘缓存
-
活动资源缓存(Active Resources Cache): 这是一个小型、可写的磁盘缓存,存储当前正在使用的图像数据。它有助于减少频繁加载的图片的重复磁盘读取。
-
未活动资源缓存(Inactive Resources Cache): 这是一个更大、只读的磁盘缓存,用于长期存储已加载的图像数据。当活动资源缓存已满时,Glide会将不再活跃的图片从活动缓存中移至未活动资源缓存,以腾出空间供新图片使用。
-
-
缓存策略
-
DiskCacheStrategy.ALL: 在内存和磁盘上都缓存。 -
DiskCacheStrategy.NONE: 不使用磁盘缓存。 -
DiskCacheStrategy.DATA: 只缓存原始数据。 -
DiskCacheStrategy.RESOURCE: 只缓存转换后的资源。 -
DiskCacheStrategy.AUTOMATIC: 根据图片数据源自动选择缓存策略。
-
RequestOptions options = new RequestOptions()
.diskCacheStrategy(DiskCacheStrategy.AUTOMATIC);
1.4.4 清除缓存
若图片发生变化或需要释放存储空间,可手动清除Glide缓存。
- 清除磁盘缓存:
Glide.get(this).clearDiskCache();
- 清除内存缓存可使用:
Glide.get(this).clearMemory();
- 清除所有图片加载请求
Glide.clear()
2. EventBus
2.1 简介
EventBus 是一个 Android 事件发布/订阅框架,通过解耦发布者和订阅者简化 Android 事件传递。传统的事件传递方式包括:Handler、BroadCastReceiver、Interface 回调,相比之下 EventBus 的优点是代码简洁,使用简单,并将事件发布和订阅充分解耦。
-
**事件(Event):**又可称为消息。其实就是一个对象,可以是网络请求返回的字符串,也可以是某个开关状态等等。事件类型(EventType)指事件所属的 Class。事件分为一般事件和 Sticky 事件,相对于一般事件,Sticky 事件不同之处在于,当事件发布后,再有订阅者开始订阅该类型事件,依然能收到该类型事件最近一个 Sticky 事件
-
**订阅者(Subscriber):**订阅某种事件类型的对象。当有发布者发布这类事件后,EventBus 会执行订阅者的 onEvent 函数,这个函数叫事件响应函数。订阅者通过 register 接口订阅某个事件类型,unregister 接口退订。订阅者存在优先级,优先级高的订阅者可以取消事件继续向优先级低的订阅者分发,默认所有订阅者优先级都为 0
-
**发布者(Publisher):**发布某事件的对象,通过 post 接口发布事件
2.2 工作流程图解
Publisher使用post发出一个Event事件,Subscriber在onEvent()函数中接收事件。
EventBus 负责存储订阅者、事件相关信息,订阅者和发布者都只和 EventBus 关联
订阅者首先调用 EventBus 的 register 接口订阅某种类型的事件,当发布者通过 post 接口发布该类型的事件时,EventBus 执行调用者的事件响应函数。
2.3 优势
-
简化组件之间的通讯方式
-
对通信双方进行解藕
-
使用ThreadMode灵活切换工作线程
-
速度快、性能好
-
库比较小,不占内存
2.4 缺点
-
使用的时候有定义很多event类
-
event在注册的时候会调用反射去遍历注册对象的方法在其中找出带有@subscriber标签的方法,性能不高。
-
需要自己注册和反注册,如果忘了反注册就会导致内存泄漏
2.5 环境配置
dependencies {
implementation("org.greenrobot:eventbus:3.2.0")
}
2.6 使用
需求:我们在同一个Activity中,实现消息的发送和接收
- 在onStart中注册EventBus
@Override
protected void onStart() {
super.onStart();
//注册EventBus
EventBus.getDefault().register(this);
}
在onDestory中将EventBus销毁
@Override
protected void onDestroy() {
super.onDestroy();
//注销EventBus
EventBus.getDefault().unregister(this);
}
在onclick中发送消息
@Override
public void onClick(View v) {
EventMessage eventMessage = new EventMessage("这是一条消息");
EventBus.getDefault().post(eventMessage);
//将事件设置为sticky类型
// EventBus.getDefault().postSticky(eventMessage);
}
写一个方法使用@Subscribe注解,用于进行信息的接收和处理
//message接收处理
@Subscribe(threadMode = ThreadMode.POSTING, sticky = false, priority = 1)
public void onReceiveMessage(EventMessage eventMessage){
TextView tv_eventbus = findViewById(R.id.tv_eventbus);
tv_eventbus.setText(eventMessage.getMessage());
}
2.7 SubScribe注解
2.7.1 ThreadMode 模式
| 类型 | ||
|---|---|---|
| POSTING: 默认模式 | 表示发送事件 post() 发生在哪个线程,接收事件 onReceiveMessage就发生在哪个线程环境中 | 适合更新 UI 的操作 |
| MAIN / MAIN_ODERED: 主线程接收事件 |
表示无论事件在什么线程环境发布 post(),事件的接收总是在主线程环境执行。 MAIN:事件处理方法在主线程上执行,但不保证事件的顺序性,即事件处理方法的执行顺序可能不同于事件发布的顺序 MAIN_ODERED:事件处理方法在主线程上执行,并且保证事件的顺序性,即事件处理方法按照事件被发布的顺序依次执行 |
|
| BACKGROUND |
事件处理方法在后台线程中执行,避免阻塞主线程,但不保证是单一的后台线程 |
|
| ASYNC | 事件处理方法在一个单独的后台线程中执行 |
|
2.7.2 sticky黏性
sticky的作用就是:订阅者可以先不进行注册,如果post事件已经发出,再注册订阅者,同样可以接收到事件,并进行处理
2.7.3 priority
priority是优先级,是一个int类型,默认值为0。值越大,优先级越高,越优先接收到事件。值得注意的是,只有在post事件和事件接收处理,处于同一个线程环境的时候,才有意义
3. SmartRefreshLayout
SmartRefreshLayout是一个“聪明”或者“智能”的下拉刷新布局,由于它的“智能”,它不只是支持所有的View,还支持多层嵌套的视图结构。它继承自ViewGroup 而不是FrameLayout或LinearLayout,提高了性能。 也吸取了现在流行的各种刷新布局的优点,包括谷歌官方的 SwipeRefreshLayout,其他第三方的 Ultra-Pull-To-Refresh、TwinklingRefreshLayout 。还集成了各种炫酷的 Header 和 Footer
3.1 特点
-
支持多种样式:
- SmartRefreshLayout 支持多种下拉刷新和上拉加载的样式,如经典、球脉冲、水波纹、贝塞尔曲线回弹等,可以根据项目需求选择合适的样式
-
支持多种控件:
- 支持 RecyclerView、ListView、GridView、ScrollView、WebView 等 Android 原生控件,以及其它第三方库的集成
-
自定义配置:
- 提供丰富的自定义配置选项,开发者可以通过配置参数调整刷新和加载的行为,如设置是否启用刷新、加载更多、是否支持自动刷新等
-
越界回弹:
- 支持越界回弹效果,当下拉或上拉超出边界时,可以展示类似弹性效果的动画
-
自动刷新和加载:
- 支持自动刷新和加载更多功能,可以通过代码自动触发刷新或加载操作,方便在特定场景下的使用
-
高度定制化:
- 提供了丰富的接口和回调,开发者可以根据自己的需求实现更复杂的刷新和加载逻辑,例如自定义 Header 和 Footer
-
性能优化:
- 优化了滑动性能,保证在滑动过程中不会因为刷新或加载操作而影响用户体验
3.2 用法
- 引入依赖
implementation("com.github.bumptech.glide:glide:4.12.0")
implementation("io.github.scwang90:refresh-layout-kernel:2.0.5") //核心必须依赖
implementation("io.github.scwang90:refresh-header-classics:2.0.5") //经典刷新头
implementation("io.github.scwang90:refresh-footer-classics:2.0.5") //经典加载
- 在gradle.properties文件中添加
android.useAndroidX=true//这一行本身可能就有
android.enableJetifier=true
**android.useAndroidX=true:**这个配置项告诉 Gradle 使用 AndroidX 库而不是支持库(Support Library)。AndroidX 是一个重新设计的 Android 库,旨在提供更清晰、一致和可扩展的 API,并且它是未来 Android 应用开发的方向。许多现代的第三方库和组件(包括 SmartRefreshLayout)已经迁移到了 AndroidX,因此你需要确保你的项目也使用 AndroidX 来兼容这些库。
**android.enableJetifier=true:**Jetifier 是一个工具,它可以帮助你的项目在使用 AndroidX 之后,仍然能够与使用旧版支持库的依赖项兼容。它会自动修改你的依赖项,确保它们使用的是 AndroidX 版本的库而不是旧版支持库。
- 在布局文件中添加SmartRefreshLayout
<com.scwang.smart.refresh.layout.SmartRefreshLayout
android:id="@+id/smart_refresh_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.scwang.smart.refresh.header.ClassicsHeader
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:srlTextPulling="刷新数据"/>
<ListView
android:id="@+id/listview"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<com.scwang.smart.refresh.footer.ClassicsFooter
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:srlTextPulling="加载数据"/>
</com.scwang.smart.refresh.layout.SmartRefreshLayout>
- 编写Activity文件
public class MainActivity extends AppCompatActivity implements OnRefreshListener, OnLoadMoreListener {
private SmartRefreshLayout refreshLayout;
private ListView listView;
private ArrayAdapter<String> adapter;
private List<String> list;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
EdgeToEdge.enable(this);
setContentView(R.layout.activity_main);
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {
Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
return insets;
});
init();
refreshLayout = findViewById(R.id.smart_refresh_layout);
listView = findViewById(R.id.listview);
adapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, list);
listView.setAdapter(adapter);
refreshLayout.setOnRefreshListener(this);
refreshLayout.setOnLoadMoreListener(this);
}
//初始化数据
private void init(){
list = new ArrayList<>();
for (int i = 0; i < 20; i++){
list.add("初始化数据" + i);
}
}
//刷新数据
@Override
public void onRefresh(@NonNull RefreshLayout refreshLayout) {
refreshData();
}
//加载更多数据
@Override
public void onLoadMore(@NonNull RefreshLayout refreshLayout) {
loadMoreData();
}
private void refreshData(){
list.clear();
for (int i = 0; i < 20; i++){
list.add("重新加载的数据" + i);
}
adapter.notifyDataSetChanged();
refreshLayout.finishRefresh();
}
private void loadMoreData(){
int size = list.size();
for (int i = size; i <size + 10; i++){
list.add("新加载的数据" + i);
}
adapter.notifyDataSetChanged();
refreshLayout.finishLoadMore();
}
}
本系列【安卓基础重点知识】是刚开始学习android的时候记录的,其中部分内容来自网页,忘记记录来源了,如需添加引用,联系我即可