recyclerview ImageViews使用过多的内存
我有一个文件共享应用程序,该应用程序通过网络传输文件。
为了使用户正确选择文件,我列出了设备上可用的所有文件并使UX更好,我在OnBindViewHolder中获得了视频和图像的缩略图。由于设备上有任意数量的照片和视频,因此这会导致加载大量的缩略图,并且鉴于它的回收模型,我希望它不会使用太多的内存,但显然可以使用。我尝试在onviewRecycled中调用bitmap.recycle,因为某些视图也可能会反映缩略图。尝试使用Glide,但并没有超越Glide。(context).load(bitmap).into(holder.imageview)。
同样,当我完成活动时,一些位图可能会持续存在(在内存分析器中检查),
但是我想开始在活动仍在前景时减少内存使用情况。
我缺少什么?
编辑我还必须说,该活动正在使用Tablayout,其中有5个针对5种不同模拟型的选项卡,
因此,这是页面适配器
public class SectionsPagerAdapter extends FragmentStateAdapter {
public static final int[] TAB_TITLES = new int[]{R.string.Text_files, R.string.audio_files, R.string.image_files, R.string.video_files/*, R.string.unknown_files*/,R.string.apk_files};
public static final int[] SEARCH_TITLE = new int[]{R.string.search_res};
private final boolean isSearching;
private ArrayList<FileItemsModel> searchResModel;
private ArrayList<FileItemsModel> txtModel;
private ArrayList<FileItemsModel> audioModel;
private ArrayList<FileItemsModel> videoModel;
private ArrayList<FileItemsModel> imageModel;
private ArrayList<FileItemsModel> apkModel;
//private ArrayList<FileItemsModel> unknownModel;
public SectionsPagerAdapter(FragmentActivity fm, ArrayList<FileItemsModel> txtModel, ArrayList<FileItemsModel> audioModel,
ArrayList<FileItemsModel> videoModel, ArrayList<FileItemsModel> imageModel, ArrayList<FileItemsModel> apkModel/*, ArrayList<FileItemsModel> unknownModel*/) {
super(fm);
this.apkModel = apkModel;
this.txtModel = txtModel;
this.audioModel = audioModel;
this.videoModel = videoModel;
this.imageModel = imageModel;
//this.unknownModel = unknownModel;
isSearching = false;
}
public SectionsPagerAdapter(FragmentActivity fm, ArrayList<FileItemsModel> searchResModel) {
super(fm);
isSearching = true;
this.searchResModel = searchResModel;
}
@Override
public void onDetachedFromRecyclerView(@NonNull RecyclerView recyclerView) {
super.onDetachedFromRecyclerView(recyclerView);
searchResModel = txtModel = audioModel = videoModel = imageModel = apkModel = null;
}
@NonNull
@Override
public Fragment createFragment(int position) {
if (!isSearching) {
switch (position) {
case 0:
return PlaceholderFragment.newInstance(txtModel);
case 1:
return PlaceholderFragment.newInstance(audioModel);
case 2:
return PlaceholderFragment.newInstance(imageModel);
case 3:
return PlaceholderFragment.newInstance(videoModel);
case 4:
return PlaceholderFragment.newInstance(apkModel);
/*case 5:
return PlaceholderFragment.newInstance(unknownModel);*/
default:
throw new RuntimeException("invalid tab index " + position);
}
}
return PlaceholderFragment.newInstance(searchResModel);
}
@Override
public int getItemCount() {
if (!isSearching)
return TAB_TITLES.length;
return SEARCH_TITLE.length;
}
}
片段,该片段容纳了RecyClerview
public class PlaceholderFragment extends Fragment implements FileItemsAdapter.ItemClickListener{
private static final String MODEL_KEY = "MODEL_KEY";
private ArrayList<FileItemsModel> model;
private FragmentFileSelectorBinding binding;
private FileItemsAdapter adapter;
private RecyclerView recyclerGrid;
private FileSelectorActivity fileActivity;
public static PlaceholderFragment newInstance(ArrayList<FileItemsModel> model) {
PlaceholderFragment fragment = new PlaceholderFragment();
Bundle bundle = new Bundle();
bundle.putParcelableArrayList(MODEL_KEY, model);
fragment.setArguments(bundle);
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
fileActivity = (FileSelectorActivity) getActivity();
if (getArguments() != null)
model = getArguments().getParcelableArrayList(MODEL_KEY);
}
@Override
public View onCreateView(
@NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
binding = FragmentFileSelectorBinding.inflate(inflater, container, false);
View root = binding.getRoot();
recyclerGrid = binding.FilesGridList;
recyclerGrid.setLayoutManager(new GridLayoutManager(getContext(),3));
adapter = new FileItemsAdapter(model);
adapter.setClickListener(this);
recyclerGrid.setAdapter(adapter);
return root;
}
@Override
public void onDestroyView() {
super.onDestroyView();
binding = null;
model = null;
fileActivity = null;
recyclerGrid.removeAllViews();
recyclerGrid = null;
adapter.setClickListener(null);
adapter = null;
}
@Override
public void onItemClick(View view, int position, ArrayList<FileItemsModel> list) {
if(fileActivity.ChosenFiles.contains(list.get(position).getPath()))
fileActivity.ChosenFiles.remove(list.get(position).getPath());
else
fileActivity.ChosenFiles.add(list.get(position).getPath());
view.setAlpha(view.getAlpha() == 1 ? 0.5f : 1);
list.get(position).setIsSelected(view.getAlpha() != 1);
}
}
My Adapter
public class FileItemsAdapter extends RecyclerView.Adapter<FileSelectorViewHolder> {
private static final String[] queryRes = new String[] { MediaStore.MediaColumns._ID };
private static final int thumbType = MediaStore.Images.Thumbnails.MICRO_KIND;
private static final Uri imageUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
private static final Uri videoUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
private static final String queryFilter = MediaStore.MediaColumns.DATA + "=?";
private final ArrayList<FileItemsModel> FileItemsModelArrayList;
private ItemClickListener listener;
public FileItemsAdapter(ArrayList<FileItemsModel> FileItemsModelArrayList)
{
super();
this.FileItemsModelArrayList = FileItemsModelArrayList;
}
@Override
public int getItemCount() {
return FileItemsModelArrayList.size();
}
@NonNull
@Override
public FileSelectorViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
View item = inflater.inflate(R.layout.file_item,parent,false);
return new FileSelectorViewHolder(item, listener,FileItemsModelArrayList);
}
@Override
public void onBindViewHolder(@NonNull FileSelectorViewHolder holder, int position) {
//TODO: sometimes item is null.
FileItemsModel item = FileItemsModelArrayList.get(position);
if(item != null) {
holder.linearLayout.setAlpha(item.getIsSelected() ? 0.5f : 1);
holder.fileInfo.setText(item.getFileName());
String minSdk = item.getMinSdk();
if (minSdk != null)
holder.minSdk.setText(minSdk);
setFileIcon(item, holder);
}
item = null;
}
@Override
public void onViewRecycled(@NonNull FileSelectorViewHolder holder) {
super.onViewRecycled(holder);
// Glide.with(holder.itemView.getContext()).clear(holder.fileImg);
if(holder.fileBitmap != null)
{
holder.fileBitmap.recycle();
holder.fileBitmap = null;
}
holder.fileImg.setImageBitmap(null);
holder.itemView.setOnClickListener(null);
this.listener = null;
}
@Override
public void onViewDetachedFromWindow(@NonNull FileSelectorViewHolder holder) {
super.onViewDetachedFromWindow(holder);
if(holder.fileBitmap != null)
{
holder.fileBitmap.recycle();
holder.fileBitmap = null;
}
holder.fileImg.setImageBitmap(null);
holder.itemView.setOnClickListener(null);
this.listener = null;
}
public void setClickListener(@Nullable ItemClickListener itemClickListener) {
this.listener = itemClickListener;
}
public interface ItemClickListener {
void onItemClick(View view, int position, ArrayList<FileItemsModel> list);
}
private Bitmap getThumbnail(ContentResolver contentResolver,FileItemsModel item) {
String mimeType = item.getMimeType();
Cursor ca = contentResolver.query(mimeType.startsWith("video") ? videoUri : imageUri,queryRes, queryFilter, new String[] {item.getPath()}, null);
if (ca != null && ca.moveToFirst()) {
int id = ca.getInt(ca.getColumnIndex(MediaStore.MediaColumns._ID));
ca.close();
return mimeType.startsWith("video") ? MediaStore.Video.Thumbnails.getThumbnail(contentResolver, id,thumbType , null )
: MediaStore.Images.Thumbnails.getThumbnail(contentResolver, id,thumbType , null );
}
ca.close();
return null;
}
public void setFileIcon(FileItemsModel item, @NonNull FileSelectorViewHolder holder)
{
ContentResolver contentResolver = item.getContentResolver();
if(contentResolver != null) {
holder.fileBitmap = getThumbnail(contentResolver, item);
if (holder.fileBitmap != null) {
holder.fileImg.setImageBitmap(holder.fileBitmap);
return;
}
}
holder.fileImg.setImageDrawable(FileSelectorActivity.getFileDrawable(item.getMimeType()));
}
}
My View Holderer
public class FileSelectorViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
TextView fileInfo ;
TextView minSdk;
ImageView fileImg;
LinearLayout linearLayout;
Bitmap fileBitmap;
FileItemsAdapter.ItemClickListener listener;
private final ArrayList<FileItemsModel> FileItemsModelArrayList;
public FileSelectorViewHolder(View item, FileItemsAdapter.ItemClickListener listener, ArrayList<FileItemsModel> FileItemsModelArrayList)
{
super(item);
this.minSdk = item.findViewById(R.id.minSdk);
this.fileInfo = item.findViewById(R.id.FileName);
this.fileImg = item.findViewById(R.id.FileImg);
this.linearLayout = item.findViewById(R.id.FileContainer);
item.setOnClickListener(this);
this.listener = listener;
this.FileItemsModelArrayList = FileItemsModelArrayList;
}
@Override
public void onClick(View view) {
if(listener != null) listener.onItemClick(view,getAdapterPosition(), FileItemsModelArrayList);
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
编辑:我想念阅读,您尝试了Glide库。但是您尚未尝试在通话中使用磁盘缓存策略。
类似:
您可以在此处阅读有关滑行缓存的信息:
https:/> https:/ /bumptech.github.io/glide/doc/caching.html#disk-cache-strategies
如果您希望它们在显示时立即加载:
preload多个带有滑行的图像
Edit: I miss read, you tried the Glide library. But you haven't tried using a disk cache strategy on your call.
Something like:
You can read about Glide caching here:
https://bumptech.github.io/glide/doc/caching.html#disk-cache-strategies
You can also preload the images into a cache if you want them to load instantly when you display them:
Preload multiple images with Glide