问题
So I have a recyclerview list of card views.I am trying to update the text time text in each view when the user clicks the card, and then reset it back when time has past. I set up an internal method in recyclerviewadapter but when I call updateTimes (calling from fragment), it does not reset the text back. Can someone instruct me on what I'm doing wrong?
import java.util.ArrayList;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.net.Uri;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.view.LayoutInflater;
import java.util.Calendar;
import android.content.Intent;
import java.text.SimpleDateFormat;
import java.util.Locale;
public class RecyclerAdapter extends RecyclerView.Adapter<FaucetHolder> {
private ArrayList<Faucet> faucets;
private Context context;
private SharedPreferences sharedPref;
private String dateFormat = "h:mm a";
public RecyclerAdapter(ArrayList<Faucet> faucetsI, Context context) {
this.faucets = faucetsI;
this.context = context;
}
@Override
public FaucetHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.card_view, viewGroup, false);
FaucetHolder f = new FaucetHolder(v);
return f;
}
@Override
public void onBindViewHolder(FaucetHolder f, int k) {
final Faucet faucet = faucets.get(k);
f.titleText.setOnClickListener(new View.OnClickListener() {
public void onClick(View btn) {
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(faucet.getLink()));
setRenewal(faucet);
notifyDataSetChanged();
context.startActivity(intent);
}
});
f.titleText.setText(faucet.getName());
sharedPref = context.getSharedPreferences("myPref", 0);
String time = sharedPref.getString(faucet.getSPName(), "could not retrieve time");
Log.e("tree", time);
f.timeText.setText(time);
}
@Override
public int getItemCount() {
return faucets.size();
}
private void setRenewal(Faucet g) {
sharedPref = context.getSharedPreferences("myPref", 0);
SharedPreferences.Editor edit = sharedPref.edit();
Calendar c = Calendar.getInstance();
long current = c.getTimeInMillis();
String x = sharedPref.getString(g.getSPName(), null);
long future = current + g.getLength();
g.setCT(future);
c.setTimeInMillis(future);
SimpleDateFormat df = new SimpleDateFormat(dateFormat, Locale.US);
String date = df.format(c.getTime());
edit.putString(g.getSPName(), date).commit();
}
public void updateTimes() {
sharedPref = context.getSharedPreferences("myPref", 0);
SharedPreferences.Editor edit = sharedPref.edit();
for ( Faucet f : faucets ) {
boolean m = checkifPast(f);
if ( m == true ) {
edit.putString(f.getSPName(), "Ready!").commit();
}
}
notifyDataSetChanged();
}
private boolean checkifPast(Faucet f) {
Calendar c = Calendar.getInstance();
long comp = c.getTimeInMillis();
if ( comp > f.getCT() ) {
return false;
}
return true;
}
}
Fragment Code
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
v = inflater.inflate(R.layout.faucetcards, container, false);
r = (RecyclerView) v.findViewById(R.id.RecyclerView);
rA = new RecyclerAdapter(generateCards(), getActivity());
lm = new LinearLayoutManager(getActivity());
r.setAdapter(rA);
r.setLayoutManager(lm);
sharedPref = getActivity().getPreferences(0);
return v;
}
@Override
public void onResume()
{
rA.updateTimes();
super.onResume();
}
回答1:
notifyDataSetChanged
should be used as a last resort, since it does not specify what has happened and therefore the adapter asumes nothing is valid anymore, which causes the list to not only rebind, but also relayout all visible views. You should instead use one of the notifyItem[Range][Inserted|Changed|Removed]()
methods instead, in your case notifyItemChanged(int position) will do.
In updateText()
you edit the text, but don't store the result in any field. Then later, bindViewHolder()
will be called, which calls setText(getTime())
and resets the text to its previous value. That is probably why nothing changes. You should add a method to your ViewHolder which first stores the result and then calls TextView.setText().
If your onClick()
is never called, you might want to check that you have set the view focusable and clickable in its layout-file.
This is my first awnser on StackOverflow and English is not my first language, so excuse me if I typed something wrong.
回答2:
Two things,
- I am not actually seeing where your
updateText
is being called. - You should call
notifyDataSetChanged()
to update the adapter to have your adapter redraw the list.
I added a simple recycler view and I added a listener to a textView. It should work after you call the text update and then call notifyDataSetChanged()
, see below
public class MyRecyclerAdapter extends RecyclerView.Adapter<FeedListRowHolder> {
private List<FeedItem> feedItemList;
private Context mContext;
public MyRecyclerAdapter(Context context, List<FeedItem> feedItemList) {
this.feedItemList = feedItemList;
this.mContext = context;
}
@Override
public FeedListRowHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.list_row, null);
FeedListRowHolder mh = new FeedListRowHolder(v);
return mh;
}
@Override
public void onBindViewHolder(FeedListRowHolder feedListRowHolder, int i) {
final FeedItem feedItem = feedItemList.get(i);
feedListRowHolder.title.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
updateText(feedItem);
notifyDataSetChanged();
}
});
Picasso.with(mContext).load(feedItem.getThumbnail())
.error(R.drawable.placeholder)
.placeholder(R.drawable.placeholder)
.into(feedListRowHolder.thumbnail);
feedListRowHolder.title.setText(Html.fromHtml(feedItem.getTitle()));
}
@Override
public int getItemCount()
{
return (null != feedItemList ? feedItemList.size() : 0);
}
private void updateText(FeedItem feedItem)
{
feedItem.setTitle("TEST!");
}
}
来源:https://stackoverflow.com/questions/30688651/update-text-within-card-view-list