I have two activities that each contain fragments. Activity A has a fragment with a ListView. Rows of the ListView are obtained from a SQLiteDatabase.
Activity B contains a fragment that enables entries of the database to be edited. When a user edits a database entry, saves the data, then returns to Activity A via the backbutton or:
actionBar = getSupportActionBar();
actionBar.setDisplayHomeAsUpEnabled(true);
actionBar.setHomeButtonEnabled(true);
How do I notify the ListView in Activity A that there has been a change to the database? I understand how to communicate between an Activity and it's fragments, but how do I implement a notifydatasetchanged when the fragments are in two different activities?
I suspect that going back to Activity A via the back button is simply recalling the view from the stack, but that view has changed when there is a database change.
You could simply call the notifyDataSetChanged in onResume in your Activity A. So when you close or go back from Activity B to A, it will update the data. Don't forget to check if the adapter is different than null, otherwise it could crash the first time you open the App.
You could also make a public function in your Activity A which updates the list and call it from your Activity B.
class ActivityA
public static void updateList() {
if(adapter != null){
adapter.notifyDataSetChanged;
}
}
class ActivityB
ActivityA.updateList();
Hope it helps :)
you could start activity with startActivityForResult(start activityB) and override method onActivityResult in activityA and notifyDataSetChanged when needed.
You will need to read the updated dataset from your SQLite database and pass it adapter again. After you need to notify adapter. For example, like in the code below:
In your Activity A
#Override
protected void onResume() {
super.onResume();
// method to read new dataset
Database ourDB = new Database(this);
ourDB.openDB();
data = ourDB.getData();
ourDB.closeDB();
if(adapter == null) {
// initializes adapter when first launched
adapter = new RecyclerViewAdapter(data, this);
yourListView.setAdapter(adapter);
}
else {
// in subsequent returns to activity we are replacing
// old data with new and reusing existing adapter
adapter.updateData(data);
}
}
In your adapter class include similar method:
public void updateData(ArrayList<String> newData) {
data = newData;
this.notifyDataSetChanged();
}
Related
I am trying to update database on non UI thread, however changeListener registered on main thread (at the same time) sometimes not get called. Each Activity adds that listener when onStart method is called, and unregister on onStop.
Here is the simple application flow:
Activity1 contains a list of already create items. When user wants to add new item, Activity2 is launched. User fills all required fields and press add btn -> created item is added into local database with temporary ID, and job is added to queue to create that item on remote. After these two operations, Activit2 is closed (calling finish()) and user is back on Activity1 with list of all already created items (including the new one). Meanwhile, job for creating new item on remote is finished, and within its onRun() method, tmpID of created object is replaced with new one that was retrieved from server. However, at this point Activity1 do not get notified about change in database.
Activities register listener like this:
public Activity extends AppCompatActivity {
private Realm mRealm;
private RealmChangeListener listener = element -> Log.d("Called");
#Override
protected void onStart() {
super.onStart();
mRealm = Realm.getDefaultInstance();
mRealm.addChangeListener(realmChangeListener);
}
#Override
protected void onStop() {
super.onStop();
mRealm.removeChangeListener(realmChangeListener);
mRealm.close();
}
}
This is method of job, that is run on worker thread
#WorkerThread
public void onRun() {
Response<ItemResponse> response = mAPI.createItem(text).execute();
if(response.isSuccessful){
Realm realm = Realm.getDefaultInstance();
realm.executeTransaction(r ->{
Item i = r.where(Item.class).equalTo("id", tmpID).findFirst();
if(i != null){
i.id = response.body().id;
}
});
realm.close();
// At this point onChange() method of realmChangeListener should be fired
}
}
On the other side, if I would stay on Activity2(not calling finish() after item is added into local DB) and wait until job get finished, onChange() method of RealmChangeListener is called properly...
Both of threads runs on the same process.
I am thankful for any suggestions
EDIT
Activity1 has a fragment attached to it, an that fragment contains list of items.
Fragment then registers for listeners according to Best practises - Controlling the lifecycle of Realm instances within onStart and onStop callbacks.
#Override
public void onStart() {
super.onStart();
mRealm = Realm.getDefaultInstance();
mRealm.addChangeListener(realmChangeListener);
}
#Override
public void onStop() {
super.onStop();
mRealm.removeChangeListener(realmChangeListener);
mRealm.close();
}
Lifecycle of Fragment, when Activity2 is:
Launched
onPause
Closed using back button or by calling finish()
onStart
onResume
For some reason, when Activity2 is closed manually, using back button, realmChangeListener is called. However, if I close it using finish(), nothing happens ...
Finally, after a couple of hours I found out where the problem was...
Activity1 has a Fragment attached to it with list of items and that fragment listens for changes on realm database to update UI. When user wanted to add new item, Activity2 was launched and along with it a presenter, that was carrying about loading some stuff from local DB. That presenter was also listening on Realm DB.
And here is the problem:
When user added new item and Activity2 was about to finish, close() method was called on presenter to clear the resources. One of the commands that were called within close() method, was mRealm.removeAllChangeListeners(). That wouldn't be a problem as Fragment from Activity1 registers its listener again in onStart() callback, but close() method on presenter was called AFTER onStart() on Fragment. So, basically it removed newly registered listener from fragment.
Again, thank you guys for your willingness! #beeender, #EpicPandaForce
In my OnCreate method I am making a network call and populating a listview with the results. I am saving the result in an ArrayList and using the ArrayList to populate the listview. If the user presses the back button and reenters the activity I would like to store the ArrayLists in a SavedInstanceState Bundle and populate the ListView with the stored ArrayLists instead of making the network call a second time. The following is my OnCreate code:
if (savedInstanceState != null) {
largeImage = savedInstanceState.getParcelableArrayList("Image");
flowercode = savedInstanceState.getStringArrayList("Code");
flowerprice = savedInstanceState.getStringArrayList("Price");
flowerdimensions = savedInstanceState.getStringArrayList("Dimension");
largeImageText = savedInstanceState.getStringArrayList("Imagetext");
ListView listView = (ListView) findViewById(R.id.LowRomance);
FlowerShopAdapter listAdapter = new FlowerShopAdapter(this, flowercode, flowerName, flowerprice, largeImage, flowerdimensions);
listView.setAdapter(listAdapter);
} else if(savedInstanceState == null) {
makesoapcall();
}
}
This is my OnSaveInstanceState code
public void onSaveInstanceState(Bundle savedInstanceState) {
savedInstanceState.putParcelableArrayList("Image", largeImage);
savedInstanceState.putStringArrayList("Code", flowercode);
savedInstanceState.putStringArrayList("Price", flowerprice);
savedInstanceState.putStringArrayList("Dimension", flowerdimensions);
super.onSaveInstanceState(savedInstanceState);
}
Currently my App is making the network call every single time. Is their something else I need to implement in order to get this to work or is their an error in the current way I am trying to implement this? The ArrayList's are definitely not null when I put them into savedInstanceState.
onSaveInstanceState() is not supposed to be called when the back button is pressed on an Activity. It's called when Android decides to destroy the Activity.
e.g. When orientation changes.
What you need here is SharedPreferences. Store the ArrayLists using SharedPreferences in onStop(). And get it in onStart(). Here is how to store ArrayList in SharedPreferences.
I want to call a listview adapter from another activies after insert record to sqllite db.
I cant call the adapter.notifyDataSetChanged() method. What is the best way to do it.
public void onClick(View v) {
TextView item_name;
item_name=(TextView) findViewById(R.id.eItemName);
Log.d("Insert: ", "Inserting ..");
db.add_item(new Item(item_name.getText().toString()), getApplicationContext());
// I want to call the method HERE!!!!
finish();
}
Just
After finish() Current Activity, Call adapter.notifyDataSetChanged() from onActivityResult()in previous Activity (As I assumes your Listview in this previous Activity).
Also start your Current Activity from Previous Activity using startActivityForResult();
Or if you have reference of List Adapter in this Activity, then using that reference call adapter.notifyDataSetChanged(). (But I think its not a good practice)
The better option would be re-loading your ListView with new data inside onResume() of your Activity where you have ListView. There is no need to call notifyDataSetChanged() from another class as you don't have your List visible in your another Activity.
#Override
protected void onResume() {
super.onResume();
//fill your Collection with new data
// setAdapter or notify your adapter
}
I've got a ListView, an ArrayList. From activity1, I pass some data, e.g a price and a name of a company. This data will be stored in an ArrayList of Hashmaps. When I first passes some data to the second activity which holds the ListView the data will be found in this list, but when I go back to the first activity and pass some information again, the old data will still be in the list. Is there any possible way I can prevent this to happend? For instance, when I return from activity2 to activity1, the ListView will be wiped.
Thanks!
what you need to do:
on the activity which holds the listView - override the onResume() method:
#Override
protected void onResume() {
super.onResume();
mArrayList.clear();
mAdapter.notifyDataSetChanged();
}
if it's not good for you to clear the array list, so you can do the following:
#Override
protected void onResume() {
super.onResume();
mListView.removeAllViews();
}
I am currently developing an android app. The app has 2 activities. Activity 1 is a ListActivity. ListActivity calls a standard Activity. When the 2nd activity is finished, I use the finish() method to close the activitity which returns to the ListActivity. I need the ListActivity to now refresh with the new dat
You should just call notifyDataSetChanged() on your adapter when you return back to your activity.
The API states:
void notifyDataSetChanged()
Notifies the attached View that the
underlying data has been changed and
it should refresh itself.
Have you packaged the data into and intent? For that matter did you startActivityForResult()? If so the you would take the data out of the intent by overriding the onActivityResult(...) method and add the data to what ever you need to do. Then like sahhhm said notifyDataSetChanged().
~Aedon
You need reload the info in the ListView...
#Override
protected void onResume() {
super.onResume();
mAdapter= new mYCustomAdapter(mActivity.this, valuesReloaded);
mList.setAdapter(mAdapter);
mAdapter.myMethodThatNotifyChange();
}
where:
valuesReloaded is the new Array with the new Values.
mAdapter is a Custom Adapter
myMethodThatNotifyChange is a method in the Class MyCustomAdapter where you must call notifyDataSetChanged() , ( in a custom adapter can only call from the class adapter)
class myCustomAdapter extends BaseAdapter{
...
...
myMethodThatNotifyChange{
notifyDataSetChanged();
}
...
...
}
Or finish the actual activity, and reload with a new intent
#Override
protected void onResume() {
super.onResume();
Intent mIntet = new Intent(mlistViewPersons.this , mlistViewPersons.class)
startActivity(mIntent);
finish();
}