Use global variables in an Adaptor Android Studio - java

I want to use my class GlobalState in my HomePlayerAdapter. When I click on a Switch in my ListView they should save the ID from my player object in GlobalState. But when I click on a Switch my App crashed.
Here my GlobalState class:
public class GlobalState extends Application {
private ArrayList<Integer> selectedPlayer;
public ArrayList<Integer> getSelectedPlayer() {
return selectedPlayer;
}
public void addSelectedPlayer(int p) {
this.selectedPlayer.add(p);
}
public void removeSelectedPlayer(int p) {
this.selectedPlayer.remove(p);
}
}
Here my HomePlayerAdapter class:
public class HomePlayerAdapter extends BaseAdapter {
private Context context;
private ArrayList<Player> items;
private GlobalState globalState;
public HomePlayerAdapter(Context context, ArrayList<Player> items){
this.context = context;
this.items = items;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null){
convertView = LayoutInflater.from(context).inflate(R.layout.home_player_list_item, parent, false);
}
globalState = (GlobalState) context.getApplicationContext();
final Player currentItem = (Player) getItem(position);
TextView playerName = (TextView) convertView.findViewById(R.id.PlayerItemTextView);
SwitchMaterial deckSwitch = (SwitchMaterial) convertView.findViewById(R.id.PlayerItemSwitch);
playerName.setText(currentItem.getName());
deckSwitch.setOnCheckedChangeListener((buttonView, isChecked) -> {
if (isChecked){
globalState.addSelectedPlayer(currentItem.getId());
}if (!isChecked){
globalState.removeSelectedPlayer(currentItem.getId());
}
});
return convertView;
}
public int getCount() {
return items.size();
}
#Override
public Object getItem(int position) {
return items.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
}
When I click on a Switch then they call: deckSwitch.setOnCheckedChangeListener and check if the swith is checked or not. When its checked it should save the ID from the selected player in the GlobalState class and when its not checked then it should delete the ID.

I don't know if you have done this somewhere else in your code, but the code snippet that you provided, the problem lies in the fact that you haven't actually created the 'selectedPlayer' Arraylist. It can be checked if you are getting the nullPointerException.
although, I would suggest, rather than creating a globalState class like this, Make a class That would hold context Independent information, and declare static member variables, and methods. So that you do not have to instantiate the class for using. Since you are going to use selectedPlayer as a global variable anyway, its better to make it static, to prevent duplicate instantiation.
As for the solution to your problem for this particular case, just doing
private ArrayList<Integer> selectedPlayer = new ArrayList<>();
should be enough.

Related

Error in notifyDataSetChanged ListView Adapter File

