This is how i add shared preferences
ct = sp.getInt("count", 0);
if (ct > 0) {
for (int i = 0; i <= ct; i++) {
list.add(sp.getString("Value[" + i + "]", ""));
}
}
adp = new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1, list);
Listtt.setAdapter(adp);
btnad.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
sped.putString("Value[" + ct + "]", editText.getText().toString());
sped.commit();
list.add(sp.getString("Value[" + ct + "]", ""));
ct += 1;
sped.putInt("count", ct);
adp.notifyDataSetChanged();
}
});
And by this i can successfully delete Sharedprefrences Value and remove it from list
sp.edit().remove("key_to_remove").apply();
adp.remove("name_to_rmv");
adp.notifyDataSetChanged();
Now my problem is that it leaves the blank space when i call it back just like closing activity and opening it again the value i have deleted has the blank space . Just like this image below i have deleted " two " but when i close and open my application it gives me blank space
how i fill adapter
ct = sp.getInt("count", 0);
if (ct > 0) {
for (int i = 0; i <= ct; i++) {
list.add(sp.getString("Value[" + i + "]", ""));
}
}
adp = new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1, list);
Listtt.setAdapter(adp);
.
I've met the same problem. I figured out a way to do this. This may not be the best way but it do what needs to be done. You will have to
decrease each and every value after the deleted value in SP by 1
if you have values in sp like
"value[0]","one"
"value[1]","two"
"value[2]","three"
"value[3]","four"
after deleted "value[1]", it would be
"value[0]","one"
"value[2]","three"
"value[3]","four"
(that's why it returns null string when you try to fetch "value[1]" because there are no such a value)
so make them a continues by inserting "value[1]". That means modify your existing value ("value[2]","three") as ("value[1]","three"). and apply this to other values also. you can simply do this by with a for loop. Then your final values would be like this.
"value[0]","one"
"value[1]","three"
"value[2]","four"
As you can see there won't be any blank spaces when you reading back. You will have to decrease counter by 1 because now there are only 3 values.
void deleteItem(int element_num,int counter,SharedPreferences sp,ArrayAdapter<String> adp){
//element_num is the element number that you want to delete
String name_to_rmv=sp.getString("Value[" + element_num + "]", ""); //backup the value that needs to be deleted
SharedPreferences.Editor editor=sp.edit();
for(int i=element_num;i<counter;i++)
editor.putString("Value[" + i + "]", sp.getString("Value[" + (i+1) + "]", "")); //read i+1 value and store it to i
counter--; //decrease counter
editor.putInt("count", counter);
editor.commit();
adp.remove(name_to_rmv);
adp.notifyDataSetChanged();
}
Related
how can I limit the number of checked checkboxes in android? I have multiple checkboxes being added programatically and it's difficult to keep track of them.
here's the code used to add them:
final CheckBox currentVariantCheckbox = new CheckBox(getApplicationContext());
checkBoxGroupList.add(currentVariantCheckbox);
Log.d(TAG, "onDataChange: added " + currentVariantCheckbox + " to the checkboxgrouplist; size = " + checkBoxGroupList.size());
currentVariantCheckbox.setChecked((Boolean) currentVariant.child("checked").getValue());
LinearLayout checkboxGroupLayout = new LinearLayout(getApplicationContext());
checkboxGroupLayout.setOrientation(LinearLayout.HORIZONTAL);
currentVariantCheckbox.setText(currentVariant.child("name").getValue(String.class));
TextView currentVariantPriceTag = new TextView(getApplicationContext());
checkboxGroupLayout.addView(currentVariantCheckbox);
if (currentVariant.child("price").exists()) {
currentVariantPriceTag.setText("+" + currentVariant.child("price").getValue(float.class).toString() + " €");
checkboxGroupLayout.addView(currentVariantPriceTag);
ok so instead of using a onCheckedStateChangedLister I used OnClickListener. And I created an ArrayList to keep track of all the checked checkboxes:
final ArrayList<CheckBox> checkedList = new ArrayList<>();//this is the list to keep track of checked checkboxes
int maxOptions = 3
int minOptions = 1
currentVariantCheckbox.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Boolean currentCheckState = currentVariantCheckbox.isChecked();
if (currentCheckState) {//if the clicked checkboxes was unchecked and is now checked
checkedList.add(currentVariantCheckbox);
Log.d(TAG, "onClick: added " + currentVariantCheckbox + " ;checkedList.size is now: " + checkedList.size());
if (checkedList.size() >= maxOptions) {
checkedList.get(0).setChecked(false);
checkedList.remove(0);// if limit exceeded remove the first element from the checked list
Log.d(TAG, "onCheckedChanged: checkedList's size is now: " + checkedList.size());
}
} else if (checkedList.size() <= minOptions) {
currentVariantCheckbox.setChecked(true);
// if the list is empty just add the clicked checkbox to the list for example here 0
// and it will be checked automatically
} else {
checkedList.remove(currentVariantCheckbox);
// if the checkbox was already checked and no limit is exceeded
// then it will be unchecked therfore it should be removed from checkedList
}
}
});
I am populating new data in my RecyclerView adapter all at once, so there are no insert or remove one item actions.
So simply, i have an old list and when some Event occurs i get the new list and i can assign the new list to the old.
Problems are i cannot make properly the animation for each item in the old list
when item has new position in the new list (should notifyItemMoved from old position to new)
when there is a new item in the new list (should notifyItemInserted with that position in the new list)
when the old item is not present in the new list (should notifyItemRemoved with that position)
Here is something i have now, which i thought will work for first case - item move to new position:
if(currentAdapterData!= null){
for(int i = 0; i < currentAdapterData.size(); i++){
for(int j = 0; j < newData.size(); j++){
if(currentAdapterData.get(i).getSomeIdentifier().equals(newData.get(j).getSomeIdentifier())){
Log.v("same item", "currentAdapterData index :" + i + " ," + currentAdapterData.get(i).getSomeIdentifier() + " == newData index: " + j + " ," + newData.get(j).getSomeIdentifier());
if(i != j){
notifyItemMoved(i, j);
}
}
}
}
}
currentAdapterData = newData;
However it does not work as expected, and there is difference between logs(which are correct) and the list appearing on the phone(with wrong items positions, some duplicates, buggy etc.)
So how can i make it work? With notifyItemMoved, notifyItemInserted and notifyItemRemoved?
I don't want to just use NofifyDataSetChanged, because it refresh the entire list instead of just updating the items with animations that have changed.
It looks like that your new data is also a form of list, not a single item. I think this could be a good candidate for using DiffUtil in the support library.
Here is also a nice tutorial for it.
It will allow you to calculate the difference in the new data and only update needed fields. It will also offload the work asynchronously.
You just need to implement a DiffUtil.Callback to indicate if your items are the same or the contents are the same.
You update your recyclerView like that:
DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(diffCallback);
diffResult.dispatchUpdatesTo(yourAdapter);
Simply use DiffUtil like
final MyDiffCallback diffCallback = new MyDiffCallback(prevList, newList);
final DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(diffCallback);
Create a Callback by extending MyDiffCallback and override methods and do as needed.
public class MyDiffCallback extends DiffUtil.Callback
// override methods
Well for this ,I feel this would be the easiest.Just follow it ->
Replace this
if(currentAdapterData!= null){
for(int i = 0; i < currentAdapterData.size(); i++){
for(int j = 0; j < newData.size(); j++){
if(currentAdapterData.get(i).getSomeIdentifier().equals(newData.get(j).getSomeIdentifier())){
Log.v("same item", "currentAdapterData index :" + i + " ," + currentAdapterData.get(i).getSomeIdentifier() + " == newData index: " + j + " ," + newData.get(j).getSomeIdentifier());
if(i != j){
notifyItemMoved(i, j);
}
}
}
}
}
currentAdapterData = newData;
with
if(currentAdapterData!= null){
for(int i = 0; i < currentAdapterData.size(); i++){
for(int j = 0; j < newData.size(); j++){
if(currentAdapterData.get(i).getSomeIdentifier().equals(newData.get(j).getSomeIdentifier())){
Log.v("same item", "currentAdapterData index :" + i + " ," + currentAdapterData.get(i).getSomeIdentifier() + " == newData index: " + j + " ," + newData.get(j).getSomeIdentifier());
if(i != j){
notifyDataSetChanged();
new CountDownTimer(250, 250) {
#Override
public void onTick(long millisUntilFinished) {
Log.d("millisUntilFinished", "" + millisUntilFinished);
}
#Override
public void onFinish() {
notifyItemMoved(i, j);
}
}.start();
}
}
}
}
}
this will update the values and after 250 millisecond(1/4th a second),the value with be moved with animation.
i have looked at various things to try and resolve this, however there is something i am missing with the onCreate or something.
i can move between portrait and landscape no problem and i can even save some of the data. my problem is in certain spinners.
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt("NS1", ns1.getSelectedItemPosition());
outState.putInt("NS2", ns2.getSelectedItemPosition());
outState.putInt("NS3", ns3.getSelectedItemPosition());
outState.putInt("NS4", ns4.getSelectedItemPosition());
outState.putInt("NS5", ns5.getSelectedItemPosition());
outState.putInt("NS6", ns6.getSelectedItemPosition());
outState.putInt("AS", announcespinner.getSelectedItemPosition());
outState.putInt("FS", feastselectorspinner.getSelectedItemPosition());
outState.putInt("CS", choirspinner.getSelectedItemPosition());
outState.putInt("SS", saintspinner.getSelectedItemPosition());
outState.putBoolean("AK", akonly.isChecked());
outState.putBoolean("PK", pkonly.isChecked());
}
#Override
protected void onRestoreInstanceState(Bundle savedInstanceState){
feastselectorspinner.setSelection(savedInstanceState.getInt("FS"));
pkonly.setChecked(savedInstanceState.getBoolean("PK"));
akonly.setChecked(savedInstanceState.getBoolean("AK"));
//savedInstanceWait = false;
//updateNewSongSpinners();
ns1.setSelection(savedInstanceState.getInt("NS1"));
ns2.setSelection(savedInstanceState.getInt("NS2"));
ns3.setSelection(savedInstanceState.getInt("NS3"));
ns4.setSelection(savedInstanceState.getInt("NS4"));
ns5.setSelection(savedInstanceState.getInt("NS5"));
ns6.setSelection(savedInstanceState.getInt("NS6"));
saintspinner.setSelection(savedInstanceState.getInt("SS"));
choirspinner.setSelection(savedInstanceState.getInt("CS"));
announcespinner.setSelection(savedInstanceState.getInt("AS"));
}
it updates everything except the nsx spinners. i believe it has somethign to do with the fact these are changeable.
if you check/uncheck the pkonly or akonly checkboxes or select a different selection in feastselectorspinner, then the nsx spinner adjust based on the database query which is performed below
private void updateNewSongSpinners(){
if(!savedInstanceWait){
db = new DatabaseHandler(Announcer.this);
List<NewSong> listnewsong = db.getAkOrPkOrFeastSongs(akonly.isChecked(), pkonly.isChecked(), feastselectorspinner.getSelectedItem().toString());
List<String> list = new ArrayList<String>();
String t;
list.add("Select New Song");
for(NewSong lns : listnewsong){
t = "";
if(lns.getSongNum() < 10){
t = "00";
}else if(lns.getSongNum() < 100){
t = "0";
}
t += Integer.toString(lns.getSongNum()) + " " + lns.getSongTitle();
list.add(t);
}
ArrayAdapter<String> adapter = new ArrayAdapter<String>(Announcer.this, R.layout.list_item, list);
adapter.setDropDownViewResource (android.R.layout.simple_spinner_dropdown_item);
//reset all spinners
ns1.setAdapter(adapter);
ns2.setAdapter(adapter);
ns3.setAdapter(adapter);
ns4.setAdapter(adapter);
ns5.setAdapter(adapter);
ns6.setAdapter(adapter);
}
}
What am i missing that is preventing the nsx spinners from going back to their saved position. the NS1...NS6 values retrieved are the correct numbers. i cannot debug this because it wont debug on my phone and my emulator when i switch between portrait and landscape the emulator does not do anything.
the savedInstanceWait was used to see if there was a race condition. i could not find one.
i am at a loss. apparently the feastselectorspinner onClick() is being called after the onRestoreInstanceState(). which is causing the spinners to reset obviously. i do not know why the feastselectorspinner calls its function and none of the others do to reset their fields, but anyways. here is the fix which i would still like to know why it was calling the onclick() after the restore()
private void updateNewSongSpinners(){
String str1, str2, str3, str4, str5, str6;
str1 = ns1.getSelectedItem().toString();
str2 = ns2.getSelectedItem().toString();
str3 = ns3.getSelectedItem().toString();
str4 = ns4.getSelectedItem().toString();
str5 = ns5.getSelectedItem().toString();
str6 = ns6.getSelectedItem().toString();
db = new DatabaseHandler(Announcer.this);
List<NewSong> listnewsong = db.getAkOrPkOrFeastSongs(akonly.isChecked(), pkonly.isChecked(), feastselectorspinner.getSelectedItem().toString());
List<String> list = new ArrayList<String>();
String t;
list.add("Select New Song");
for(NewSong lns : listnewsong){
t = "";
if(lns.getSongNum() < 10){
t = "00";
}else if(lns.getSongNum() < 100){
t = "0";
}
t += Integer.toString(lns.getSongNum()) + " " + lns.getSongTitle();
list.add(t);
}
ArrayAdapter<String> adapter = new ArrayAdapter<String>(Announcer.this, R.layout.list_item, list);
adapter.setDropDownViewResource (android.R.layout.simple_spinner_dropdown_item);
//reset all spinners
ns1.setAdapter(adapter);
ns2.setAdapter(adapter);
ns3.setAdapter(adapter);
ns4.setAdapter(adapter);
ns5.setAdapter(adapter);
ns6.setAdapter(adapter);
//if available keep previously chosen song
for(int i = 0; i < list.size(); i++){
if(list.get(i).equals(str1)) ns1.setSelection(i);
if(list.get(i).equals(str2)) ns2.setSelection(i);
if(list.get(i).equals(str3)) ns3.setSelection(i);
if(list.get(i).equals(str4)) ns4.setSelection(i);
if(list.get(i).equals(str5)) ns5.setSelection(i);
if(list.get(i).equals(str6)) ns6.setSelection(i);
}
}
hi i have problem in displaying a value into my TextView..
For example i will input 1,2,3,4 then i like to display the output in this manner in my TextView..How can i do that? please help me, thank you in advance
1 appeared 1 times
2 appeared 1 times
3 appeared 1 times
4 appeared 1 times
here's my code:
String []values = ( sum.getText().toString().split(","));
double[] convertedValues = new double[values.length];
Arrays.sort(convertedValues);
int i=0;
int c=0;
while(i<values.length-1){
while(values[i]==values[i+1]){
c++;
i++;
}
table.setText(values[i] + " appeared " + c + " times");
c=1;
i++;
if(i==values.length-1)
table.setText(values[i] + " appeared " + c + " times");
Make your textView to support multipleLines and after that create in code a StringBuffer and append to it the results, something like
resultString.append(result).append(" appeared").append(c).append(" times\n");
after that you set text for textView like:
textView.setText(resultString.toString());
Here is the idea :
// this is test string, you can read it from your textView
String []values = ( "2, 1, 3, 5, 1, 2".toString().split(","));
int [] intValues = new int[values.length];
// convert string values to int
for (int i = 0; i < values.length; ++i) {
intValues[i] = Integer.parseInt(values[i].trim());
}
// sort integer array
Arrays.sort(intValues);
StringBuilder output = new StringBuilder();
// iterate and count occurrences
int count = 1;
// you don't need internal loop, one loop is enough
for (int i = 0; i < intValues.length; ++i) {
if (i == intValues.length - 1 || intValues[i] != intValues[i + 1]) {
// we found end of "equal" sequence
output.append(intValues[i] + " appeared " + count + " times\n");
count = 1; // reset count
} else {
count++; // continue till we count all equal values
}
}
System.out.println(output.toString()); // prints what you extected
table.setText(output.toString()); // display output
I'm facing a problem: I want to store a list then read/display it from a file !
In fact, the problem is when writing the list, it just writes it without any end of line or any conditions, code:
try {
fOut = context.openFileOutput(nom, Context.MODE_APPEND);
osw = new OutputStreamWriter(fOut);
for (int i = 0; i < list.size(); i ++ )
{
osw.write(list.get(i));
}
osw.flush();
osw.close();
fOut.close();
Data stored:
data = date + " : " + ans + " L/100km\n" + litre + " litres "+ km + " km\n";
ListView L = (ListView) findViewById(R.id.lv);
ArrayAdapter adapter = new ArrayAdapter(this, R.layout.list_item, list);
L.setAdapter(adapter);
Can i modify this line osw.write(list.get(i));or add another line(s) to make an end of line after every data!
Thank you.
osw.write(list.get(i) + "\n"); should do the job.
To add line break every X lines, you can modify your for loop this way:
for (int i = 0; i < list.size(); i ++ )
{
osw.write(list.get(i));
if ((i+1) % X == 0) // change X to desired number
{
osw.write("\n");
}
}