Only overridden methods in Class are being detected - java

I've created a custom adapter to handle a RecyclerView.
For some reason, the only methods that I can call from it after it has been initialised, are the ones that are overridden. Can anyone explain why this is? I have no idea!
public class CustomAdapter extends RecyclerView.Adapter<CustomAdapter.ViewHolder> {
private List<Item> items;
public static class ViewHolder extends RecyclerView.ViewHolder {
private ImageView icon;
private TextView text;
public ViewHolder(View item) {
super(item);
text = (TextView) itemView.findViewById(R.id.t);
icon = (ImageView) itemView.findViewById(R.id.i);
}
....
}
public CustomAdapter(List<Item> items) {
this.items = items;
}
#Override
public CustomAdapter.ViewHolder onCreateViewHolder(ViewGroup container, int type) {
View v = LayoutInflater.from(container.getContext())
.inflate(R.layout.fragment, container, false);
return new ViewHolder(v);
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
//method content
}
// EVERY METHOD I HAVE WRITTEN FROM HERE ONWARDS GOES UNDETECTED
public int getCount() {
return items.size();
}
}
i.e. when I instantiate an instance of the adapter:
private RecyclerView.Adapter adapter = new CustomAdapter(items);
and then I try to call adapter.getCount() it does not detect getCount().
getCount() does not come up in the autocomplete options when I start to type after 'adapter'.
getCount() shows an error, which just says 'Cannot Resolve Method' and getCount() in the CustomAdapter class shows that it is never used. This applies to all methods which do not have #override above them.
It is as if the methods don't exist. I cannot call them, but they are there. I am completely baffled!

change
private RecyclerView.Adapter adapter = new CustomAdapter(items);
to
private CustomAdapter adapter = new CustomAdapter(items);

Related

Setter in RecyclerViewAdapter not working?

