As the title.
I'm writing a custom RecyclerView which supports multi select mode. And I need tracking selected/unselected state of each item. So after data size of recyclerView has changed. I want to update size of my tracking state list.
But I don't know where to override methods : notifyDataSetChanged, notifyItemChagned ....
As the previous answer already correctly stated. You can't as those methods are final.
I came into the same situation when implementing the FastAdapter
The only solution I came up with is to name those methods slightly different. notifyDataSetChanged -> notifyAdapterDataSetChanged
https://github.com/mikepenz/FastAdapter/blob/develop/library/src/main/java/com/mikepenz/fastadapter/FastAdapter.java#L1354
public void notifyAdapterDataSetChanged() {
//... your custom logic
notifyDataSetChanged();
}
For the library it was quite important to improve the documentation regarding this point, but it is the only solution as of now.
You can't because it's final in RecyclerView.Adapter see here
You can override using BaseAdapter with ListView
#Override
public void notifyDataSetChanged() {
// TODO Auto-generated method stub
super.notifyDataSetChanged();
}
Register the adapter as the RecyclerView.Adapter's observer.
yourRecyclerView.getAdapter().registerAdapterDataObserver(new AdapterDataObserver() {
#Override
public void onChanged() {
// Do nothing
}
});
You can't because you can't override final methods.
Related
I've a vertical RecyclerView and each element of it, is a nested horizontal RecyclerView. Both have their Adapter and ViewHolder. When I change a flag, I want to be able to refresh the drawing of all items in each inner horizontal RecyclerView. I've written a method in the outer adapter that consequently call the inner one:
OuterAdapter:
public void setEditEnabled(boolean enabled) {
innerAdapter.setEditEnabled(enabled);
notifyDataSetChanged();
}
InnerAdapter:
public void setEditEnabled(boolean enabled) {
this.editable = enabled;
notifyDataSetChanged();
}
Then in the activity I call:
outerAdapter.setEditEnabled(editable);
outerRecyclerView.invalidate();
But only some "rows" are correctly updated...How can I solve this?
EDIT: so the flow is:
Outer setEditEnabled -> inner setEditEnabled -> inner notify -> outer notify
First of all, why are you calling invalidate on the RecyclerView. when you call notifyDataSetChanged() on the adapter, it automatically updates the RecyclerView items. And why is there only one inner Adapter. I think there should be a different adapter for each horizontal RecyclerView.
I don't know if I'm doing it right, but it seems to work fine.
Previously I was instantiating a new innerAdapter in the ViewHolder constructor:
class ViewHolder extends RecyclerView.ViewHolder {
RecyclerView innerRecyclerView;
ViewHolder(View view) {
super(view);
[...] // init things
innerRecyclerView.setAdapter(new InnerAdapter(context, onItemClickListener));
}
}
Now I'm doing the new in the OuterAdapter constructor and saving the reference as private field of the class:
public DailyMenusAdapter(Context context, OnItemClickListener onItemClickListener) {
innerAdapter = new InnerAdapter(context, onItemClickListener);
}
Then I pass the reference to:
innerRecyclerView.setAdapter(innerAdapter);
Is that ok in your opinion? So reusing the same adapter over and over again.
You know, I think if you will create annonimous Adapter class instead of notifyDataSetChanged (somethink like mRecyclerView.setAdapter(new YourAdapter(this, listOfDataYouPass))) it will work fine.
EDIT:Usually we do something like this to set adapter to RecyclerView:
List mLogs = new ArrayList<>;
mLogs.addAll (logs);
mLogAdapter = new LogAdapter(this, mLogs);
mRecyclerView = findViewById(R.id.log_list);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
mRecyclerView.setAdapter(mLogAdapter);
and then, when we need to modify something we call mLogAdapter.notifyDataSetChanged. Or just call notifyDataSetChanged inside Adapter class. But in many cases it works wrong, hard to say why in your case.
So here is what I advise:
instead of call notifyDataSetChanged make this method and call it when you need to update or change something:
private void updateRecyclerView (){
mRecyclerView.setAdapter(new LogAdapter(this, mLogs));
}
Note: Do not pay attention to the names, I took code from the first project I got
I'm trying to attach an onClickListener() method to an item which is inside a Recycler view. I know I can easily achive that by doing it from the RecyclerAdapter, but the goal of doing that is to show a custom dialog with some information that parent fragment contains, there are some ways to pass data, but I think that's better to attach the listener from fragment instead, and this way I can directly access the data.
I've tried to access from the fragment the way I use to do it from the adapter, with some modifications:
myRecyclerAdapter.myViewHolder.reportContainer.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(getContext(),"Touch",Toast.LENGTH_SHORT).show();
}
});
But aparently the myViewHolder object it's not created yet by the time I try to use it, so I get the Java NullPointerException (F..$&##^$&^%, don't misunderstand me, I love it).
So, I need some help to do what I'm trying to, or some other good ideas to try, warning: I;m really trying to avoid passing data, except with maybe a ViewModel (don't know if I can), becouse it's a lot of fields to pass
This is fundamentally incorrect. The problem here is, there are multiple ViewHolders in the RecylerView. Which one do you want to attach it to? There would be n number of items and not all items will be rendered at the same time.
Instead of updating the ViewHolder, use a callback.
class MyAdapter extends RecyclerView.Adapter {
MyAdapterCallback callback = null;
....
#Override
public void onBindViewHolder(holder: ViewHolder, position: Int) {
holder.reportContainer.setOnClickListener { // You can set this in OnCreateViewHolder as well.
if (callback != null) {
callback.onClick();
}
}
}
}
interface MyAdapterCallback {
void onClick()
}
From your fragment,
myAdapter.callback = new MyAdapterCallback() {
#Override
public void onClick() {
// Access your fragment variables here.
}
}
I have seen and searched for this method but I can not understand, what exactly does it do? I think you update the view in an adapter, here an example
mSelectPosition = getAdapterPosition();
if (!objection.isChecked()) {
notifyItemChanged(mSelectPosition);
objection.setChecked(true);
if (!ifExist(objection)) {
mList.add(objection);
}
} else {
removeList(objection);
notifyItemChanged(mSelectPosition);
objection.setChecked(false);
check.setVisibility(View.VISIBLE);
check.setImageDrawable(TintUtils.createTintedDrawable(iconNormal,
colorNormal));
}
After the adapter has loaded your data and is showing it already, if you change the values of objects being used to by the adapter and want the interface to show the new values, you need to call notifyItemChanged to ensure the UI is updated to the new values, otherwise it may or may not update.
I have two listview, like listview_1 and listview_2. I wanna refresh the listview_2 while listview_1 is refreshed.
My code like this:
public void updateTwoListView() {
listview_1.getAdapter().notifyDataSetChanged();
listview_2.getAdapter().notifyDataSetChanged();
}
But it don't work, listview_1 can refresh but the listview_2 can't.
And at that moment what I found is that listview_1 was on focus.
And then I tried to set focus to other views before ran the method, both of them didn't refresh. It likes to refresh a listview only if the listview has focus.
What's more I found that when I called the method to refresh, listview_2 didn't, and then I set focus to listview_2, refreshed itself!
So, What all I want to ask is:
How to refresh two listview at one moment in Android?
What's more code:
//init two listview there
public void init() {
listview_1 = (ListView)findViewById(R.id.listView1);
listview_2 = (ListView)findViewById(R.id.listView2);
adapter1 = new MyListViewAdapter(mContext);
adapter2 = new MyListViewAdapter(mContext); //I have tried use different adapter, that also didn't work.
listview_1.setAdapter(adapter1);
listView_2.setAdapter(adapter2);
}
the real code of upside snippet is:
public void updateTwoListView(int currentPosition) {
adapter1.updateCurPos(currentPosition);
adapter2.updateCurPos(currentPosition);
}
and in MyListViewAdapter.java:
public void updateCurPos(int currentPosition) {
mCurrentPos = currentPosition;
notifyDataSetChanged();
}
And I will call method like listViewManager.updateTwoListView(1) outside to refresh.
Any reply is appreciated.
You have called listview_1 twice. Just change one of them to listview_2 as below:
public void updateTwoListView() {
listview_1.getAdapter().notifyDataSetChanged();
listview_2.getAdapter().notifyDataSetChanged();
}
It seems the problem of your code is that you call getAdapter().
Sets the data behind this ListView. The adapter passed to this method may be wrapped by a WrapperListAdapter, depending on the ListView features currently in use. For instance, adding headers and/or footers will cause the adapter to be wrapped.
Source: http://developer.android.com/reference/android/widget/ListView.html#setAdapter(android.widget.ListAdapter)
The solution is save your Adapter as member variable in your activity and call the notifyDataSetChanged()from there.
See more on this question's answer: https://stackoverflow.com/a/31893525/2742759
I've a Spinner with onItemSelected interation that works, but how the Api specification says:
This callback is invoked only when the newly selected position is different from the
previously selected position or if there was no selected item.
I need to remove this limitation and i want that the callback is invoked also if the user select the same element. How to do that?
Anyone did the same thing?
Any idea about this would be appreciable..
i want that the callback is invoked also if the user select the same element. How to do that?
Setting the OnItemClickListener for a Spinner will throw an exception and using ItemSelectedListener you will not be notified if the user click on the selected/same element.
I suppose the only way to overcome this limitation is to use a CustomAdapter for the Spinner items and implement the setOnClickListener for each view in the adapter.
I had this same problem and looked around for a bit. There might be multiple ways of getting this functionality to work but extending the spinner worked for me. You could do something similar to what I found here.
So instead of using the default Android spinner extend it and add some code to it that will trigger your callback method.
I would like to add that using the setOnItemClickListener on a Spinner will throw an exception as stated in the documentation:
A spinner does not support item click events. Calling this method will raise an exception.
In this case you have to make a custom spinner: Try this
public class MySpinner extends Spinner{
OnItemSelectedListener listener;
public MySpinner(Context context, AttributeSet attrs)
{
super(context, attrs);
}
#Override
public void setSelection(int position)
{
super.setSelection(position);
if (position == getSelectedItemPosition())
{
listener.onItemSelected(null, null, position, 0);
}
}
public void setOnItemSelectedListener(OnItemSelectedListener listener)
{
this.listener = listener;
}
}