Paging3 (一)  入门

前言:

官方分页工具,  确实香.   但数据源不开放, 无法随意增删改操作;  只能借助 Room;  但列表数据不一定都要用 Room吧;

如果偏查询的分页数据用 Paging3 ;  其他一概用 老Adapter;  这倒也算个方案. [苦笑]

目录:

  1. 简单使用  -  数据源,Viewmodel,Adapter 等
  2. LoadResult  -  Error, Page.  Error 用法等
  3. PagingConfig
  4. 监听列表加载状态
  5. LoadStateAdapter  -  loading, 加载失败, 没有更多等
  6. Map  -  数据预处理

官方 Pagings 优势: 

  • 分页数据的内存中缓存。该功能可确保您的应用在处理分页数据时高效利用系统资源。
  • 内置的请求重复信息删除功能,可确保您的应用高效利用网络带宽和系统资源。
  • 可配置的 RecyclerView 适配器,会在用户滚动到已加载数据的末尾时自动请求数据。
  • 对 Kotlin 协程和 Flow 以及 LiveData 和 RxJava 的一流支持。
  • 内置对错误处理功能的支持,包括刷新和重试功能。

导包:

dependencies {
val paging_version = "3.0.0" //唯一必导包
implementation("androidx.paging:paging-runtime:$paging_version") // 测试用
testImplementation("androidx.paging:paging-common:$paging_version") // optional - RxJava2 support
implementation("androidx.paging:paging-rxjava2:$paging_version") // optional - RxJava3 support
implementation("androidx.paging:paging-rxjava3:$paging_version") // 适配 Guava 库 - 高效java扩展库
implementation("androidx.paging:paging-guava:$paging_version") // 适配 Jetpack Compose - 代码构建View; 干掉 layout
implementation("androidx.paging:paging-compose:1.0.0-alpha09")
}

1. 简单使用:

1.1 数据源  PagingSource 

自定义数据源, 继承 PagingSource

它有两个泛型参数,  1. 页码key,  没有特殊需求的话一般就是 Int 类型;  2.集合实体类型

重写两个方法:  1.load()  加载数据的方法;   2.getRefreshKey  初始加载的页码;  暂且返回 1 或 null

LoadResult.Page 后面再讲;

class DynamicDataSource: PagingSource<Int, DynamicTwo>() {

    //模拟最大页码
private var maxPage = 2 //模拟数据
private fun fetchItems(startPosition: Int, pageSize: Int): MutableList<DynamicTwo> {
Log.d("ppppppppppppppppppppp", "startPosition=${startPosition};;;pageSize=${pageSize}")
val list: MutableList<DynamicTwo> = ArrayList()
for (i in startPosition until startPosition + pageSize) {
val concert = DynamicTwo()
concert.title = "我是标题${i}"
concert.newsInfo = "我是内容${i}"
concert.nickName = "小王${i}"
list.add(concert)
}
return list
} override fun getRefreshKey(state: PagingState<Int, DynamicTwo>): Int? = null override suspend fun load(params: LoadParams<Int>): LoadResult<Int, DynamicTwo> {
val nextPageNumber = params.key ?: 1
val size = params.loadSize
Log.d("ppppppppppppppppppppp", "nextPageNumber=${nextPageNumber};;;size=${size}")
val response = fetchItems((nextPageNumber-1) * size, size) return LoadResult.Page(
data = response,
prevKey = null, // Only paging forward. 只向后加载就给 null
//nextKey 下一页页码; 尾页给 null; 否则当前页码加1
nextKey = if(nextPageNumber >= maxPage) null else (nextPageNumber + 1)
)
}
}

1.2 ViewModel

代码比较简单.  内容我们一会再讲

class DynamicPagingModel(application: Application) : AndroidViewModel(application) {
val flow = Pager(
//配置
PagingConfig(pageSize = 10, prefetchDistance = 2,initialLoadSize = 10)
) {
//我们自定义的数据源
DynamicDataSource()
}.flow
.cachedIn(viewModelScope)
}

1.3 前台使用: 

初始化 Adapter 及 RecycleView

mViewModel?.flow?.collectLatest  绑定监听,  然后通过 submitData() 刷新列表;

mAdapter = SimplePagingAdapter(R.layout.item_dynamic_img_two, null)