I have a boolean in my onBindViewHolder which decides whether a button is clickable or not.
In the constructor I set this value to false, later when the user unlocks something I want to set it to true with a setter.
Here is my RecyclerViewAdapter.java:
public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.ViewHolder> {
private ArrayList<Items> items;
Context mContext;
private boolean unlocked;
public RecyclerViewAdapter(Context context, ArrayList<Items> items, boolean unlocked) {
mContext = context;
this.items = items;
this.unlocked = tabUnlocked;
}
public void setUnlocked(boolean unlocked) {
this.unlocked = unlocked;
this.notifyDataSetChanged();
}
#NonNull
#Override
public RecyclerViewAdapter.iewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(mContext).inflate(R.layout.item, parent, false);
RecyclerView.LayoutParams lp = new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
v.setLayoutParams(lp);
return new RecyclerViewAdapter.ViewHolder(v);
}
#Override
public void onBindViewHolder(#NonNull final RecyclerViewAdapter.ViewHolder holder, int position) {
final Items currentItem = items.get(position);
final String name = currentItem.getName();
holder.itemTextView.setText(name);
holder.itemTextView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (unlocked) {
//do something
}
}
});
}
#Override
public int getItemCount() {
return item.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
TextView itemTextView;
public ViewHolder(#NonNull View itemView) {
super(itemView);
itemTextView = itemView.findViewById(R.id.textViewItem);
}
}
}
And here is how I call the Setter to change it:
I make the RecyclerView public:
public RecyclerViewAdapter adapter;
Then I create an instance in my onCreate:
recyclerView = rootView.findViewById(R.id.recyclerView);
adapter = new RecyclerViewAdapter(items);
recyclerView.setAdapter(adapter);
And when the user unlocks a certain thing I call this method of the current Class:
public void unlockTab() {
adapter.setUnlocked(true);
}
When I log the boolean inside of that setter it tells me it got changed.
But when I log the boolean inside the onBindViewHolder it still remains false.
Why is the setter method not setting the boolean to true in the whole RecyclerViewAdapter.java class?
Hope someone can help me!
EDIT
I already tried adding "this.notifyDataSetChanged();" to the Setter Method (Thanks to #a_local_nobody)
Adapters are responsible for changes to recyclerviews. but if you don't tell them something changed, they won't know to do so.
call notifyDataSetChanged();
public void unlockTab() {
adapter.setUnlocked(true);
adapter.notifyDataSetChanged();
}
what does it do ?
It tells your recyclerview to bind all the data again, so then your changes will apply

RecyclerView messes up child view on scrolling

Well i tried to implement the recyclerview into Android Studio like this :
public class RecycleViewAdapter extends RecyclerView.Adapter<RecycleViewAdapter.ViewHolder> {
public String[] dataSet;
public Context context;
//---------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------//
public class ViewHolder extends RecyclerView.ViewHolder{
public ImageView image;
public TextView name;
public ViewHolder(View itemView) {
super(itemView);
this.image = itemView.findViewById(R.id.image);
this.name = itemView.findViewById(R.id.name);
}
public void bindData(Object data){
String extractedData = (String)data;
this.name.setText("");
this.name.setText(extractedData);
this.image.getLayoutParams().height = getRandomIntInRange(250, 100);
}
}
//---------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------//
public RecycleViewAdapter(Context context, String[] dataSet){
this.context = context;
this.dataSet = dataSet;
}
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(context).inflate(R.layout.food_view,parent,false);
ViewHolder viewHolder = new ViewHolder(view);
// Resolves the messed up views after recycling.
viewHolder.setIsRecyclable(false);
return viewHolder;
}
#Override
public void onBindViewHolder(#NonNull ViewHolder holder, int position) {
holder.bindData(dataSet[position]);
}
#Override
public int getItemCount() {
return dataSet.length;
}
// Custom method to get a random number between a range
protected int getRandomIntInRange(int max, int min){
Random rdm = new Random();
return rdm.nextInt((max-min)+min)+min;
}
}
Somehow i noticed that once i scroll up and down the recycled views get messed up...
Heres a Picture without Scrolling :
normal
And here is one after Scrolling... as you can see totally messed up :
messed up
Why does this happen and how can i prevent this ?
Does anyone got a solution ?
Well
Adapter is calling onBindViewHolder() all times when he must recreate view on the screen. You need to call getRandomIntInRange() outside of onBindViewHolder()
You could see it:

How can I use two layouts when using Android FirebaseListAdapter?

I am making an Android chat app that uses Cloud Firebase. In populating the listview with messages, I want to use two layouts, one for the incoming messages, and one for the going out messages. When following a tutorial that did something like this,
( http://www.devexchanges.info/2016/12/simple-chat-application-using-firebase.html )
they make their own messageAdapter class which introduces a getView function that will return one of the two views depending on the message. in the constructor for this class though, the super() statement is not working for me. here is the constructor:
public MessageAdapter(Lobby activity, Class<ChatMessage> modelClass, int modelLayout, DatabaseReference ref) {
super(activity, modelClass, modelLayout, ref);
this.activity = activity;
}
this is exactly like the tutorial uses it, but for some reason in the context of my own application it is not working. Is there something I have to do with the FirebaseListAdapter class to allow this action? Any help would be appreciated, if you need to see any of the other code in my project I'll be happy to edit to include it. Thanks.
Try using a RecyclerView and RecyclerView.Adapter instead of a FirebaseListAdapter, like this:
public class ChatAdapter extends RecyclerView.Adapter<ChatAdapter.ViewHolder> {
private static final int CHAT_END = 1;
private static final int CHAT_START = 2;
private List<Chat> mDataSet;
private String mId;
/**
* Called when a view has been clicked.
*
* #param dataSet Message list
* #param id Device id
*/
ChatAdapter(List<Chat> dataSet, String id) {
mDataSet = dataSet;
mId = id;
}
#Override
public ChatAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v;
if (viewType == CHAT_END) {
v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_chat_end, parent, false);
} else {
v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_chat_start, parent, false);
}
return new ViewHolder(v);
}
#Override
public int getItemViewType(int position) {
if (mDataSet.get(position).getId().equals(mId)) {
return CHAT_END;
}
return CHAT_START;
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
Chat chat = mDataSet.get(position);
holder.mTextView.setText(chat.getMessage());
}
#Override
public int getItemCount() {
return mDataSet.size();
}
/**
* Inner Class for a recycler view
*/
class ViewHolder extends RecyclerView.ViewHolder {
TextView mTextView;
ViewHolder(View v) {
super(v);
mTextView = (TextView) itemView.findViewById(R.id.tvMessage);
}
}
}
Please see more at https://github.com/thaleslima/firebase-chat-sample.

