我如何使用AsyncTask、RecyclerView和RecyclerView.Adapter将图像从手机获取到我的R



我正试图将手机中的图像加载到我的回收视图中。

到目前为止,我已经创建了一个回收视图适配器和网格布局管理器,并将它们连接到我的回收视图中。我可以成功地检索图像的完整路径,并使用异步任务将它们添加到适配器中。

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_gallery);
settingUp();
run();
}

public void settingUp(){
//setting up recycler view
recyclerView = findViewById(R.id.imageGallery);
recyclerView.setHasFixedSize(true);
//setting up recyclerview layout manager
RecyclerView.LayoutManager layoutManager = new      GridLayoutManager(getApplicationContext(),2);
recyclerView.setLayoutManager(layoutManager);
//setting up recyclerview adapter
adapter = getInstance(getApplicationContext());
recyclerView.setAdapter(adapter);
// instance of load task
loadTask = new LoadTask();
}
private void run() {
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, STORAGE_PERMISSION_CODE);
}
else
{
loadTask.execute();
}
}
/**
* Loads the images into the cursor using a background thread
*/
private class LoadTask extends AsyncTask<Void,Void, Cursor>
{
// images are loaded into the cursor here, in the background.
@Override
protected Cursor doInBackground(Void... voids) {
loadImagesIntoCursor();
return imageCursor;
}
// this method runs after doInBackground finishes
@Override
protected void onPostExecute(Cursor cursor) {
transferImagesToAdapter(cursor);
}
}
//*********************************************************************************************************
/**
* Loads all the Images from external storage into the cursor.
*/
private void loadImagesIntoCursor()
{
imageCursor = getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, new String[]{MediaStore.Images.Media.DATA}, null, null,
MediaStore.Images.Media.DATE_ADDED + " DESC");
}
private void transferImagesToAdapter(Cursor imageCursor)
{
String path;
if(imageCursor != null)
{
imageCursor.moveToFirst();
while (!imageCursor.isAfterLast()){
path =       imageCursor.getString(imageCursor.getColumnIndex(MediaStore.Images.Media.DATA));
adapter.add(path);
imageCursor.moveToNext();
}
imageCursor.close();
}
}
/** MY ADAPTER CLASS **/
class ImageAdapter extends RecyclerView.Adapter<ImageAdapter.ImageViewHolder>{
private ArrayList<String> images;
//private static ImageAdapter singleton = null;
Context context;
public ImageAdapter(Context context, ArrayList<String> paths)
{
images = paths;
this.context = context;
}
public ImageAdapter(Context context)
{
this.context = context;
}

//--------- OVERRIDE METHODS ---------------------------------------------
@NonNull
@Override
public ImageViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.cell_layout,parent);
return new ImageViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull ImageViewHolder holder, int position) {
holder.image.setScaleType(ImageView.ScaleType.CENTER_CROP);
// load image into image holder view using picasso library
Picasso.with(context).load(images.get(position)).into(holder.image);
}
@Override
public int getItemCount() {
return images.size();
}
//------------------------------------------------------------------------
public void add(String path){
this.images.add(path);
}
//------------------------------------------------------------------------
public class ImageViewHolder extends RecyclerView.ViewHolder{
protected ImageView image;
public ImageViewHolder(View view){
super(view);
this.image = view.findViewById(R.id.img);
}
}

}

然而,在添加了imagepath之后,我不知道是什么触发了适配器中的onCreateViewHolder和onBindViewHolder方法,这将在recyclerview中显示我的图像。请帮忙!

更新RecyclerView列表项需要做两件事。

  1. 更新适配器中的数据列表
  2. 通知数据集更改
private void transferImagesToAdapter(Cursor imageCursor)
{
String path;
if(imageCursor != null)
{
imageCursor.moveToFirst();
while (!imageCursor.isAfterLast()){
path =       imageCursor.getString(imageCursor.getColumnIndex(MediaStore.Images.Media.DATA));
adapter.add(path); // If it update data list in your adapter then fine.
adapter.notifyDataSetChanged(); // It will do all the callbacks and update your screen.
imageCursor.moveToNext();
}
imageCursor.close();
}
}