mDataBind.rvRecycle.let {
it.layoutManager = LinearLayoutManager(mActivity)
it.adapter = mAdapter
} //Activity 用 lifecycleScope
//Fragments 用 viewLifecycleOwner.lifecycleScope
viewLifecycleOwner.lifecycleScope.launchWhenCreated {
mViewModel?.flow?.collectLatest {
mAdapter.submitData(it)
}
}

1.4 Adapter

必须继承  paging 的 PagingDataAdapter

DiffCallback() 或 handler  NewViewHolder 不了解的可以看我的 ListAdapter 封装系列

open class SimplePagingAdapter(
private val layout: Int,
protected val handler: BaseHandler? = null
) :
PagingDataAdapter<DynamicTwo, RecyclerView.ViewHolder>(DiffCallback()) { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return NewViewHolder(
DataBindingUtil.inflate(
LayoutInflater.from(parent.context), layout, parent, false
), handler
)
} override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
if(holder is NewViewHolder){
holder.bind(getItem(position))
}
}
}

over  简单的分页模拟数据已完成;  

2. LoadResult

它是一个密封类;   它表示加载操作的结果;

2.1 LoadResult.Error

表示加载失败;  需提供 Throwable 对象.

public data class Error<Key : Any, Value : Any>(
val throwable: Throwable
) : LoadResult<Key, Value>()

可用于:

  • 异常时返回,  HTTP, IO, 数据解析等异常;
  • 服务器错误码响应
  • 没有更多数据

2.1 LoadResult.Page

表示加载成功;

参数:

data 数据集合;

prevKey 前页页码 key;   //向下一页加载 给null

nextKey 后页页码 key;    //向上一页加载 给null