Inflate two types of .XML in RecyclerView

I have gone under a lot of frustration all because of this one issue I'm having: how do I inflate different .XML files for different objects in a RecyclerView? I have done as much as I can do, such as making a ListItemType object:
public class ListItemType {
public static int NOTE_VIEW = 0;
public static int CATEGORY_VIEW = 1;
}
And a ListViewItem object:
public class ListViewItem {
private int mType;
private Object mObject;
public ListViewItem(int type, Object object) {
mType = type;
mObject = object;
}
public int getType() {
return mType;
}
public void setType(int type) {
mType = type;
}
public Object getObject() {
return mObject;
}
public void setObject(Object object) {
mObject = object;
}
}
I'm clueless as to where I go from here.
RecyclerView Implement
First of all you have to add/create to/your Model type that indicates the your Model type and to know which layout to inflate:
MyModel.java
public class MyModel {
public enum ModelTypes {
TYPE_1,
TYPE_2
}
// your model members ^^^
ModelTypes type;
}
Now you have to create your ViewHolder, I suggest to create a parent ViewHolder class and extends your model types with sub classes.
MyHolder.java
public class MyHolder extends RecyclerView.ViewHolder {
// must have the ViewHolder default constructor
public MyHolder(View itemView) {
super(itemView);
}
public static MyHolder inflateViewByType(MyModel.ModelTypes type,
LayoutInflater layoutInflater, ViewGroup parent) {
View view;
switch (type) {
case TYPE_1:
view = layoutInflater.inflate(R.layout.layout_type_1, parent, false);
return new MyHolderType1(view);
break;
case TYPE_2:
view = layoutInflater.inflate(R.layout.layout_type_2, parent, false);
return new MyHolderType2(view);
break;
}
// Model type not supported
return null;
}
}
Create your ViewHolder types, in my example i have only two types.
MyHolderType1.java
public class MyHolderType1 extends MyHolder {
// layout members
public MyHolderType1(View itemView) {
super(itemView);
// init your layout members by for layout_type_1 by itemView.findViewById(...)
}
}
MyHolderType2.java
public class MyHolderType2 extends MyHolder {
// layout members
public MyHolderType2(View itemView) {
super(itemView);
// init your layout members by for layout_type_2 by itemView.findViewById(...)
}
}
Until now you only create the ViewHolder types to implement the RecyclerView.
RecyclerView must have an Adapter that extends the default RecyclerView.Adapter, to do this we have to create a new class and extends the RecyclerView.Adapter with our ViewHolder.
MyRecyclerViewAdapter.java
public class MyRecyclerViewAdapter extends RecyclerView.Adapter<MyHolder> {
private List<MyModel> mData;
public MyRecyclerViewAdapter(#NonNull List<MyModel> data) {
mData = data;
}
#Override
public MyHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
MyModel.ModelTypes type = MyModel.ModelTypes.values()[viewType];
return MyHolder.inflateViewByType(type, layoutInflater, parent);
}
#Override
public void onBindViewHolder(MyHolder holder, int position) {
MyModel model = mData.get(position);
switch (model.type) {
case TYPE_1:
setupViewType1((MyHolderType1) holder, model);
break;
case TYPE_2:
setupViewType2((MyHolderType2) holder, model);
break;
}
}
// to update the adapter data without reinitialize it
public void updateData(#NonNull List<MyModel> newData) {
mData = newData;
notifyDataSetChanged();
}
private void setupViewType1(MyHolderType1 holder, MyModel model) {
// do what you want with your views in layout_type_1
}
private void setupViewType2(MyHolderType2 holder, MyModel model) {
// do what you want with your views in layout_type_2
}
#Override
public int getItemCount() {
return mData.size();
}
#Override
public int getItemViewType(int position) {
return mData.get(position).type.ordinal();
}
}
Keep going, we almost done.
Now we have to initialize the RecyclerView in our activity, and set the an instance of MyRecyclerViewAdapter to it.
To this we have find out RecyclerView in and xml by calling findViewById(...), and then set the LayoutManager to the RecyclerView, after all we set the adapter with our data.
MyActivity.java
public class MyActivity extends Activity{
// ....
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_layout);
// init your views
RecyclerView recyclerView = findViewById(R.id.recycler_view);
// here you can pull or generate your recycler view list data
List<MyModel> data = getData();
MyRecyclerViewAdapter adapter = new MyRecyclerViewAdapter(data);
// set layout manager to the recycler view (Required)
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this,
LinearLayoutManager.VERTICAL, false);
recyclerView.setLayoutManager(linearLayoutManager);
// set the adapter to the recycler view (Required)
recyclerView.setAdapter(adapter);
}
// ....
}