Recycler ViewRecycler View Adapter是两个不同的东西。简单地将数据添加到Adapter中,只会使Adapter对象变得更胖。

必须告诉Recycler ViewAdapter的数据状态已经改变,并且Recycler View应该从Adapter中提取更新的数据。

有两种方法:

  1. Adapter的数据源中放入所有数据更改后,调用方法notifyDataSetChanged方法
  2. 使用DiffUtil

上述技术之间的区别在于,notifyDataSetChanged将数据完全重置为当前数据源的数据,而DiffUtil只更改已更新的数据,不更改未更改的数据。

因此,如果您的数据源有大约1000个对象,而您只更改了一个对象,那么最好使用DiffUtils,因为notifyDataSetChanged将重新创建所有视图,即使是没有更改的视图,这也会影响性能。

此外,@vikas jha的答案的问题是,如果有很多图像,就会出现严重的性能瓶颈,因为即使是添加一个图像,整个数据源也会被重新加载,而它在循环中的事实会加剧问题。因此,将adapter.notifyDataSetChanged();调用移到循环之外。我假设您有一个图像的List作为数据源,其中add方法只是将一个图像添加到List中。

最好为adapter提供一个重载的add方法,该方法接受图像列表,将它们附加到adapter中现有图像列表的末尾(假设您以前加载过图像(,然后调用notifyDataSetChanged

您的活动类

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
run();
setContentView(R.layout.activity_gallery);
settingUp();
}

public void settingUp(){
//setting up recycler view
recyclerView = findViewById(R.id.imageGallery);
//setting up recyclerview layout manager
RecyclerView.LayoutManager layoutManager = new      GridLayoutManager(getApplicationContext(),2);
recyclerView.setLayoutManager(layoutManager);
// instance of load task
loadTask = new LoadTask();
}
private void run() {
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, STORAGE_PERMISSION_CODE);
}
}
/**
* Loads the images into the cursor using a background thread
*/
private class LoadTask extends AsyncTask<Void,Void, List<String>
{ 
// images are loaded into the cursor here, in the background.
@Override
protected List<String> doInBackground(Void... voids) {
return getAllImages();
}
// this method runs after doInBackground finishes
@Override
protected void onPostExecute(List<String imagesList>) {
ImageAdapter imageAdapter = new ImageAdapter(getActivity, magesList);
recyclerview.setAdapter(imageAdapter);
}
}
//*********************************************************************************************************
/**
* Loads all the Images from external storage into the cursor.
*/
private void getAllImages()
{
List<String> imagesList = new ArrayList<>();
Cursor imageCursor = getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, new String[]{MediaStore.Images.Media.DATA}, null, null,
MediaStore.Images.Media.DATE_ADDED + " DESC");
if(imageCursor != null)
{
imageCursor.moveToFirst();
while (!imageCursor.isAfterLast()){
String path = imageCursor.getString(imageCursor.getColumnIndex(MediaStore.Images.Media.DATA));
imagesList.add(path);
imageCursor.moveToNext();
}
imageCursor.close();
}
return imagesList;
}

您的适配器

/** MY ADAPTER CLASS **/
class ImageAdapter extends RecyclerView.Adapter<ImageAdapter.ImageViewHolder>{
private List<String> images;
Context context;
public ImageAdapter(Context context, List<String> paths)
{
this.images = paths;
this.context = context;
}
//--------- OVERRIDE METHODS ---------------------------------------------
@NonNull
@Override
public ImageViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.cell_layout,parent);
return new ImageViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull ImageViewHolder holder, int position) {
holder.image.setScaleType(ImageView.ScaleType.CENTER_CROP);
// load image into image holder view using picasso library
Picasso.with(context).load(images.get(position)).into(holder.image);
}
@Override
public int getItemCount() {
return images.size();
}
public class ImageViewHolder extends RecyclerView.ViewHolder{
protected ImageView image;
public ImageViewHolder(View view){
super(view);
this.image = view.findViewById(R.id.img);
}
}

最新更新