public data class Page<Key : Any, Value : Any> constructor(
/**
* Loaded data
*/
val data: List<Value>,
/**
* [Key] for previous page if more data can be loaded in that direction, `null`
* otherwise.
*/
val prevKey: Key?,
/**
* [Key] for next page if more data can be loaded in that direction, `null` otherwise.
*/
val nextKey: Key?,
/**
* Optional count of items before the loaded data.
*/
@IntRange(from = COUNT_UNDEFINED.toLong())
val itemsBefore: Int = COUNT_UNDEFINED,
/**
* Optional count of items after the loaded data.
*/
@IntRange(from = COUNT_UNDEFINED.toLong())
val itemsAfter: Int = COUNT_UNDEFINED
) : LoadResult<Key, Value>() {

3.PagingConfig

分页配置

参数:

pageSize:  每页容量

prefetchDistance:  当RecycleView 滑动到底部时, 会自动加载下一页.   如果能提前预加载, 可以省去部分等待加载的时间.

        prefetchDistance 就是距离底部提前加载的距离.  默认 = pageSize;   = 0 时将不会加载更多

enablePlaceholders:  允许使用占位符.  想了解的点这里

initialLoadSize: 初始加载数量,  默认 = pageSize * 3

maxSize:   似乎意义没有那么简单.  还没看源码,不清楚;  不能 < pageSize + prefetchDistance * 2

jumpThreshold: 某阈值!  好吧我摊牌了, 我不知道. [奸笑]

4.监听加载状态:  

LoadState:  表示加载状态密封类;

LoadState.NotLoading:  加载完毕,  并且界面也已相应更新

LoadState.Error:  加载失败.

LoadState.Loading:  正在加载..

lifecycleScope.launch {
mAdapter.loadStateFlow.collectLatest { loadStates ->
when(loadStates.refresh){
is LoadState.Loading -> {
Log.d("pppppppppppppp", "加载中")
}
is LoadState.Error -> {
Log.d("pppppppppppppp", "加载失败")
}
is LoadState.NotLoading -> {
Log.d("pppppppppppppp", "完事了")
}
else -> {
Log.d("pppppppppppppp", "这是啥啊")
}
}
} //或者:
mAdapter.addLoadStateListener { ... }
}

5. 状态适配器  LoadStateAdapter

用于直接在显示的分页数据列表中呈现加载状态。 例如:  尾部显示 正在加载, 加载失败, 没有更多等;

5.1 自定义 MyLoadStateAdapter  继承 LoadStateAdapter

重写  onCreateViewHolder,  onBindViewHolder

retry:  如果加载失败, 想要重试,  则提供该高阶函数参数;  否则不需要它

class MyLoadStateAdapter(
/**
* 当下一页加载失败时, 继续尝试加载下一页;
*/
private val retry: () -> Unit
) : LoadStateAdapter<LoadStateViewHolder>() { override fun onCreateViewHolder(
parent: ViewGroup,
loadState: LoadState
) = LoadStateViewHolder(parent, retry) override fun onBindViewHolder(
holder: LoadStateViewHolder,
loadState: LoadState
) = holder.bind(loadState)
}

5.2 自定义 LoadStateViewHolder

功能: 

  • 加载中 显示 Loading;
  • 加载失败  显示 错误信息.    包括 http, IO 异常,  后台给的错误 msg 等;
  • 没有更多
class LoadStateViewHolder (
parent: ViewGroup,
retry: () -> Unit
) : RecyclerView.ViewHolder(
LayoutInflater.from(parent.context)
.inflate(R.layout.view_loading_more, parent, false)
) {
private val binding = ViewLoadingMoreBinding.bind(itemView) init {
//当点击重试按钮时, 调用 PagingDataAdapter 的 retry() 重新尝试加载
binding.btnLoadingRetry.setOnClickListener {
retry()
}
} fun bind(loadState: LoadState) {
// 当加载失败时.
if(loadState is LoadState.Error){
// 将没有更多封装成 NoMoreException; 此时显示没有更多 View
if(loadState.error is NoMoreException){
hideNoMoreUi(false) //显示 没有更多 View
hideErrUi(true) //隐藏 失败 View
}else{
hideNoMoreUi(true)
hideErrUi(false, loadState.error.message) //显示失败 View时, 填充错误 msg
}
}else{
hideNoMoreUi(true)
hideErrUi(true)
} //加载中..
binding.pbLoadingBar.visibility = if(loadState is LoadState.Loading){
View.VISIBLE
}else{
View.GONE
}
} /**
* 隐藏没有更多View;
*/
private fun hideNoMoreUi(hide: Boolean){
if(hide){
binding.tvLoadingHint.visibility = View.GONE
}else{
binding.tvLoadingHint.visibility = View.VISIBLE
}
} /**
* 隐藏 加载失败View;
*/
private fun hideErrUi(hide: Boolean, msg: String? = null){
if(hide){
binding.tvLoadingError.visibility = View.GONE
binding.btnLoadingRetry.visibility = View.GONE
}else{
binding.tvLoadingError.text = msg
binding.tvLoadingError.visibility = View.VISIBLE
binding.btnLoadingRetry.visibility = View.VISIBLE
}
}
}

顺便补一下  NoMoreException;  用法? 在下面 PagingSource 喽.

class NoMoreException: RuntimeException()

5.3 layout  view_loading_more.xml

包含:   TextView: 没有更多;    ProgressBar: 加载中;   TextView: 错误信息;   Button: 重试按钮

<layout>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:paddingHorizontal="16dp"
android:layout_width="match_parent"
android:layout_height="54dp">
<View
android:layout_width="match_parent"
android:layout_height="1px"
android:background="#e5e5e5"
app:layout_constraintTop_toTopOf="parent"/>
<TextView
android:id="@+id/tv_loading_hint"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="14sp"
android:textColor="#798080"
android:text="已经到底了"
android:visibility="gone"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/>
<ProgressBar
android:id="@+id/pb_loading_bar"
android:layout_width="32dp"
android:layout_height="32dp"
android:visibility="gone"
android:indeterminateTint="#7671F8"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/>
<TextView
android:id="@+id/tv_loading_error"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:textColor="@color/shape_red"
android:text="错误信息"
android:layout_marginEnd="8dp"
android:maxLines="2"
android:ellipsize="end"
android:visibility="gone"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/btn_loading_retry"
app:layout_constraintStart_toStartOf="parent"/>
<Button
android:id="@+id/btn_loading_retry"
android:layout_width="60dp"
android:layout_height="38dp"
android:textColor="@color/white"
android:text="重试"
android:visibility="gone"
android:background="@drawable/shape_blue_7671f8_r8"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

5.4 PagingSource 需要根据情况  返回不同的  LoadResult

代码如下,  直接看注释就可以了;   

class DynamicDataSource: PagingSource<Int, DynamicTwo>() {

    private var maxPage = 1

    override fun getRefreshKey(state: PagingState<Int, DynamicTwo>): Int? = null

    override suspend fun load(params: LoadParams<Int>): LoadResult<Int, DynamicTwo> {
try {
val nextPageNumber = params.key ?: 1 //超过页码时, 返回没有更多状态 NoMoreException
if(nextPageNumber > maxPage){
return LoadResult.Error(NoMoreException())
} //这是 Retrofit 网络请求
val map = mapOf("page" to nextPageNumber, "pageSize" to params.loadSize)
val param = ApiManager.INSTANCE.getJsonBody(map)
val response = ApiManager.INSTANCE.mApi.getDynamicList(param) //后台 响应错误码时; 用 RuntimeException 返回错误信息
if(response.code != 200){
return LoadResult.Error(RuntimeException(response.msg))
} //解析响应数据
val jo = response.data
val list = jo?.getAsJsonArray("newsList")?.toString()?.toBeanList<DynamicTwo>() ?: mutableListOf()
maxPage = jo?.get("totalPage").toString().toInt() //返回正常数据
return LoadResult.Page(
data = list,
prevKey = null, // Only paging forward. 只向后加载就给null
// nextKey 下一页页码; 尾页给 null; 否则当前页码加1
nextKey = nextPageNumber + 1
)
} catch (e: IOException) {
// IOException for network failures.
return LoadResult.Error(e)
} catch (e: HttpException) {
// HttpException for any non-2xx HTTP status codes.
return LoadResult.Error(e)
} catch (e: Exception) {
// IOException for network failures.
return LoadResult.Error(e)
}
}
}

代码中 请求参数只给了 page 和 pageSize;  其他参数怎么给?  

  1. DynamicDataSource 的构造方法传入;
  2. 动态参数怎么办?  写回调, 从ViewModel 中组装请求数据
  3. 麻烦怎么办?  创建 BaseDataSource.  将相似代码封装.  请求参数通过高阶函数从ViewModel组装;

5.5 前台使用: 

首先正常初始化 Adapter,  RecycleView,  并调用  mViewModel?.flow?.collectLatest

其次  RecycleView 的 adaper 不要给 主数据Adapter;  而是给 withLoadStateFooter() 返回的 ConcatAdapter

val stateAdapter = mAdapter.withLoadStateFooter(MyLoadStateAdapter(mAdapter::retry))
mDataBind.rvRecycle.let {
it.layoutManager = LinearLayoutManager(mActivity)
// **** 这里不要给 mAdapter(主数据 Adapter); 而是给 stateAdapter ***
it.adapter = stateAdapter
}

PagingDataAdapter 的 withLoadStateFooter 方法会返回一个新的 ConcatAdapter 对象; 请将这个 ConcatAdapter 设置给 RecycleView
withLoadStateFooter 的参数 就是我们自定义的 MyLoadStateAdapter;  retry -> mAdapter.retry()

5.6 看一下  LoadStateAdapter 的源码;  

可以发现,  这是个单条目 Adapter.   

并且  只有当  LoadState.Loading, LoadState.Error 时才会出现;   当然也可以重写  displayLoadStateAsItem(), 让它所有状态都出现;

当 列表状态变化时,  会设置 loadState 参数;  动态增删改 Item;

abstract class LoadStateAdapter<VH : RecyclerView.ViewHolder> : RecyclerView.Adapter<VH>() {

    var loadState: LoadState = LoadState.NotLoading(endOfPaginationReached = false)
set(loadState) {
if (field != loadState) {
val oldItem = displayLoadStateAsItem(field)
val newItem = displayLoadStateAsItem(loadState) if (oldItem && !newItem) {
notifyItemRemoved(0)
} else if (newItem && !oldItem) {
notifyItemInserted(0)
} else if (oldItem && newItem) {
notifyItemChanged(0)
}
field = loadState
}
} final override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): VH {
return onCreateViewHolder(parent, loadState)
} final override fun onBindViewHolder(holder: VH, position: Int) {
onBindViewHolder(holder, loadState)
} final override fun getItemViewType(position: Int): Int = getStateViewType(loadState)

  //条目数量, final 不可重写;
final override fun getItemCount(): Int = if (displayLoadStateAsItem(loadState)) 1 else 0 abstract fun onCreateViewHolder(parent: ViewGroup, loadState: LoadState): VH abstract fun onBindViewHolder(holder: VH, loadState: LoadState) open fun getStateViewType(loadState: LoadState): Int = 0
  
  //只有当 Loading, Error 时, 才显示
open fun displayLoadStateAsItem(loadState: LoadState): Boolean {
return loadState is LoadState.Loading || loadState is LoadState.Error
}
}

