I am trying to learn retrofit and I have made successful attempts at posting data and now I am trying to retrieve JSON array which looks as follows:
{
"result": "success",
"message": "All Questions Have Been Selected",
"question": {
"all_question_ids": ["1","2","3"]
}
}
I am using the following getter
public ArrayList getAll_question_ids(){
return all_question_ids;
}
I am retrieving using Retrofit as follows
if (resp.getResult().equals(Constants.SUCCESS)) {
SharedPreferences.Editor editor = pref.edit();
Log.d("Question_IDs", "getAllQuestionID() = " + response.body().getQuestion().getAll_question_ids() );
editor.putString(Constants.All_QUESTION_IDS,((resp.getQuestion().getAll_question_ids().toString())));
editor.apply();
}
progress.setVisibility(View.INVISIBLE);
It is here that I am stuck, as I am retrieving the array ok but I am unsure how to loop out the Array which is now stored in Shared Preferences.
When I place a toast to show me how the IDs are coming across, my toast confirms the data as [1,2,3]
The goal is to add a dynamic button and the individual ID, i.e button 1, button 2 etc every-time the loop is iterated.
I have tried the following:
String questionNumber = pref.getString(Constants.All_QUESTION_IDS, "");
for (int i =0; i < questionNumber.length(); i++) {
try {
/*Dynamically create new Button which includes the question name
*/
AppCompatButton btn_question = new AppCompatButton(getActivity());
/*LayoutParams (int width, int height,float weight)
As LayoutParams is defaulted in px, I have called a method called dpToPX to make sure
the dynamically added EditText is the same size on all devices.
*/
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(dpToPx(280), dpToPx(45), 1);
btn_question.setBackgroundColor(Color.parseColor("#3B5998"));
btn_question.setTextColor(Color.WHITE);
// btn_question.setText(String.valueOf(x));
btn_question.setText("Question "+ pref.getString(Constants.All_QUESTION_IDS,""));
btn_question.setGravity(Gravity.CENTER);
//generate unique ID for each new EditText dynamically created
View.generateViewId();
//Log.d("TEST VALUE", "Question1 generated ID = " + btn_question.generateViewId());
params.setMargins(0, dpToPx(10), 0, dpToPx(10));
btn_question.setPadding(0, 0, 0, 0);
btn_question.setLayoutParams(params);
allEds.add(btn_question);
mLayout.addView(btn_question);
} catch (Exception e) {
Log.d(TAG, "Failed to create new edit text");
}
}
However the above is adding the value as it appears in the array e.g [1,2,3] which is obviously not what I want.
I have added a photo in case my explanation isn't clear. I want a button with 1 number added to it each time the loop iterates but I am unable to figure this out.
I have looked through lots of resource but cannot find an answer that is relevant to my problem, although, if there is, I am not familiar enough to recognise a similar issue.
If someone can offer some assistance, I would appreciate it!
When you call editor.putString(Constants.All_QUESTION_IDS,((SOMETHING.toString())));, what is actually stored depends on the implementation of the toString method in the type of SOMETHING (in this case String[]). So avoid doing that. Instead, since you're already using Gson or Jackson (or others), store the question_idsas JSON:
final String jsonIds = gson.toJson (resp.getQuestion().getAll_question_ids());
editor.putString(Constants.All_QUESTION_IDS, jsonIds);
Your actual stored value no longer depends on the implementation of something that you don't control (String[].toString). It is a valid JSON array and regardless of what tool/library you use to read it back, it's valid.
Now, to read back the stored data:
final String storedJson = pref.getString(Constants.All_QUESTION_IDS, null);
if (null == storedJson) {
// TODO: No question ids found
}
final String[] ids = gson.fromJson (storedJson, String[].class);
for (int i = 0; i < ids.length; i++) {
// make your buttons
}
This is a problem of saving and then reading out a List of items (in this case, String instances).
You've chosen to save the list by calling editor.putString() with a value of getAll_question_ids().toString(). That toString() call is going to return a string representation of your list, or, in other words, a String instance with the value [1, 2, 3]. At this point, you no longer have a List proper, but a String that looks like a list.
This is all technically fine, but it means you have to take this into account when you're trying to read out that list.
You've written this to read the list back out:
String questionNumber = pref.getString(Constants.All_QUESTION_IDS, "");
Once this line executes, questionNumber will be a String instance with the value [1, 2, 3]. Again, this is fine, but now we come to the key point: we have to convert this String back into a List.
If you know for sure that the values in this list won't have commas in them, you can do it easily:
Trim the braces off the string using substring()
Create a String[] using split()
Convert your array to a list using Arrays.asList() (you could even skip this step since iterating over an array is just as easy as iterating over a list)
Put that together and you get:
String questionNumber = pref.getString(Constants.All_QUESTION_IDS, "");
questionNumber = questionNumber.substring(1, questionNumber.length() - 1);
String[] array = questionNumber.split(", ");
List list = Arrays.asList(array);
At this point, you can iterate over your array or list:
for (String value : list) {
...
btn_question.setText("Question " + value);
...
}
Related
Am doing one small android app. In that i have Expandable listview and am trying to populate data's from SQLite. So that i used HashMap to store parent(String) and child(ArrayList).
For eg I have four integer no's in parent(1, 2, 3, 4) i get this and stored in ListArray. Now i need to get child(ListArray) for that particular parent. Parent 1 contain (aa, bb), parent 2 contain (cc).. etc, now see this code
try
{
header = new ArrayList<String>();
footer = new ArrayList<String>();
child= new HashMap<String, List<String>>();
String date = null;
int count=0, countchild=0;
Cursor c = db.rawQuery("SELECT Date FROM Table", null);
if (c.moveToFirst())
{
do
{
date=c.getString(c.getColumnIndex("Date"));
header.add(date);
count=count+1;
} while (c.moveToNext());
}
for (int i = 0; i < count; i++)
{
String temp=header.get(i);
Cursor cc=db.rawQuery("SELECT Id FROM Table WHERE Date ='"+ temp +"' ", null);
if(cc.moveToFirst())
{
do
{
countchild=countchild+1;
String id=cc.getString(cc.getColumnIndex("Id"));
//footer.clear(); // it clear all data's on child
footer.add(id);
Log.d("Footer date count", "" + countchild);
child.put(temp, footer);
}
while (cc.moveToNext());
//footer.clear(); // it clear all data's on child
}
footer.clear(); // it clear all data's on child
}
}
I want to clear footer here after adding it to child then only i will get proper Expandable listview. If i remove/comment this footer.clear() line then all child's are added to all parents. eg parent 1 contain (aa, bb, cc, etc) and parent 2 contain (aa, bb, cc, etc). If i leave this footer.clear() line then all child's are cleared and display only parent like this eg Parent 1(), Parent 2()... etc
How to clear this footer(ListArray) after adding it to HashMap ?? or tell me some suggestion to modify this code.
Thank you. Srihari
When you put the ArrayList to the HashMap, the HashMap actually saves a reference to your array, not a copy.
That's why you must use different arrays for each group:
for (int i = 0; i < count; i++)
{
List<String> children = new ArrayList<String>();
String temp = header.get(i);
Cursor cc = db.rawQuery("SELECT Id FROM Table WHERE Date ='"+ temp +"' ", null);
if(cc.moveToFirst())
{
countChild += cc.getCount();
Log.d("Footer date count", "" + countchild);
do
{
String id = cc.getString(cc.getColumnIndex("Id"));
children.add(id);
child.put(temp, children);
}
while (cc.moveToNext());
}
}
As you can see a new children ArrayList here is created for each group and it's never cleared as that would clear the values from HashMap also.
Furthermore I've let myself fix a few other things like using Cursor's getCount method, to get the count instead of looping. Also I'm not using the footer array as it's unnecessary in the code you've shown.
Lastly, please use understandable and meaningful names for your variables as it can help you as well as others who read your code.
Remember Java is OO so if you clear an instance of an object, in this case an ArrayList, every other object referencing to it will get that new value.
What I recommend is you create a new instance of your footer variable everytime you need to fill a new group of your expandable list view, that way every footer list instance you create will be "associated" with one group in your list.
Hope this helps. :)
I have three ArrayLists, two are Strings and the last one is an Integer.
The first ArrayList contains the specific Variant (variantArray) for a certain Product like the flavor variant of a cola, the second one contains the Unit (unitArray) that contains the unit like the size (80oz, 500mL, 1L) of the product, and the last one is the quantity *(quantityArray).
This is the class I use.
public class CurrentOrderClass {
//ArrayLists
private ArrayList<String> variantArray = new ArrayList<String>();
private ArrayList<String> unitArray = new ArrayList<String>();
private ArrayList<Integer> quantityArray = new ArrayList<Integer>();
//TODO ArrayList functions
public ArrayList<String> getUnitArray() {
return unitArray;
}
public void setUnitArray(ArrayList<String> unitArray) {
this.unitArray = unitArray;
}
public void addToUnitArray(String unit){
this.unitArray.add(unit);
}
public ArrayList<Integer> getQuantityArray() {
return quantityArray;
}
public void setQuantityArray(ArrayList<Integer> quantityArray) {
this.quantityArray = quantityArray;
}
public void addToQuantityArray(int quantity){
this.quantityArray.add(quantity);
}
public ArrayList<String> getVariantArray() {
return variantArray;
}
public void setVariantArray(ArrayList<String> variantArray) {
this.variantArray = variantArray;
}
public void addToVariantArray(String variantArray){
this.variantArray.add(variantArray);
}
#Override
public String toString() {
return "[ product=" + productName + ", variants=" +
variants + " , unit=" + unit + " , quantity=" + quantity + "]";
}
}
I take in user input so the user chooses the Variant, Unit, and Quantity and the input is then stored in their respective ArrayLists.
However, I'm having a problem updating the ArrayLists when the user inputs a Variant and a Unit that already exists in the ArrayLists but only with a different Quantity. What I want to do is not to add the new entry, but update the current ArrayLists in such a way that when the user inputs a variant and a unit but different quantity, I'd only update the quantity.
The first thing I tried was to see if the input already exists in the ArrayList by using indexOf(userInputVariant) and then check if it matches with a indexOf(userInputUnit), this would mean that the user input repeated already. However, I don't think indexOf runs on that logic and the value it returns is the value where it found the first instance of the userInputVariant string.
The second attempt I tried was using a for each loop, however, I'm once again having a hard time returning the index I want properly.
I instantiate an object of the CurrentOrderClass named currentOrder and prepopulated the first 10 elements of its variantArray with "Grape"
After that, I tried this if-else statement:
if( (currentOrder.getVariantArray().indexOf(product.getVariant()[variantPosition]) ==
currentOrder.getUnitArray().indexOf(product.getUnit()[position])
However, as mentioned above, indexOf returns an int where it first found the String that I told it to find, I don't think it checks if it exists after that certain position.
The second code I tried was to use a for-each and return the position from there, but again, it only returned position = 0.
for( String Grape : currentOrder.getVariantArray() ){
Log.d("Angelo", "Retrived Element: " + Grape
+ " at position = " + currentOrder.getVariantArray().indexOf(Grape));
}
I'm currently thinking of running a for-each loop inside a for-each loop but I don't know how to make it return the proper position that I want.
Does anyone have an idea on how to make it work properly? I need to return the position of an item that appears multiple times in my variantArray by "cross-referencing" it with my unitArray. Thanks.
One for loop is enough in this case.
This will some thing like:
isExist = false;
for(index = 0; index<variantArray.size(); index++){
if(variantArray.get(index) == userChoiceVariant &&
unitArray.get(index) == userChoiceUnit){
//update quantity
isExist = true;
}
}
if(!isExist){
//insert order
}
The first solution I reach is: "Search all the indexes matching with the user input in the variant array, store this in another ArrayList<Integer>, name it, matchingVariants for now. Then, for each of the ints in matchingVariants get that position of the units list. If one of this items matches, then you should update, otherwise insert.
However, I think a better solution is wrap Variants and Units in one class, for example Product with attributes String variant and String unit. Implementing equals method you can forget about your variants and units lists and have only one ArrayList<Product>
As a next step, I would use a Map with Product as key and Integer as values. So I can just update the Map rather than having all the lists you have.
I want to save multiple files to my database one by one.
And what happen here using my codes is this:
What I want to happen is like this one:
here is my code:
//Arraylist for getting the multiple brand code
ArrayList<String> content = new ArrayList<String>();
for (int j=0; j<checkSelected.length; j++) {
if(checkSelected[j]==true) {
String values = BrandListAdapter.mListItems.get(j);
//content.add(values);
Cursor rSubBrand = databaseHandler.getReport_SubBrandCode(values);
String SubBrandCode = rSubBrand.getString(rSubBrand.getColumnIndex(Constants.SUBBRAND_CODE));
content.add(SubBrandCode);
//Casting and conversion for SubBrand Code
String subBrand = content.toString();
//SAVE SUBBRAND
databaseHandler.SaveSubBrand(new Cons_iReport (ReportCode, subBrand));
Toast.makeText(getApplicationContext(), subBrand, Toast.LENGTH_LONG).show();
}
}
Mistakes:
content.add(SubBrandCode);
do you know how to remove the '[ ]' in the saved data? (e.g. [AC001]) All I want to save is the AC001 only.
Solutions:
Call clear() method of ArrayList before adding new values into it.
Its giving you [AC001] as you are subBrand by doing content.toString();. Don't convert it to string, instead use content.getString(position) and it will give you String value.
im using MultiSelectListPreference and the values save on array..
How can read??
SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(this);
Set<String> a = pref.getStringSet("tabs", null);
for ( int i = 0; i < a.size(); i++) {
Log.d("salida", a[i]);
}
i get this error: The type of the expression must be an array type but it resolved to Set
You want to use the Set, and since it isn't an array, the square brackets ([])are cannot be used to access indexes.
To easily read the values from the Set,use the enhanced for loop:
for (String str: a){
Log.d("salida", str);
}
If you want to remove items from that Set as you loop through, you will have to use an Iterator, as shown in this answer.
Alternatively, if you want an array, you can use Set#toArray():
String [] prefStrings = a.toArray(new String[a.size()]);
Then you can use the square brackets (prefStrings[position]) to access an index.
I would like to see if I can avoid a lengthy switch or if block by directly converting some strings into an object name. For example, I have a class called Example and I want to [edit] have up to 10 instances of the class Example1, Example2, so on. Can I use something like:
int ExampleNum = 2;
// can be changed to any 1-10 value corresponding to instances
String s = "Example" + String.valueOf(ExampleNum);
Refresh(s);
public void Refresh(Example example){
...
}
Thus I would create a string with the value of Example2 and pass that to my Refresh method.
[edit]
I don't want to use all the instances at once, but rather have other methods that change the int ExampleNum so that when I try to refresh it refreshes the appropriate Example instance.
Rather than saying:
if (ExampleNum == 2)
Refresh(Example2);
I would use the ExampleNum and String to use the right instance name;
Why not use array's instead??
Example[] e = null;
for(int i=1;i<=10;i++)
{
e[i] = new Example();
Refresh(e[i]);
}
Well, your code, as it stands now, doesn't make any sense since you're passing a String to Refresh, which takes an Example object as an argument.
However, if you're asking how you can create the strings Example1, Example2, ... Example 10, you can do this:
for (int i = 1; i <= 10; i++) {
s = "Example" + i;
refresh(s); // assuming this takes a string
}