简体   繁体   English

RecyclerView中的图像没有刷新

[英]Images in the RecyclerView are not refreshing

About project. 关于项目。 I am making an app, which takes data from website and shows it. 我正在制作一个应用,该应用从网站获取数据并显示它。 Now, I am working on the ListFragment, which is responsible for getting titles, dates, authors and images, from the list of last 6 posts, then putting them in the storage, and from storage to the RecyclerView . 现在,我正在研究ListFragment,它负责从最近6个帖子的列表中获取标题,日期,作者和图像,然后将它们放入存储库,再从存储库存储到RecyclerView

click to see the website 点击查看网站

Everything works fine, when I am running ListFragment. 当我运行ListFragment时,一切正常。 But when i try to refresh my RecyclerView with my SwipeRefreshLayout it refreshes only String data, like titles, dates and authors. 但是,当我尝试使用SwipeRefreshLayout刷新RecyclerView时,它仅刷新字符串数据,例如标题,日期和作者。 Refreshing images in RecyclerView istn't working. 在RecyclerView中刷新图像无法正常工作。

For example. 例如。 There is one new post on the website. 网站上有一篇新文章。 I run my ListFragment without Internet connection, then turn Internet connection on and refresh RecyclerView swiping it down. 我在没有Internet连接的情况下运行ListFragment,然后打开Internet连接并刷新RecyclerView,将其向下滑动。 Only String values are updated in RecyclerView items in a proper way, Images stay in the same places, despite there were downloaded new ones and put into the storage successfully. 在RecyclerView项中,只有字符串值会以适当的方式更新,尽管下载了新的图像并将其成功放入存储中,但图像仍位于相同的位置。

How can I succesfully refresh images in my RecyclerView? 如何在RecyclerView中成功刷新图像? Thanks for any help! 谢谢你的帮助!

onCreateView() method of my ListFragment 我的ListFragment的onCreateView()方法

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {

    /* Inflating View */
    view = inflater.inflate(R.layout.fragment_list, container, false);

    ImageView banerImageView = view.findViewById(R.id.newsyBanerImageView);

    /* Enabling RecyclerView, and setting adapter for it */
    recyclerView = view.findViewById(R.id.recyclerView);

    layoutManager = new LinearLayoutManager(getContext());
    recyclerView.setLayoutManager(layoutManager);

    /* SwipeRefreshLayout varriable for recyclerView refreshing operations */
    swipeRefreshLayout = view.findViewById(R.id.swipeRefreshLayout);
    swipeRefreshLayout.setOnRefreshListener(this);

     /* Executing methods in TakeDataFromWebsite class. It dowloads data to save it to
    storage, then read it and put in UserInterface, in another Thread */
    new TakeDataFromWebSite().execute();
    swipeRefreshLayout.setRefreshing(true);

    /* enabling prograssbar */
    progressBar = view.findViewById(R.id.progressBar);

    return view;
}

onRefresh() method of my SwipeRefreshLayout 我的SwipeRefreshLayout的onRefresh()方法

@Override
public void onRefresh() {
    new TakeDataFromWebSite().execute();
}

TakeDataFromWebsite class TakeDataFromWebsite类

public class TakeDataFromWebSite extends AsyncTask<Void, Void, Void> {

    //
    MyRecyclerAdapter recyclerAdapterInside = new MyRecyclerAdapter();

    /* In these ArrayLists is put Content from website, and saved to files, contentSources
    are adresses of articles contents */
    private ArrayList<String> titlesFromWebsite = new ArrayList<>();
    private ArrayList<String> datesFromWebsite = new ArrayList<>();
    private ArrayList<String> authorsFromWebsite = new ArrayList<>();
    private ArrayList<String> imagesSourcesFromWebsite = new ArrayList<>();
    private ArrayList<String> contentSourcesFromWebsite = new ArrayList<>();
    //
    private ArrayList<RequestCreator> imagesFromWebsite = new ArrayList<>();

    /* In these arraylists is put content, which is read from storage */
    private ArrayList<String> titlesFromStorage = new ArrayList<>();
    private ArrayList<String> datesFromStorage = new ArrayList<>();
    private ArrayList<String> authorsFromStorage = new ArrayList<>();
    private ArrayList<String> contentSourcesFromStorage = new ArrayList<>();
    //
    private ArrayList<File> imagesFromStorage = new ArrayList<>();



    /* Number of downloaded divs */
    int elementsCountFromWebsite;

    /* It's used to do not always check if website is available in another thread */
    boolean isUrlReachable = false;

