关于项目。 我正在制作一个应用,该应用从网站获取数据并显示它。 现在,我正在研究ListFragment,它负责从最近6个帖子的列表中获取标题,日期,作者和图像,然后将它们放入存储区,再从存储区到RecyclerView。
当我运行ListFragment时,一切正常。但是,当我尝试用SwipeRefreshLayout刷新RecyclerView时,它仅刷新String数据,例如标题,日期和作者。在RecyclerView中刷新图像无法正常工作。
例如。 网站上有一篇新文章。我在没有Internet连接的情况下运行ListFragment,然后打开Internet连接并刷新RecyclerView,将其向下滑动。在RecyclerView项目中,只有String值会以适当的方式更新,尽管下载了新的图像并将其成功放入存储中,图像仍位于相同的位置。
如何在RecyclerView中成功刷新图像? 感谢您的帮助!
我的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;
}
我的SwipeRefreshLayout的onRefresh()方法
@Override
public void onRefresh() {
new TakeDataFromWebSite().execute();
}
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);
}
}
我的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;
}
}
答案 0 :(得分:0)
您要先通知 recyclerAdapterInside
,然后再将其提供给 recyclerview
:
recyclerAdapterInside.notifyDataSetChanged();
swipeRefreshLayout.setRefreshing(false);
recyclerView.setAdapter(recyclerAdapterInside);
只需更改 onPostExecute(Void aVoid)
中 AsyncTask
内的序列即可:
swipeRefreshLayout.setRefreshing(false);
recyclerView.setAdapter(recyclerAdapterInside); // Set adapter first.
recyclerAdapterInside.notifyDataSetChanged(); // Then notify for data change.
注意:切勿尝试通过以下方式更新用户界面(即活动/片段)
AsyncTask
,它可能会为UI视图对象抛出NullPointerException
。使用Interface
在UI和AsyncTask
。