I use onBindViewHolder in my CardAdapter. It includes an onClick method of checkedTextView.I am trying to get these texts and put to Arraylist(sharedP). But ArrayList only returns the last element. Where is my fault?
public void onBindViewHolder(#NonNull final CardTasarimTutucu holder, int position) {
SharedPreferences sp = mContext.getSharedPreferences("checked",Context.MODE_PRIVATE);
e=sp.edit();
sharedP= new ArrayList<>();
word = words.get(position).getMean();
Log.e("getMean",word);
id= words.get(position).getId();
str= new StringBuffer("");
holder.rowText.setText(word);
holder.rowText.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (holder.rowText.isChecked()) {
sharedP.remove(sharedP.indexOf(word));
flag=false;
holder.rowText.setCheckMarkDrawable(null);
holder.rowText.setChecked(false);
} else {
sharedP.add(word);
flag=true;
Log.e("deneme",word);
holder.rowText.setCheckMarkDrawable(R.drawable.ic_check_black_24dp);
holder.rowText.setChecked(true);
}
str.delete(0,str.length());
for(int i=0;i<sharedP.size();i++){
Log.e("sharedpreference1",sharedP.get(i).toString());
str.append(sharedP.get(i));
str.append(".");
}
if(flag==false){
e.remove("str");
e.commit();
}
Log.e("size",str.toString());
e.putString("str", str.toString());
e.remove("set");
e.commit();
}
});
}
example of checkedTextView
shared preference
First of all onBindViewHolder is calling for each item in RecyclerView in order to display the data in each position in the view item. So it is like a loop. In your code you initialize the sharedP array inside onBindViewHolder sharedP= new ArrayList<>();. So for each item you pass / scroll , the array is getting initialized again and the previous item is being lost.In other words when you reach the end of your list you will have only 1 item inside your list , the last one.
Related
I tried to get a array from an adapter from my code
here is the array that i wanted to get from my adapter, named MakananAdapter :
private int[] JumlahPesan = {0,0,0,0};
The array is changing constantly since user will be deciding the amount that they want, here is the onBindViewHolder code:
public void onBindViewHolder(#NonNull viewHolder holder, final int position) {
ImageView ivMakanan = holder.ivMakanan;
TextView tvNamaHarga = holder.tvNamaMakanan;
TextView tvKetersediaan = holder.tvKetersediaan;
TextView tvHarga = holder.tvHargaMakanan;
final TextView tvPesanan = holder.tvJumlahPesanan;
Button btnTambah = holder.btnTambah;
Button btnKurang = holder.btnKurang;
ivMakanan.setImageResource(makanans.get(position).getGambarMakanan());
tvNamaHarga.setText(makanans.get(position).getNamaMakanan());
tvKetersediaan.setText("Stok : " + makanans.get(position).getStatusMakanan());
tvHarga.setText("Harga : " + makanans.get(position).getHargaMakanan());
btnTambah.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
JumlahPesan[position]++;
tvPesanan.setText(String.valueOf(JumlahPesan[position]));
}
});
btnKurang.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
JumlahPesan[position]--;
tvPesanan.setText(String.valueOf(JumlahPesan[position]));
}
});
}
as you can see i make a button that increase and decrease the data of the array
and i tried to get the array data to my activity, but i still get error.
my activity named PilihMakananActivity.class
here is the array to save the data from the adapter
private int[] Pesanan = {0,0,0,0};
and i tried to get the data in onResume
protected void onResume() {
super.onResume();
com.example.iotforcanteen.adapter.MakananAdapter coba = null;
for (int i = 0; i<4 ; i++) {
Pesanan [i]= coba.AmbilJumlahPesanan(i);
}
}
and i tried to show it in a snackbar like this
btnKonfirmasi.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Snackbar.make(v, Pesanan[0] + Pesanan[1] + Pesanan[2] + Pesanan[3],Snackbar.LENGTH_SHORT).show();
}
});
Im so sorry if the code is so messy, because im new to android development.so is there any way to fix this error?
It has error because you set to your adapter null value in onResume .
But in general I assume you use RecyclerView in code so the steps for using RecyclerView is important, first you must set LayoutManager for RecyclerView. Then make an adapter and set it to RecyclerView and I recommend you to do this steps in onCreate not onResume.
Here is a little example
RecyclerView recyclerView = findViewById(R.id.rec);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
adapter = new MyRecyclerViewAdapter(this, list);
recyclerView.setAdapter(adapter);
Also make your array in adapter public or write getter for it. After calling setAdapter for RecyclerView, you can get your data in adapter. For example you can define a Button and in OnClickListener get the desired array(here is JumlahPesan) in adapter
you aren't initiating this adapter (null) and few lines below trying to access data from it, this is NullPointerException
com.example.iotforcanteen.adapter.MakananAdapter coba = null;
for (int i = 0; i<4 ; i++) {
Pesanan [i]= coba.AmbilJumlahPesanan(i);
}
make reference to already exitsting adapter atached to your ListView or RecyclerView, not freshly created and not initialised at all
note that onResume is called once at the beggining, thus your Pesanan won't have current data, only copy from start of Activity
maybe just get your values straightly when button pressed, without a copy of array in Activity:
btnKonfirmasi.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Snackbar.make(coordinatorLayout,
adapterAttachedToView.AmbilJumlahPesanan(0) + " " +
adapterAttachedToView.AmbilJumlahPesanan(1) + " " +
adapterAttachedToView.AmbilJumlahPesanan(2) + " " +
adapterAttachedToView.AmbilJumlahPesanan(3),
Snackbar.LENGTH_SHORT).show();
}
});
note that Snackbar.make( should take View, in which Snackbar will appear, not clicked Button (you are passing v to Snackbar.make)
I have an activty which has an EditText and a Spinner, in which when selecting an element of the Spinner, the selected element must be displayed in the EditText. Until then everything goes well. But if I want to assign a value to that EditText, outside of the onItemSelected method proper to the Spinner, it simply does not show the string I assigned it with the setText method.
deps = new ArrayList<>();
cargarDeps();
deps.add("");
adapterSPDep = new ArrayAdapter<String>(this, R.layout.lista_sp, deps);
spDep.setAdapter(adapterSPDep);
spDep.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> adapterView, View view, int pos, long id) {
auxDep = (String) adapterView.getItemAtPosition(pos);
txtDep.setText(auxDep);
}
#Override
public void onNothingSelected(AdapterView<?> parent) {
// txtDep.setText(auxDep);
}
});
that code its in the onCreate of my activity, my method "cargaDeps()" is linked to a webservice which obtains all the departments that exists, which I save in the ArrayList "deps". In the onItemSelected () method of the Spinner is where I assign what my EditText is selected. But when I call this method:
public void rellenar(String[] campos) {
txtNum.setText(campos[4]);
txtFecha.setText(campos[1]);
txtHora.setText(campos[2]);
txtDes.setText(campos[3]);
txtTipo.setText(campos[4]);
txtDep.setText(auxDep);
txtReporta.setText(campos[6]);
txtAtiende.setText(campos[7]);
}
in txtDep.setText (auxDep); no value is assigned.
Make a global String value and assign the value you want to get from the spinner to the String value.
I have the following code for the recyclerview adapter for an android app that I'm working on right now:
#Override
public void onBindViewHolder(final FeedViewHolder contactViewHolder, final int i) {
final FeedInfo ci = feedInfoList.get(i);
//Set the text of the feed with your data
contactViewHolder.feedText.setText(ci.getFeed());
contactViewHolder.surNameText.setText(ci.getSurName());
contactViewHolder.nameText.setText(ci.getFirstName());
contactViewHolder.feedDate.setText(ci.getDate());
contactViewHolder.numberOfGoingText.setText(ci.getNumber_of_going());
contactViewHolder.numberOfInterestedText.setText(ci.getNumber_of_interested());
//seteaza fotografia de profil in postare
new ProfilePictureDownloadImage(contactViewHolder.profilePicture).execute(ci.getProfileImageURL());
ImageButton interestedButton = contactViewHolder.interestedButton;
interestedButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
int position = i;
FeedInfo fi = feedInfoList.get(position);
int displayedNumberOfInterested = Integer.parseInt(ci.getNumber_of_interested()) + 1;
contactViewHolder.numberOfInterestedText.setText(Integer.toString(displayedNumberOfInterested));
System.out.println("emilutzy interested from within" + fi.getPostID());
contactViewHolder.surNameText.setText("kk");
}
});
}
The problem is the click listener. In theory the button I press should increment the number right next to it. However, since I have to declare onBindViewHolder's arguments as final, only the first click works, the rest of the clicks do not change the value of the number. I am new to Android, so could you please help me find a better solution?
There's a nice method called getAdapterPosition() that you can use in your RecyclerView's ViewHolder.
Instead of setting the click listener in onBindViewHolder, set it in the constructor of your ViewHolder like so:
public class FeedViewHolder extends RecyclerView.ViewHolder {
private TextView feedText;
private TextView surNameText;
private Button interestedButton;
// ... the rest of your viewholder elements
public FeedViewHolder(View itemView) {
super(itemView);
feedtext = itemView.findViewById(R.id.feedtext);
// ... find your other views
interestedButton.setOnClickListener(new View.OnClickListener() {
final FeedInfo fi = feedInfoList.get(getAdapterPosition());
int numInterested = Integer.parseInt(ci.getNumber_of_interested()) + 1;
// setting the views here might work,
// but you will find that they reset themselves
// after you scroll up and down (views get recycled).
// find a way to update feedInfoList,
// I like to use EventBus to send an event to the
// host activity/fragment like so:
EventBus.getDefault().post(
new UpdateFeedInfoListEvent(getAdapterPosition(), numInterested));
// in your host activity/fragment,
// update the list and call
// notifyDatasetChanged/notifyDataUpdated()
//on this RecyclerView adapter accordingly
});
}
}
Don't set your position in onBindViewHolder to final (Android Studio will warn you why).
I'm not sure how the object FeedInfo looks like but you could also at a method called for example increaseNumberOfInterested() which would increase the value of Number_of_interested by one and would persist in the object when the recyclerview recycle the cell. it would like kind of like below
#Override
public void onBindViewHolder(final FeedViewHolder contactViewHolder, final int i) {
final FeedInfo ci = feedInfoList.get(i);
//Set the text of the feed with your data
contactViewHolder.numberOfInterestedText.setText(ci.getNumber_of_interested());
contactViewHolder.interestedButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//Increase the number of interested in the object, so it can be persisted when cell is reclycled
ci.setNumberOfInterested(ci.getNumber_of_interested()) + 1);
//Get new value and display
contactViewHolder.numberOfInterestedText.setText(Integer.toString(ci.getNumber_of_interested()));
}
I am facing a Firebase RecyclerView problem where I cannot remove unwanted CardViews from my RecyclerViews. In my code I check the city's name and the guide's chosen city to match them. It populates guide's details only if the guide's city matches the picked city, but it also shows empty cardview with default layout.
guideDataRef = FirebaseDatabase.getInstance().getReference().child("Guides");
public void recycler() {
super.onStart();
try {
//Guide RecyclerView
Query guideQuery = guideDataRef.orderByKey();
guideQuery.keepSynced(true);
FirebaseRecyclerOptions guideOptions =
new FirebaseRecyclerOptions.Builder<UserModelClass>().setQuery(guideQuery, UserModelClass.class).build();
guideAdapter = new FirebaseRecyclerAdapter<UserModelClass, guideViewHolder>(guideOptions) {
#Override
protected void onBindViewHolder(#NonNull guideViewHolder holder, final int position, #NonNull final UserModelClass model) {
String pickedcity = model.getPickedCity();
String postname = (String) cityName.getText();
if(pickedcity.equals(postname)) {
final String guide_key= getRef(position).getKey();
holder.setGuideName(model.getName());
holder.setGuideSurname(model.getSurName());
holder.setGuideImage(getApplicationContext(), model.getPhotoURL());
// holder.mView.setVisibility(View.VISIBLE);
//Guide Click listener
holder.mView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent guideHireIntent = new Intent(getApplication(), GuideHireActivity.class);
guideHireIntent.putExtra("guide_id", guide_key);
finish();
startActivity(guideHireIntent);
}
});
}
}
#NonNull
#Override
public guideViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_layout_guides, parent, false);
return new guideViewHolder(view);
}
#Override
public void onError(DatabaseError e){
Toast.makeText(getApplicationContext(), "Error by stopping ", Toast.LENGTH_SHORT).show();
}
#Override
public int getItemCount() {
return super.getItemCount();
}
#Override
public void onDataChanged() {
super.onDataChanged();
notifyDataSetChanged();
}
};
guideAdapter.notifyDataSetChanged();
guideRecyclerView.setAdapter(guideAdapter);
guideAdapter.startListening();
} catch (DatabaseException e) {
Toast.makeText(this, "Error", Toast.LENGTH_SHORT).show();
}
}
enter image description here
enter image description here
I can change the adapter visibility to gone if it does not match with the requirements but the problem is that after making it's visibility gone it is still there holding the place (but invisible - there's still an empty space). How can I avoid populating an item from the recycler view completely, instead of making it invisible if the requirements do not match?
You're not showing what guideDataRef is in your code, so I'm assuming that it's just aDatabaseReference object for everything beneath a \Guides node.
If you're doing that, you're going to get a call for onBindViewHolder for every child at that particular location. This means that you're going to be asked to make a view for every child. You cannot choose whether or not a view will appear for that item.
It looks like you're assuming that your if statement in onBindViewHolder method will skip over those items. But what's actually happening is that you're simply allowing an empty view to occupy that spot in the list.
Instead, you should come up with a query that generates only the items of interest to your list. This means you'll have to tell Firebase to filter for children that meet your criteria.
You can also read the entire contents of the location, manually filter out the items you don't want, and build a list of items you do want. You can then build an custom adapter with that list, and it can then become the input to a ListView or even better to a RecyclerView.
Hi I'm working at my first bigger app in android studio "FlashCards". I would like it to work so after you click on the button the flashcard's textview changes its text to next random flashcard untill you see all of the them how can i do something like 'continue' to my loop from inside onClick method.
here's the loop's code:
while(i < mTestDeck.size()) {
// generates random number which will represent position in deck.
int random = randomGenerator.nextInt() % mTestDeck.size();
// if random flashcard was already shown create random number again
if (mTestDeck.get(random).wasShown())
continue;
//text view that we will operate on
TextView deckTextView = (TextView) findViewById(R.id.flashcard_text_view);
// set text
deckTextView.setText(mTestDeck.get(random).getFront());
// set mWasShown to true
mTestDeck.get(random).flashcardShown();
Button myButton = (Button) findViewById(R.id.know_answer);
myButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
mTestDeck.correctAnswer();
}
});
myButton = (Button) findViewById(R.id.dont_know_answer);
myButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
}
});
}
}
First, this way, you have a potential infinite loop. And if it can happens, it will happens! It's not a good idea to "get random item and check if it's ok or try again".
I think that it's better to keep a list with all items in a random order. You just have to iterate over it.
Something like:
int currentPosition = 0;
List<Card> items = new ArrayList<Card>(mTestDeck).shuffle();
// Call this method once in onCreate or anywhere you initialize the UI
private void function setCurrentCard() {
Card currentItem = items.get(currentPosition);
[...] // Set all UI views here
myButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (currentPosition > items.size) {
// TODO? End?
return;
}
currentPosition++;
setCurrentCard();
}
});
}