    /* Method in new Thread */
    @Override
    protected Void doInBackground(Void... params) {

        if (isURLReachable(mContext, webSiteAddress)) {
            isUrlReachable = true;

            Document doc = new Document("doc");
            try {

                /* Getting whole document */
                doc = Jsoup.connect(webSiteAddress).get();

            } catch (Exception e) {
                e.printStackTrace();
                Log.e("ListFragment", "Doc from site getting Exception.");
            }

                /* Getting proper divs and spans */
                Elements postThumbDivs = doc.select("div[class=post-thumb]");
                Elements dates = doc.select("span[class=posted-on]");
                Elements authors = doc.select("span[class=author vcard]");

                /* Setting variable to number of post divs downloaded */
            elementsCountFromWebsite = postThumbDivs.size();

                /* Variables for iteration */
                Element postThumbDiv;
                Element date;
                Element author;

                for (int i = 0; i < elementsCountFromWebsite; i++) {

                    /* Getting titles and adding them to list */
                    postThumbDiv = postThumbDivs.get(i).select("a").first();
                    titlesFromWebsite.add(postThumbDiv.attr("title"));

                    /* Getting sources od articles contents and adding them to list */
                    postThumbDiv = postThumbDivs.get(i).select("a").first();
                    contentSourcesFromWebsite.add(postThumbDiv.attr("href"));

                    /* Getting images sources and adding them to list */
                    postThumbDiv = postThumbDivs.get(i).select("img").get(0);
                    imagesSourcesFromWebsite.add(postThumbDiv.attr("src"));

                    /* Adding picasso requestCreator to the arrayList, which is used to write
                     data in the storage later *  */
                    imagesFromWebsite.add(Picasso.get().load(postThumbDiv.attr("src")));

                    /* Getting dates and adding them to list */
                    date = dates.get(i).getElementsByTag("time").first();
                    datesFromWebsite.add(date.text());

                    /* Getting authors and adding them to list */
                    author = authors.get(i);
                    authorsFromWebsite.add(author.text());
                }
        }
        return null;
    }

    @Override
    protected void onPostExecute(Void aVoid) {
        super.onPostExecute(aVoid);

        /* If website is available write data to storage */
        if (isUrlReachable){
            write(mContext, titlesFromWebsite, fileName + "Titles");
            write(mContext, datesFromWebsite, fileName + "Dates");
            write(mContext, authorsFromWebsite, fileName + "Authors");
            write(mContext, imagesSourcesFromWebsite, fileName + "ImagesSources");
            write(mContext, contentSourcesFromWebsite, fileName + "ContentSources");

            for(int i = 0; i < elementsCountFromWebsite; i++){
                imagesFromWebsite.get(i).into
                        (picassoImageTarget(mContext, imagesDirectoryName, Integer
                                .toString(i) + ".png"));
            }


        } else{
            Snackbar.make(view, getText(R.string.brak_polaczenia_z_serwerem), Snackbar
                    .LENGTH_LONG).show();
        }

        /* Reading data from storage files. These arraylists are later sent to an adapter,
        whch uses them as a source of content */
        titlesFromStorage = readStringArraylist(mContext, fileName + "Titles");
        datesFromStorage = readStringArraylist(mContext, fileName + "Dates");
        authorsFromStorage = readStringArraylist(mContext, fileName + "Authors");
        contentSourcesFromStorage = readStringArraylist(mContext, fileName + "ContentSources");

        /* Number of elements taken from storage used while reading data from storage */
        int itemsCountFromStorage = titlesFromStorage.size();

        /* Getting Images from storage into file and adding to the files arraylist */
        ContextWrapper contextWrapper = new ContextWrapper(mContext);
        File directory = contextWrapper.getDir(imagesDirectoryName, Context.MODE_PRIVATE);
        for(int i = 0; i < itemsCountFromStorage; i++){

            File myImageFile = new File(directory, Integer.toString(i) + ".png");
            imagesFromStorage.add(myImageFile);

        }

        /* Setting FragmentManager to the recyclerAdapter */
        recyclerAdapterInside.setFragmentManager(getFragmentManager());

        /* Sending String Arraylist to an adapter */
        recyclerAdapterInside.setTitles(titlesFromStorage);
        recyclerAdapterInside.setDates(datesFromStorage);
        recyclerAdapterInside.setAuthors(authorsFromStorage);
        recyclerAdapterInside.setContentSources(contentSourcesFromStorage);

        /* Sending File Arraylist to an adapter */
        recyclerAdapterInside.setImages(imagesFromStorage);

        /* Context and directory sent from this fragment to an adapter. They are used for
        reading images from storage */
        recyclerAdapterInside.setmContext(mContext);
        recyclerAdapterInside.setImagesDirectoryName(imagesDirectoryName);

        /* Setting an adapter to the recyclerView. Not in CreateView() method, because it is
        need to be done after loading all data from storage*/
        recyclerAdapterInside.notifyDataSetChanged();
        swipeRefreshLayout.setRefreshing(false);
        recyclerView.setAdapter(recyclerAdapterInside);

    }

}

My RecyclerView.Adapter class 我的RecyclerView.Adapter类