I am getting the following error in hundreds of my users. I used it in my code because it asked me to call notifyDataSetChanged() but it didn't work. I have shared my adapter file below. I've done a lot of research for this but can't pinpoint the problem. I need your help.
Regards.
Fatal Exception: java.lang.IllegalStateException
The content of the adapter has changed but ListView did not receive a notification.
Make sure the content of your adapter is not modified from a background thread, but only from the UI thread. Make sure your adapter calls notifyDataSetChanged() when its content changes. [in ListView(2131296786, class android.widget.ListView)
My Adapter Code:
public class TracksAdapter extends BaseAdapter {
private DatabaseReference mDatabaseReference;
Context context;
private static TracksAdapter mInstance = null;
private Activity activity;
private InterstitialAd interstitialAds;
private int pos = -1;
private LoadingDialog progress = null;
List<Track> trackItems;
public void showProgressDialog() {
progress = new LoadingDialog(context);
progress.setCircleColors(context.getResources().getColor(R.color.turu), context.getResources().getColor(R.color.turu), context.getResources().getColor(R.color.turu));
progress.show();
}
public void hideProgressDialog() {
if (progress != null) {
progress.dismiss();
progress = null;
}
}
protected void TracksAdapter(Activity activity) {
this.activity = activity;
}
public TracksAdapter(Context context, List<Track> rowItems) {
notifyDataSetChanged();
this.context = context;
this.trackItems = rowItems;
}
#Override
public int getCount() {
return trackItems.size();
}
#Override
public Object getItem(int position) {
pos = position;
if (trackItems != null && trackItems.size() > position) {
return trackItems.get(position); // Line 54.
}
return null;
}
#Override
public long getItemId(int position) {
return trackItems.indexOf(getItem(position));
}
/* private view holder class */
private class ViewHolder {
String id, names, phones, lastseens, dates;
TextView name;
TextView phone;
TextView lastseen;
Integer membership;
ImageView delete, file;
}
public static TracksAdapter getInstance() {
return mInstance;
}
#RequiresApi(api = Build.VERSION_CODES.O)
#SuppressLint("WrongViewCast")
#Override
public View getView(int position, View convertView, ViewGroup parent) {
final ViewHolder holder;
if (convertView == null) {
}
}
}
Here is what I think the problem is, let us first see your code. This portion right here
public TracksAdapter(Context context, List<Track> rowItems) {
notifyDataSetChanged();
this.context = context;
this.trackItems = rowItems;
}
As you said you are calling notifyDataSetChanged(), but the thing is where is it being called.
You are calling it right now before any changes to data set has been made, you should call it after you have assigned the rowItems. You call it before and at that point nothing has changed.
So the correct code, will be as follows:
public TracksAdapter(Context context, List<Track> rowItems) {
this.context = context;
this.trackItems = rowItems;
notifyDataSetChanged();
}

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

How to update SpeedView inside ListView without initial animation?

So I have a fragment with three speedview gauges in it. Picture of fragment They used to be in the fragment directly and would work fine, but after I needed to add the textviews, I couldn't get everything to fit on the screen so I decided to create a custom layout and use a list view to display them.
It used to be very easy to update the speedometers and everythign worked fine.
After adding everything to a listview the only way I can think to get everything to update is to use notifyDataSetChanged() on the adapter, but when I do this, the gauge indicator snaps to 0 and goes up to the desired number from there. I have tried using a holder to maybe fix the problem, but no luck.
This is the fragment's code on how I create the adapter
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
OEEsegmentList = (ListView) view.findViewById(R.id.OEEplusLV);
qualitySegment = new OEEListSegment("Quality", OEEqualityValueString, "Bad parts: "+OEEqualityBadPartsValueString, "Total parts: "+OEEqualityTotalPartsValueString);
availabilitySegment = new OEEListSegment("Availability", OEEavailabilityValueString, "Downtime: "+OEEavailabilityDowntimeValueString, "Next time: "+OEEavailabilityNextTimeValueString);
performanceSegment = new OEEListSegment("Performance", OEEperformanceValueString, "Act time: "+OEEperformanceActTimeValueString, "Takt time: "+OEEperformanceTaktTimeValueString);
OEEsegmentArrayList = new ArrayList<>();
OEEsegmentArrayList.add(qualitySegment);
OEEsegmentArrayList.add(availabilitySegment);
OEEsegmentArrayList.add(performanceSegment);
OEEadapter = new OEEListAdapter(getActivity(), R.layout.oee_list_layout, OEEsegmentArrayList);
OEEsegmentList.setAdapter(OEEadapter);
}
and here is one of the update functions, they're all basically the same code with different names. I call them in the main activity when I recieve a message about the particular marker being changed.
public void updateOEEplusAvailability (String availability) {
OEEavailabilityValueString=availability;
availabilitySegment.setSegmentValueDial(OEEavailabilityValueString);
OEEadapter.notifyDataSetChanged();
}
this is my entire list adapter
public class OEEListAdapter extends ArrayAdapter<OEEListSegment> {
private Context mContext;
int mResource;
public ArrayList<OEEListSegment> mSegments ;
public OEEListAdapter(#NonNull Context context, int resource, #NonNull ArrayList<OEEListSegment> objects) {
super(context, resource, objects);
mContext = context;
mResource = resource;
mSegments=objects;
}
#NonNull
#Override
public View getView(int position, View convertView, ViewGroup parent) {
final ViewHolder holder;
holder = new ViewHolder();
String name = getItem(position).getSegmentName();
String valueDial = getItem(position).getSegmentValueDial();
String valueTV1 = getItem(position).getSegmentValueTV1();
String valueTV2 = getItem(position).getSegmentValueTV2();
final OEEListSegment Segment = new OEEListSegment(name, valueDial, valueTV1, valueTV2);
LayoutInflater inflater = LayoutInflater.from(mContext);
convertView = inflater.inflate(mResource, parent, false);
TextView textViewName = (TextView) convertView.findViewById(R.id.textViewSegmentName);
holder.speedView = (SpeedView) convertView.findViewById(R.id.segmentSpeedView);
holder.textViewFirst = (TextView) convertView.findViewById(R.id.textViewSegmentFirst);
holder.textViewSecond=(TextView) convertView.findViewById(R.id.textViewSegmentSecond);
convertView.setTag(holder);
holder.textViewFirst.setText(mSegments.get(position).getSegmentValueTV1());
holder.textViewSecond.setText(mSegments.get(position).getSegmentValueTV2());
holder.speedView.speedTo(Float.parseFloat(mSegments.get(position).getSegmentValueDial()));
holder.speedView.clearSections();
holder.speedView.addSections(
new Section(.3f, Color.RED)
, new Section(.7f, Color.YELLOW)
, new Section(1f, Color.GREEN));
textViewName.setText(name);
holder.textViewFirst.setText(valueTV1);
holder.textViewSecond.setText(valueTV2);
holder.speedView.speedTo(Float.parseFloat(valueDial));
return convertView;
}
#Override
public int getViewTypeCount() {
return getCount();
}
#Override
public int getItemViewType(int position) {
return position;
}
#Override
public int getCount() {
return mSegments.size();
}
public Object getItemCustom(int position) {
return mSegments.get(position);
}
#Override
public long getItemId(int position) {
return 0;
}
private class ViewHolder {
protected SpeedView speedView ;
private TextView textViewFirst ;
private TextView textViewSecond;
}
}
And this is the list segment code
public class OEEListSegment implements Parcelable {
private String name;
private String valueDial;
private String valueTV1;
private String valueTV2;
public OEEListSegment(String name, String valueDial, String valueTV1, String valueTV2) {
this.name=name;
this.valueDial=valueDial;
this.valueTV1=valueTV1;
this.valueTV2=valueTV2;
}
public String getSegmentName() {
return name;
}
public void setSegmentName(String name) {
this.name=name;
}
public String getSegmentValueDial() {
return valueDial;
}
public void setSegmentValueDial(String valueDial) {
this.valueDial=valueDial;
}
public String getSegmentValueTV1() {
return valueTV1;
}
public void setSegmentValueTV1(String valueTV1) {
this.valueTV1=valueTV1;
}
public String getSegmentValueTV2() {
return valueTV2;
}
public void setSegmentValueTV2(String valueTV2) {
this.valueTV2=valueTV2;
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeStringArray(new String[] {this.name, this.valueDial, this.valueTV1, this.valueTV2});
}
private void readFromParcel(Parcel in) {
name = in.readString();
valueDial= in.readString();
valueTV1= in.readString();
valueTV2= in.readString();
}
public OEEListSegment(Parcel in){
String[] data = new String[4];
in.readStringArray(data);
// the order needs to be the same as in writeToParcel() method
this.name = data[0];
this.valueDial= data[1];
this.valueTV1= data[2];
this.valueTV2= data[3];
}
public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
public OEEListSegment createFromParcel(Parcel in) {
return new OEEListSegment(in);
}
public OEEListSegment[] newArray(int size) {
return new OEEListSegment[size];
}
};
}
Any solution would be appreciated. Either how to stop that initial animation (0 to desired number) from happening in the speed view or how to update the listview so that animation doesn't happen.
Or would it be best to omit the list view completely, while still getting this desired layout (there will only ever be 3 segments).
I wasn't able to do what I needed to do inside the list segment, but since I knew the exact number of times I wanted this segment to be shown, I decided to change my approach.
I added a scoll view in my main layout and then included the segment layout 3x inside it. I then needed to access all the components by ID like this to acces the segment (layout)
performanceLayout = view.findViewById(R.id.performanceSegment);
and like this to access the elements inside my segments
speedViewPerformance= performanceLayout.findViewById(R.id.segmentSpeedView);
then I could update the speeviews with funcktions like this
public void updateOEEplusPerformance (String performance) {
OEEperformanceValueString=performance;
speedViewPerformance.speedTo(Float.parseFloat(OEEperformanceValueString));
}
It's much simpler than what I was trying to do before, since I don't need an adapter or a new class, I definitely do not need to change the speedview animation and it works just like I needed it to!

How to make two different Constructors in the same Class - Android

i think that this can be done, but maybe im wrong (Im sure im wrong). I have this adapter that sometimes uses a List of Class1 and in other moments uses a list of Class2. So, can i do TWO differents constructors where un the first one i use List1 and in the other one i use the List2?
public class SpinnerAdapter extends BaseAdapter {
private List<String> listaDeTexto;
private Activity activity;
private LayoutInflater layoutInflater;
private List<MetodoDePago> listaMetodosDePago;
private List<Banco> listaDeBancos;
public SpinnerAdapter(List<String> listaDeTexto, Activity activity, List<MetodoDePago> listaMetodosDePago) {
this.listaDeTexto = listaDeTexto;
this.activity = activity;
this.layoutInflater = (LayoutInflater)activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
this.listaMetodosDePago = listaMetodosDePago;
}
public SpinnerAdapter(List<String> listaDeTexto, Activity activity, List<Banco> listaDeBancos) {
this.listaDeTexto = listaDeTexto;
this.activity = activity;
this.layoutInflater = (LayoutInflater)activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
this.listaDeBancos = listaDeBancos;
}
#Override
public int getCount() {
return listaDeTexto.size();
}
#Override
public Object getItem(int position) {
return position;
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = convertView;
if (convertView == null){
view = layoutInflater.inflate(R.layout.spinner_custom,null);
}
TextView textView = view.findViewById(R.id.textViewSpinner);
textView.setText(listaDeTexto.get(position));
ImageView imageView = view.findViewById(R.id.imgViewSpinner);
Glide.with(view)
.load(listaMetodosDePago.get(position).getThumbnail())
.into(imageView);
return view;
}
}
Due to type erasure in Java, you are basically declaring two constructors which look like, SpinnerAdapter(List l1, Activity a, List l2) { } to Java.
A simple solution would be to create one constructor and add a type argument. So, something like, SpinnerAdapter(List l1, Activity a, List l2, int type) { }.
You can then check the type value in the constructor and the getView(...) method to initialize your variables as needed.

Only overridden methods in Class are being detected

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);

Categories

Resources