5.7 LoadStateAdapter  改建头尾

如果我们把它强行改造成 Header footer: 

  1. 重写 displayLoadStateAsItem() 不管什么状态, 都返回true
  2. loadState 不能重写,  所以 notifyItemChanged(0) 必被调用;
  3. 暴力一点, 直接重写 notifyItemChanged() 让它什么都不做?   好吧  它也是 final, 不能重写
  4. 既然要调刷新, 那就调吧 [破涕为笑];  那怎么办 尽量少执行无用代码呗,   那就 onBindViewHolder() 啥也不干;
  5. 头尾由前端控制,  Adapter 只需要把这个 固定View显示就 ok 了
  6. 如果能阻止 notifyItemChanged(0) 那就更好了.  聪明的你有没有办法呢. [666]

最终 Adapter: 

class EndViewAdapter(val v: View) : LoadStateAdapter<EndHolder>() {

    override fun onCreateViewHolder(
parent: ViewGroup,
loadState: LoadState
) = EndHolder(v) override fun onBindViewHolder(holder: EndHolder, loadState: LoadState){
//啥也不干
} override fun displayLoadStateAsItem(loadState: LoadState) = true
} class EndHolder(itemView: View) : RecyclerView.ViewHolder(itemView)

好吧,  一运行, 崩了 [捂脸];   called attach on a child which is not detached