public class MyRecyclerAdapter extends RecyclerView.Adapter<MyRecyclerAdapter.ViewHolder> {

/* rraylists used to provide content */
private ArrayList<String> titles = new ArrayList<>();
private ArrayList<String> dates = new ArrayList<>();
private ArrayList<String> authors = new ArrayList<>();
private ArrayList<String> contentSources = new ArrayList<>();

/* Arraylist used, which i set with images from storage */
private ArrayList<File> images = new ArrayList<>();

/* Fragment with content of article and manager from  */
private ContentFragment contentFragment;
private FragmentManager fragmentManager;

/* Context and imagesDirectoryName from ListFragment */
private Context mContext;
private String imagesDirectoryName;

class ViewHolder extends RecyclerView.ViewHolder{

    public TextView itemTitleTextView;
    public TextView itemDateTextView;
    public TextView itemAuthorTextView;
    public ImageView itemImageView;
    public ImageView itemDateImageView;
    public ImageView itemAuthorImageView;



    public ViewHolder(View itemView){
        super(itemView);

        itemTitleTextView = itemView.findViewById(R.id.itemTitleTextView);
        itemDateTextView = itemView.findViewById(R.id.itemDateTextView);
        itemAuthorTextView = itemView.findViewById(R.id.itemAuthorTextView);
        itemImageView = itemView.findViewById(R.id.itemImageView);
        itemDateImageView = itemView.findViewById(R.id.itemDateImageView);
        itemAuthorImageView = itemView.findViewById(R.id.itemAuthorImageView);


        itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                int position = getAdapterPosition();

                contentFragment = new ContentFragment();

                /* Setting contentFragment attributes to proper values */
                contentFragment.setWebSiteAddress(contentSources.get(position));
                contentFragment.setItemIndex(position);
                contentFragment.setDate(dates.get(position));
                contentFragment.setAuthor(authors.get(position));
                contentFragment.setTitle(titles.get(position));
                contentFragment.setImagesDirectoryName(imagesDirectoryName);

                /* Fragment transaction process */
                FragmentTransaction transaction = fragmentManager.beginTransaction();
                transaction.replace(R.id.menuFragment, contentFragment);
                transaction.addToBackStack("contentFragment");
                transaction.commit();

                /* Test */
                Snackbar.make(v, "Click detected on item " + position, Snackbar.LENGTH_LONG)
                        .setAction("Action",null).show();
            }
        });
    }

}

@Override
public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i){
    View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.card_layout,
            viewGroup, false);
    ViewHolder viewHolder = new ViewHolder(v);
    return viewHolder;
}

@Override
public void onBindViewHolder(ViewHolder viewHolder, int i){
    viewHolder.itemTitleTextView.setText(titles.get(i));
    viewHolder.itemDateTextView.setText(dates.get(i));
    viewHolder.itemAuthorTextView.setText(authors.get(i));

    /* Process of reading images from arraylist and putting them to ImageViews */
    Picasso.get().load(images.get(i)).into(viewHolder.itemImageView);

}



@Override
public int getItemCount(){
    return titles.size();
}

public void setTitles(ArrayList<String> titles){
    this.titles = titles;
}

public void setDates(ArrayList<String> dates){
    this.dates = dates;
}

public void setAuthors(ArrayList<String> authors){
    this.authors = authors;
}

public void setContentSources(ArrayList<String> contentSources){
    this.contentSources = contentSources;
}

public void setFragmentManager(FragmentManager fragmentManager){
    this.fragmentManager = fragmentManager;
}

public void setmContext(Context mContext){
    this.mContext = mContext;
}

public void setImagesDirectoryName(String imagesDirectoryName) {
    this.imagesDirectoryName = imagesDirectoryName;
}

public void setImages(ArrayList<File> images){
    this.images = images;
}

} }

You're notifying recyclerAdapterInside before providing it to recyclerview : 您要在将其提供给recyclerAdapterInside之前通知recyclerview

recyclerAdapterInside.notifyDataSetChanged();
swipeRefreshLayout.setRefreshing(false);
recyclerView.setAdapter(recyclerAdapterInside);

Just change that sequence inside your onPostExecute(Void aVoid) of your AsyncTask : 只需在AsyncTask onPostExecute(Void aVoid)中更改该序列 onPostExecute(Void aVoid)

swipeRefreshLayout.setRefreshing(false);
recyclerView.setAdapter(recyclerAdapterInside); // Set adapter first.
recyclerAdapterInside.notifyDataSetChanged(); // Then notify for data change.

Note: Never try to update UI (ie Activity/Fragment) from AsyncTask , it may throw NullPointerException for UI view objects. 注意:切勿尝试通过AsyncTask更新UI(即Activity / Fragment),它可能会为UI视图对象抛出NullPointerException Use Interface to communicate between UI and AsyncTask . 使用Interface在UI和AsyncTask之间进行通信。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM