I have a Room Database table with multiple columns (PartsTable). I need to fetch only one column from the table that contains one word String and I'm using a subset of a table as per google docs (PartsTuple).
Now I need to create a function that will or something else that will return the ArrayList of fetched data, which I can access in my adapter class. I am able to return the data and see it in a console log (from the main fragment where I get data from ViewModel), but I just can't seem to make it work on a function that will return the said list of data which I could then access from a different class.
Code from DAO:
#Query("SELECT keyword FROM partsTable")
LiveData<List<PartsTuple>> getTuple();
Code from repo:
public LiveData<List<PartsTuple>> getPartsTuple() {
return partsKeyword;
}
Code from view model:
public LiveData<List<PartsTuple>> getPartsTuple() {
return partsKeyword;
}
Fragment class where I display data in a log:
mViewModel.getPartsTuple().observe(getViewLifecycleOwner(), new Observer<List<PartsTuple>>() {
#Override
public void onChanged(List<PartsTuple> partTuple) {
Log.d(TAG, "vraceno: " + partTuple.toString());
}
});
, and data from the log
D/PartsFragment: vraceno: [part1, parts3, part_2]
Code from adapter class where I compare strings and highlight them.
ArrayTEST arrayTEST = new ArrayTEST();
ArrayList<String> values = arrayTEST.getWordFromHardcodedList();
String text = note.getPartsSubtitle();
Spannable textSpannable = new SpannableString(text);
for (int j = 0; j < values.size(); j++) {
//word of list
String word = String.valueOf(values.get(j));
//find index of words
for (int i = -1; (i = text.indexOf(word, i + 1)) != -1; i++) {
//find the length of word for set color
int last = i + word.length();
textSpannable.setSpan(new BackgroundColorSpan(Color.parseColor("#1a0cab8f")),
i, last, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
textSpannable.setSpan(new ForegroundColorSpan(Color.RED),
i, last, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
}
if (note.getPartsSubtitle().trim().isEmpty()) {
tvTEXT.setVisibility(View.GONE);
} else {
tvTEXT.setText(textSpannable);
}
The part that I'm having trouble with is this, where I need to get a list of data from database and not hardCoded like this
arrayTEST.getWordFromHardcodedList();
Now I need to access this list of data from my adapter class since if there is a match I wanna highlight the parts from the list of parts in my main recycler view where all the data is shown. I can do this when I type the list manually but it needs to be dynamic based on user input.
Thanks in advance
In your adapter class add a field for this list - I'll call it highlightedParts. Observe getPartsTuple() as you do, and set the data you get to highlightedParts. Then you need to create a custom setter for highlightedParts and every time it gets called, update elements of the RecyclerView to highlight the desired items. For updating, you can use notifyDataSetChanged() method. There are other, more optimized variations for only updating a specific item or item range, but you're going to have to update entire dataset.
Ended up using shared preferences with Gson.
In app gradle add
implementation 'com.google.code.gson:gson:2.8.6'
Save the data to SP in a fragment:
SharedPreferences sharedPreferences = requireActivity().getSharedPreferences("shared_preferences", MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPreferences.edit();
Gson gson = new Gson();
String json = gson.toJson(myListOfData);
editor.putString("partsKEY", json);
editor.apply();
Load the array in the adapter class:
SharedPreferences sharedPreferences = context.getSharedPreferences("shared_preferences", MODE_PRIVATE);
Gson gson = new Gson();
String json = sharedPreferences.getString("partsKEY", null);
Type type = new TypeToken<ArrayList<NoteTupleTest>>() {
}.getType();
partsArrayList= gson.fromJson(json, type);
if (partsArrayList== null) {
partsArrayList= new ArrayList<>();
}
Related
My app has to display a list of names on ListView. Those names are stored within Cloud Firestore in the following manner:
Collection: users - Documents: Organized by user UID - Field: name (I must note that there are other fields for each user too, however i need to retrieve the name field specifically)
To accomplish this, I have a first list that retrieves all documents or user UIDs. That first list is then used within a for loop to retrieve the name of each user in the users collection.
However, due to Firebase retrieving data asynchronously, some names are usually missing and they end up being displayed in a disorganized manner (not consistent with the order in which uids were passed from the first list).
If anyone could give me any insight on how to make Firebase wait for data to be retrieved before continuing with the for loop it would be greatly appreciated!
Below is some of my code to give you a better idea of what I am doing.
This first part of the code, which successfully retrieves all documents (uids) and puts them on a list
subTopicsDatabase.collection("schoolTopics").document(docKey).get().addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>() {
#Override
public void onComplete(#NonNull Task<DocumentSnapshot> task) {
if (task.isSuccessful()){
DocumentSnapshot document = task.getResult();
if (document.exists()) {
List<String> list = new ArrayList<>();
Map<String, Object> map = document.getData();
if (map != null) {
for (Map.Entry<String, Object> entry : map.entrySet()) {
list.add(entry.getValue().toString());
}
}
}});
The second part of the code, which doesnt work due to Firebase's asynchronous behavior.
for (int i = 0; i<list.size(); i++) {
String uid = list.get(i);
Toast.makeText(TutorsListActivity.this, uid, Toast.LENGTH_LONG).show();
subTopicsDatabase.collection("users").document(uid).get().addOnSuccessListener(new OnSuccessListener<DocumentSnapshot>() {
#Override
public void onSuccess(DocumentSnapshot documentSnapshot) {
if (documentSnapshot.exists()) {
String stName = documentSnapshot.getString("name");
ArrayAdapter<String> adapter = new ArrayAdapter<>(TutorsListActivity.this, R.layout.item_subtopic, testList);
adapter.notifyDataSetChanged();
sListView2.setAdapter(adapter);
}
}
});
}
You need to store the elements and in last of the for loop, you have to show the names list.
As you said you are getting a list of All UID's now you want their names on a list. I had updated your code to work.
// Create a Hashmap Object which has Key as UID and Name as Key
HashMap<String,String> hashMap = new HashMap<>();
for (int i = 0; i<list.size(); i++) {
final String uid = list.get(i);
Toast.makeText(TutorsListActivity.this, uid, Toast.LENGTH_LONG).show();
subTopicsDatabase.collection("users").document(uid).get().addOnSuccessListener(new OnSuccessListener<DocumentSnapshot>() {
#Override
public void onSuccess(DocumentSnapshot documentSnapshot) {
if (documentSnapshot.exists()) {
//Store Your UID and Name in Hashmap
String stName = documentSnapshot.getString("name");
hashMap.put(uid,stName);
}
//Check if it is last index of array then show the names list
if(i==list.size()-1){
showListInAdapter(hashMap);
}
}
});
}
private void showListInAdapter(HashMap<String,String> hashMap) {
//now convert your hashmap into a list of name and get Your Names List and show in Adapter
ArrayList<String> listOfNames = new ArrayList<>(hashMap.keySet());
//Set list to Adapter
ArrayAdapter<String> adapter = new ArrayAdapter<>(TutorsListActivity.this, R.layout.item_subtopic, listOfNames);
sListView2.setAdapter(adapter);
adapter.notifyDataSetChanged();
}
Your assertion that it doesn't work because of Firebase's asynchronous behavior is incorrect. The reason that your view is not displaying the way you want it to, is because you are updating your adapter every single time you receive a document back from Firebase.
In psuedocode, this is what should happen:
// Create function with completion block - i.e. fetchTopicNames
//
// Create array to hold fetched String values - i.e. topicNames
// For loop to request each document
// add String value to `topicNames`
// if current iteration is last iteration, finish forLoop and return topicNames
//
In another method, call your newly created method, update your adapter with your full list of topicNames. You can also then perform other operations on your Array like filtering and sorting. There is probably a more efficient way as well, I'm just giving you the most basic way to accomplish your task.
you can simulate fetching user synchronous by making recursion (function which call it self until index becomes bigger then size of list of uids).
So first thing you want to define adapter and List of strings (which represent user names). When you do that, you can call recursion, which will populate your List and notifyDataSetChanged. Here is the example
// Define empty list of user names, which you will populate later with recursion
List<String> userNames = new ArrayList<String>();
// Connect adapter with empty list
ArrayAdapter<String> adapter = new ArrayAdapter<>(TutorsListActivity.this, R.layout.item_subtopic, userNames);
// Set adapter to ListView
sListView2.setAdapter(adapter);
// Call recursion with list of uids and starting index of 0
getUserSync(list, 0);
private void getUserSync(List<String> list, int i) {
if (i < 0 || i > list.length - 1) {
// If index i is out of bounds for list, we break the recursion
return;
}
String uid = list.get(i);
Toast.makeText(TutorsListActivity.this, uid, Toast.LENGTH_LONG).show();
subTopicsDatabase.collection("users").document(uid).get().addOnSuccessListener(new OnSuccessListener<DocumentSnapshot>() {
#Override
public void onSuccess(DocumentSnapshot documentSnapshot) {
// When we load document, we fetch name and add it to the list which is connected to adapter
// After that, we call adapter.notifyDataSetChanged which will update ui
// When all that is done, we call getUserSync, to fetch user name for next uid
if (documentSnapshot.exists()) {
String stName = documentSnapshot.getString("name");
if (stName != null) {
userNames.add(stName);
adapter.notifyDataSetChanged();
}
}
getUserSync(list, i++);
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
// If enything goes wrong, we break the recursion
return;
}
});
}
If you have any troubles, feel free to comment..
I recommend that you follow the Guide to App Architecture and use a LiveData observer to keep the ListView updated. You can follow this tutorial and insert your Firebase access in the Repository class.
Changing your code to fit the MVVM pattern may require a bit of work but it will also make your app run better and simplify some development later.
I have a SQLite database that contains multiple tables. For each table, I am trying to represent all the data in an ExpandableListView using a custom CursorTreeAdapter. As far as I understand, the method getChildrenCursor returns a cursor that points to the data I needed to populate my child views. However, I do not have a concrete idea on how to retrieve the children cursor using the groupCursor parameter.
#Override
protected Cursor getChildrenCursor(Cursor groupCursor) {
String[] projection = { "columnNeeded" };
return context.getContentResolver()
.query(CONTENT_URI, projection, null, null, null);
}
the above method will return a cursor that returns all rows containing the column I need. Is this the right way to do this?
In the "columnNeeded" column for each row of the table, it contains a String representation of a jsonArray. I was trying to store an arrayList into each row of the table using JSONArray. Therefore, I am trying to retrieve this arrayList and populate the child views with this arrayList like so:
#Override
protected void bindChildView(View view, Context context, Cursor cursor, boolean isLastChild) {
TextView name = (TextView) view.findViewById(R.id.summary_child_name);
TextView bill = (TextView) view.findViewById(R.id.summary_child_bill);
String arrayListString = cursor
.getString(cursor.getColumnIndex("columnNeeded"));
JSONObject json = new JSONObject();
try {
json = new JSONObject(arrayListString);
} catch (JSONException e) {
Log.e(LOG_TAG, "Unable to retrieve list of items");
}
JSONArray jsonArray = json.optJSONArray(ReceiptContract.JSONARRAY_NAME);
// retrieveArrayList iterates through jsonArray and adds it to items
items = retrieveArrayList(jsonArray);
name.setText(What do I put here?);
bill.setText(What do I put here?);
}
As you can see I have managed to retrieve the entire array list as an ArrayList type object. However, I am stuck on displaying the array list in the child views. Any idea on how I can go about doing this?
Use HashMap to store your data as key value and populate your data into your ExpandableListView using BaseExpandableListAdapter
I have a spinner that has an item and a sub item, it's populated programatically with hashmaps. I need to be able to grab a value out of the selected item by its key. I've gotten as far as getting the entire hashmap out but I can't figure out how to get just the one value based on the key I need.
JSONArray recordsArray = json.getJSONArray("record");
for (int i = 0; i < recordsArray.length(); i++) {
JSONObject record = recordsArray.getJSONObject(i);
Map<String, String> datum = new HashMap<String, String>(2);
datum.put("code", record.getString("id") + " - " + record.getString("heading"));
datum.put("description", record.getString("body"));
spinneritems.add(datum);
adapter.notifyDataSetChanged();
spinner.setSelection(0);
populateList();
}
The above code shows how I populate my spinner, I then need to grab the value in the populateList() method.
Spinner was populated by an array of hashmaps. I used
String spinnerItem = spinneritems.get(spinner.getSelectedItemPosition()).get("key");
to get the value out of the hashmap at the index in the array I needed
I have to develop an one android application.
Here i have to get the list of items and set that list of item value in android spinner.
So i have using following code:
if (getIntent().getExtras() !=null) {
retailerNamesList = (ArrayList<RetailerNames>) getIntent().getExtras().getSerializable("RetailerName");
for (int i=0;i<retailerNamesList.size();i++) {}
mRetailerNameAdapter = new RetailerNamesAdapter(WatchList.this,retailerNamesList);
retailerlist.setAdapter(mRetailerNameAdapter);
}
Here i get the list of arraylist values in that spinner.but i have to split these values and set it in android spinner.please help me.how can i do ???
EDIT:
In the above code am getting the output like:
[com.example.RetailerNames#41216470]
But i need to get the output like:
String[] period_timings={"0-2 days","Within a Week","Within a Month"};
That list have to split and get the values in string[].How can i write the code for these ??? please provide me solution for these ???
for (int i=0;i<retailerNamesList.size();i++){
retailerNamesList.get(i);
}
or if you really have to create an array of it then
final int nameListSize = retailerNamesList.size();
String []names = new String[nameListSize];
for (int i=0;i<nameListSize ;i++){
names[i] = retailerNamesList.get(i);
}
// use the string array names to set wherever u need.
I've got an array coming in from a cursor in a function from a sqlite database. I'd like to add multiple items to the array to make it easier to bring data in from other pages. I.e. I'd like to do mArray("ID"), mArray("Name") (i'll be populating a listview from an array of the function, and would like to have easy access to name from ID)
Here is my code at the moment which only saves the ID in the array:
public static Array GetRooms(String StationID) {
File dbfile = new File(Global.currentDBfull);
SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(dbfile, null);
Cursor c = db.rawQuery("select * from StationObjects where ObjectID = 0 and StationID = " + StationID , null);
c.moveToFirst();
Log.e("TomDebug", c.getString(c.getColumnIndex("SubGroupName")));
ArrayList<String> mArrayList = new ArrayList<String>();
c.moveToFirst();
while(!c.isAfterLast()) {
mArrayList.add(c.getString(c.getColumnIndex("SubGroupName")));
c.moveToNext();
}
return null;
}
Edit: To give a bit of clarity;
In psudocode i'd like to be able to do:
while(!c.isAfterLast()) {
mArrayList.name.add(c.getString(c.getColumnIndex("Name")));
mArrayList.type.add(c.getString(c.getColumnIndex("Type")));
mArrayList.ID.add(c.getString(c.getColumnIndex("ID")));
c.moveToNext();
}
So that anywhere in the code i can do
Array curRooms = GetRooms("1234")
String name = curRooms.Name
String type = curRooms.Type
(i know the mix between array and string wont work there, but just an example)
It sounds like you want an actual data structure instead of a string. There are a few ways of doing this, with ORMs and whatnot, but a basic example would be something like this, that you can fill the fields in from the database.
public class StationObject
{
public String name;
public String type;
public String id;
}
//pseudocode
for each result in resultset
fill temp StationObject with fields
add temp to list