「这是我参与11月更文挑战的第6天,活动详情查看:2021最后一次更文挑战」
牙叔教程 简单易懂
这种setImageBitmap必须主动回收图片, bitmap已经赋值给了你定义的变量, 既然你给图片添加了新的引用, 那么这张图片就归你管, 系统就不管了
"ui";
ui.layout(
<vertical>
<img id="img"></img>
</vertical>
);
let img = images.read(imgPath);
let bitmap = img.bitmap;
ui.img.setImageBitmap(bitmap);
events.on("exit", function () {
img.recycle();
});
复制代码
这种就不用自己主动回收图片, 因为你没有对图片进行引用, 引用是系统自己搞的, 系统可以处理
"ui";
ui.layout(
<vertical>
<img id="img" src="file://{{imgPath}}"></img>
</vertical>
);
复制代码
这种也不用自己主动回收图片, 原因同上
ui.layout(
<vertical>
<img id="img"></img>
</vertical>
);
ui.img.attr("src", "file://" + imgPath);
复制代码
下面来看看RecyclerView中使用图片的情况 这是使用 img.attr("src", "file://" + data.imgPath); 不需要主动回收, 但是滑动rv的时候, 有点卡, 因为每次加载数据, 都去读取一遍图片
ui.layout(
<vertical>
<text text="牙叔教程 简单易懂" textSize="28sp" textColor="#fbfbfe" bg="#00afff" w="*" gravity="center"></text>
<androidx.recyclerview.widget.RecyclerView id="recyclerView"></androidx.recyclerview.widget.RecyclerView>
</vertical>
);
let imgPath = "/storage/emulated/0/脚本/ui界面图片回收/" + "road.jpg";
let dataList = [];
var len = 33;
for (var i = 0; i < len; i++) {
dataList.push({
imgPath: imgPath,
});
}
let recyclerView = ui.recyclerView;
let layoutManager = new LinearLayoutManager(context);
layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
recyclerView.setLayoutManager(layoutManager);
let recycleAdapter = createRecyclerViewAdapter(dataList);
recyclerView.setAdapter(recycleAdapter);
/* ---------------------------自定义函数----------------------------------------------- */
function createRecyclerViewAdapter(dataList) {
let boxXml = (
<horizontal id="horizontalParent">
<text id="num"></text>
<img id="img"></img>
</horizontal>
);
return RecyclerView.Adapter({
onCreateViewHolder: function (parent, viewType) {
log("onCreateViewHolder");
// 视图创建
let view;
let holder;
view = ui.inflate(boxXml, parent, false);
holder = JavaAdapter(RecyclerView.ViewHolder, {}, view);
return holder;
},
onBindViewHolder: function (holder, position) {
// log("onBindViewHolder");
// 数据绑定
let data = dataList[position];
holder.itemView.num.setText(position + "");
holder.itemView.img.attr("src", "file://" + data.imgPath);
},
getItemCount: function () {
return dataList.length;
},
});
}
复制代码
我们把onBindViewHolder改写一下, 如果已经加载过一次图片, 就不用执行 **img.attr("src"**这个命令了, 这属于最简单的缓存吧
onBindViewHolder: function (holder, position) {
let data = dataList[position];
holder.itemView.num.setText(position + "");
if ("file://" + imgPath !== holder.itemView.img.attr("src")) {
log("需要读取图片");
holder.itemView.img.attr("src", "file://" + data.imgPath);
} else {
log("不需要读取图片");
}
},
复制代码
修改之后, 除了一开始加载的前几张图片有点卡之外, 其他的一点都不卡, 丝滑的很,
那么问题还是有的, 如何让前几张图片, 滑动的时候, 也不要卡呢? 我们提前读取图片试试, 也就是用setImageBitmap
let imgPath = "/storage/emulated/0/脚本/ui界面图片回收/" + "road.jpg";
let dataList = [];
var len = 33;
let img = images.read(imgPath);
let bitmap = img.bitmap;
for (var i = 0; i < len; i++) {
dataList.push({
imgPath: imgPath,
img: img,
bitmap: bitmap,
});
}
events.on("exit", function () {
img.recycle();
});
ui.layout(
<vertical>
<text text="牙叔教程 简单易懂" textSize="28sp" textColor="#fbfbfe" bg="#00afff" w="*" gravity="center"></text>
<androidx.recyclerview.widget.RecyclerView id="recyclerView"></androidx.recyclerview.widget.RecyclerView>
</vertical>
);
let recyclerView = ui.recyclerView;
let layoutManager = new LinearLayoutManager(context);
layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
recyclerView.setLayoutManager(layoutManager);
let recycleAdapter = createRecyclerViewAdapter(dataList);
recyclerView.setAdapter(recycleAdapter);
/* ---------------------------自定义函数----------------------------------------------- */
function createRecyclerViewAdapter(dataList) {
let boxXml = (
<horizontal id="horizontalParent">
<text id="num"></text>
<img id="img"></img>
</horizontal>
);
return RecyclerView.Adapter({
onCreateViewHolder: function (parent, viewType) {
log("onCreateViewHolder");
// 视图创建
let view;
let holder;
view = ui.inflate(boxXml, parent, false);
holder = JavaAdapter(RecyclerView.ViewHolder, {}, view);
return holder;
},
onBindViewHolder: function (holder, position) {
let data = dataList[position];
holder.itemView.num.setText(position + "");
holder.itemView.img.setImageBitmap(data.bitmap);
},
getItemCount: function () {
return dataList.length;
},
});
}
复制代码
试了一下bitmap, 真的很丝滑呢, 起码小米11pro是丝滑的,
我们的dataList有33条数据, 每条数据使用的都是同一张图片的bitmap, 我们来试试33张不同的图片, 看会不会卡顿
修改dataList即可, 注意, bitmap是需要自己主动回收的
let img = images.read(imgPath);
for (var i = 0; i < len; i++) {
let newImg = img.clone();
let bitmap = newImg.bitmap;
dataList.push({
imgPath: imgPath,
img: newImg,
bitmap: bitmap,
});
}
events.on("exit", function () {
img.recycle();
dataList.map(function (item) {
item.img.recycle();
});
});
复制代码
基本和使用同一张图片的bitmap效果一样, 感觉不到卡顿.
这就表明, 读取图片是最消耗资源的, 我们尽量少的去读取图片, 尽量早的读取图片, 尤其要在ui中, 减少此类耗时操作, 不然, 卡顿是避免不了的.
现在加载33张图片, 还算可以吧. 如果我们加载3333张图片呢? 我觉得光是提前读取图片就会非常卡了, 非常耗时, 说不定就OOM了(Out Of Memory), 所以在数量级上去之后, 我们是不会提前读取全部图片的,
我们只会读取一小部分图片, 应该叫预加载吧,
手机是支撑不了同一时刻, 加载那么多图片数据的, 一会就卡爆了, 那么我们设定一个阈值, 只在同一时刻保存阈值以内数量的图片数据,
如果有新的图片需要显示, 那么就删掉以前的旧图片, 这个叫
LruCache(Least Recently Used Cache) 全称最近最少使用算法,其主要思想是使用SoftReference(或者WeakReference),因为我们的缓存容量是有限的,它会面临一个问题:当有新的内容需要加入我们的缓存,但我们的缓存空闲的空间不足以放进新的内容时,我们就需要舍弃原有的部分内容从而腾出空间用来放新的内容。
当然了, 写脚本估计用不到几张图片, 这个LurCache了解即可.
环境
手机: Mi 11 Pro
Android版本: 11
Autojs版本: 9.0.11
名人名言
思路是最重要的, 其他的百度, bing, stackoverflow, github, 安卓文档, autojs文档, 最后才是群里问问 --- 牙叔教程
声明
部分内容来自网络 本教程仅用于学习, 禁止用于其他用途