怎么办, 取消 RecycleView 的刷新闪烁动画:

(mDataBind.rvRecycle.itemAnimator as SimpleItemAnimator).supportsChangeAnimations = false;

整个 RecycleView 的条目刷新动画都没了,  这不是个事啊!  但博主已经没办法了 [捂脸]

没办法了怎么办? 不用 Header 了?   当然不是,  我们只是不用 LoadStateAdapter 做头尾了;  我们用 ConcatAdapter 做头尾;

就是在 withLoadState...  之后,  再自己组装  ConcatAdapter

6. MAP:  数据转换;  有的时候, 我们需要对响应数据 进行预先处理; 

例如: 根据条件,预先改变实体内容;

val flow: Flow<PagingData<DynamicTwo>> = Pager(
PagingConfig(pageSize = 10, prefetchDistance = 2,initialLoadSize = 10)
) {
DynamicDataSource()
}.flow
.cachedIn(viewModelScope)
.map {
it.map { entity ->
// 这里根据条件, 预先处理数据
if(entity.isLike == 1){
entity.nickName = "变变变, 我是百变小魔女"
}else{
entity.nickName = "呜哈哈哈"
}
entity
}
}

例如:  组合实体; 根据条件产生不同实体;

val flow: Flow<PagingData<GroupEntity>> = Pager(
PagingConfig(pageSize = 10, prefetchDistance = 2,initialLoadSize = 10)
) {
DynamicDataSource()
}.flow
.cachedIn(viewModelScope)
.map {
it.map { entity ->
// 这里根据条件, 预先处理数据
if(entity.isLike == 1){
GroupEntity.DynamicTwoItem(entity)
}else{
GroupEntity.DynamicItem(DynamicEntity())
}
}
} sealed class GroupEntity{
class DynamicTwoItem (val entity: DynamicTwo): GroupEntity()
class DynamicItem (val entity: DynamicEntity): GroupEntity()
}

又例如: 插入实体分隔符等

Over

回到顶部