How to create base adapter which has type parameter that extends another class and implements an interface?

I have seen the answer to the question,
Java: how to create a generic class that requires a data type which extends a class and implements an interface?
So I attempted to create a base adapter for recyclerview. This is my complete code for the base adapter:
class BaseAdapter<T extends SugarRecord & ModelInterface> extends RecyclerView.Adapter<BaseAdapter.ViewHolder> {
protected SparseArray<T> modelSparseArray;
protected Context context;
private int backgroundResource;
public BaseAdapter(SparseArray<T> modelSparseArray, Context context) {
this.modelSparseArray = modelSparseArray;
this.context = context;
setupBackgroundResource(context);
}
private void setupBackgroundResource(Context context){
TypedValue typedValue = new TypedValue();
context.getTheme().resolveAttribute(R.attr.selectableItemBackground, typedValue, true);
backgroundResource = typedValue.resourceId;
}
public class ViewHolder extends RecyclerView.ViewHolder{
#Bind(R.id.done_indicator)
CheckBox doneIndicator;
#Bind(R.id.title)
TextView title;
View view;
public ViewHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
view = itemView;
}
}
public void addModel(T model){
int key = model.getId().intValue();
int index = modelSparseArray.indexOfKey(key);
modelSparseArray.append(key, model);
if(key < 0)
notifyItemInserted(modelSparseArray.size());
else
notifyItemChanged(index);
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.row_layout, parent, false);
view.setBackgroundResource(backgroundResource);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(ViewHolder holder, final int position) {
final T model = modelSparseArray.valueAt(position);
holder.title.setText(model.getTitle());
holder.doneIndicator.setChecked(model.isDone());
holder.doneIndicator.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
model.setDone(isChecked);
model.save();
}
});
}
#Override
public int getItemCount() {
return modelSparseArray.size();
}
}
This question is almost exactly the same as I'm asking, however, the OP of that question gave the answer to the question using a pastebin which, unfortunately, the link is not working anymore.
The error is:
Error:(24, 1) error: BaseAdapter is not abstract and does not override abstract method onBindViewHolder(BaseAdapter.ViewHolder,int) in Adapter
Error:(80, 5) error: method does not override or implement a method from a supertype
The first error is pointing at the start of the class declaration, the second error points at the Override above onBindViewHolder
So I discovered the answer as soon as I posted the question, I'll post this in case anyone need the answer:
Change the RecyclerView.Adapter<BaseAdapter.ViewHolder> to RecyclerView.Adapter<BaseAdapter<T>.ViewHolder>
I originally created the base adapter without the type parameter so it worked with RecyclerView.Adapter<BaseAdapter.ViewHolder>, but after adding the type parameter, I also need to add <T>.
Another solution is making the internal ViewHolder static as #chRyNaN suggested.

Categories

Resources