孟老板 Paging3 (一) 入门的更多相关文章

  1. 孟老板 Paging3 (二) 结合Room

    BaseAdapter系列 ListAdapter系列 Paging3 (一) 入门 Paging3 (二) 结合 Room Paging3 (二)  结合Room Paging 数据源不开放, 无法 ...

  2. 孟老板 ListAdapter封装, 告别Adapter代码 (三)

    BaseAdapter系列 ListAdapter封装, 告别Adapter代码 (一) ListAdapter封装, 告别Adapter代码 (二) ListAdapter封装, 告别Adapter ...

  3. 孟老板 ListAdapter封装, 告别Adapter代码 (四)

    BaseAdapter系列 ListAdapter封装, 告别Adapter代码 (一) ListAdapter封装, 告别Adapter代码 (二) ListAdapter封装, 告别Adapter ...

  4. 孟老板 BaseAdapter封装(五) ListAdapter

    BaseAdapter封装(一) 简单封装 BaseAdapter封装(二) Header,footer BaseAdapter封装(三) 空数据占位图 BaseAdapter封装(四) PageHe ...

  5. 孟老板 BaseAdapter封装 (一) 简单封装

    BaseAdapter封装(一) 简单封装 BaseAdapter封装(二) Header,footer BaseAdapter封装(三) 空数据占位图 BaseAdapter封装(四) PageHe ...

  6. 孟老板 BaseAdapter封装 (二) Healer,footer

    BaseAdapter封装(一) 简单封装 BaseAdapter封装(二) Header,footer BaseAdapter封装(三) 空数据占位图 BaseAdapter封装(四) PageHe ...

  7. 孟老板 BaseAdapter封装 (三) 空数据占位图

    BaseAdapter封装(一) 简单封装 BaseAdapter封装(二) Header,footer BaseAdapter封装(三) 空数据占位图 BaseAdapter封装(四) PageHe ...

  8. 孟老板 BaseAdapter封装(四) PageHelper

    BaseAdapter封装(一) 简单封装 BaseAdapter封装(二) Header,footer BaseAdapter封装(三) 空数据占位图 BaseAdapter封装(四) PageHe ...

  9. 孟老板 ListAdapter封装, 告别Adapter代码 (上)

    BaseAdapter封装(一) 简单封装 BaseAdapter封装(二) Header,footer BaseAdapter封装(三) 空数据占位图 BaseAdapter封装(四) PageHe ...

随机推荐

  1. layui中的视频上传(PHP )

    1.html中: <div class="layui-form-item"> <label class="layui-form-label"& ...

  2. 记一次 .NET 某HIS系统后端服务 内存泄漏分析

    一:背景 1. 讲故事 前天那位 his 老哥又来找我了,上次因为CPU爆高的问题我给解决了,看样子对我挺信任的,这次另一个程序又遇到内存泄漏,希望我帮忙诊断下. 其实这位老哥技术还是很不错的,他既然 ...

  3. Element ui结合springboot的简单实战

    Eelment UI简单实战 前端开发 1 创建项目,导入element ui(略) 2 大致设计出想要的效果,如下 3 创建包 根据设计的大致模样在项目的components中创建对应的包,方便以后 ...

  4. 『动善时』JMeter基础 — 18、JMeter配置元件【计数器】

    目录 1.计数器介绍 2.计数器界面详解 3.计数器的使用 (1)测试计划内包含的元件 (2)线程组界面内容 (3)计数器界面内容 (4)HTTP请求界面内容 (5)查看结果 1.计数器介绍 如果需要 ...

  5. java基础——创建对象与内部分布

    类与对象的关系 类是一种抽象的数据类型,它是对某一类事物整体描述和定义,但是不能代表某一个具体的事物 动物.植物.手机.电脑... Person类,Pet类,Car类,这些类都是用来描述和定义某一类具 ...

  6. istio流量管理:非侵入式流量治理

    在服务治理中,流量管理是一个广泛的话题,一般情况下,常用的包括: 动态修改服务访问的负载均衡策略,比如根据某个请求特征做会话保持: 同一个服务有多版本管理,将一部分流量切到某个版本上: 对服务进行保护 ...

  7. 一文详解 Linux 系统常用监控工一文详解 Linux 系统常用监控工具(top,htop,iotop,iftop)具(top,htop,iotop,iftop)

    一文详解 Linux 系统常用监控工具(top,htop,iotop,iftop)     概 述 本文主要记录一下 Linux 系统上一些常用的系统监控工具,非常好用.正所谓磨刀不误砍柴工,花点时间 ...

  8. 使用ps、top、ps_mem命令找出Linux中的最大内存消耗过程

    使用ps.top.ps_mem命令找出Linux中的最大内存消耗过程 2020-02-08 16:06:59作者:自力稿源:云网牛站 您可能已经看到Linux系统多次消耗过多的内存,如果是这种情况,那 ...

  9. Docker——基本使用及常用命令

    Docker 是一个开源的应用容器引擎,而一个容器其实是一个虚拟化的独立的环境,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化. ...

  10. 文件包含之包含了Linux文件描述符

    0x00 原理   文件描述符是内核为了高效管理已被打开的文件所创建的索引,用于指向被打开的文件,所有执行I/O操作的系统调用都通过文件描述符. 翻译成人话- 可以认为是指向文件的一个指针,如果有文件 ...