Notifying an ArrayAdapter of changes when closing a PreferenceActivity - android

I have a ListView that has some minor visual preferences that are set in a PreferenceScreen. These preferences are simple booleans to show or not to show some specific TextViews on each item in my ListView. Anyhow, when these preferences are changed, I need to notify my ArrayAdapter that the data has changed in order to get the list redrawn. However, doing this via an OnSharedPreferenceChangeListener wouldn't really be optimal because there are several preferences that you can change, that would cause an unnecessary amount of updates to the ArrayAdapter. So, to the question: How can I identify when my ListActivity has occurred on the screen after closing my PreferenceActivity, which I then could use to check for changes in the preferences, and only then notify the ArrayAdapter.
Edit: The ArrayAdapter being an inner class of my ListActivity, which is set as a ListAdapter.

There are several ways of doing it. As you noticed, the good way is to update your ListActivity when it becomes visible again.
To achieve that you can:
simply override onResume() method from your ListActivity. Method will be invoked when your activity comes to the foreground.
Another good solution would be to start your PreferenceActivity in such way:
//class member of your list activity
private static final int CODE_PREFERENCES = 1;
...
//running your preferences from list activity
Intent preferencesIntent = new Intent().setClass(this, YourPreferences.class);
startActivityForResult(preferencesIntent, CODE_PREFERENCES);
You also have to implement onActivityResult() in your list activity. This method will be invoked when preferences activity has been closed.
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == CODE_PREFERENCES) {
// notify your adapter that data has changed
}
}

PreferenceActivity extends Activity, so you can override onStop and there do those checks and notifications.

Related

Returning to activity after onActivityResult?

So, here's the scenario.
There is one EditText which has its own TextWatcher set, used for setting the word count.
I also have a Navigation Drawer, Sliding, and in that have an option which launches a new Activity for result.
The result I want is the Target number of words the user wants to achieve, and then get the result from the user input and calculate the perecentage of target recived and set it to the text of a TextView in the Main Activity.
Now, the problem is :
Navigation Drawer has it's own ItemClickListener, and it exists as an independent View in the Activity. (Hidden, mostly, that is.)
And the Main Activity is different view.
How can I implement a correct OnActivityResultMethod so that I can return to the Activity's oncreate Method, techinically speaking, to the TextWatcher so that the calculation can be made and percentage be set.
Because the OnActivityResult is called automatically, so I cannot do anything to override it.
It has the data the app needs, but it is not called progmatically, so it cannot return values.
You can try this:
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
Intent i = getIntent();
i.putExtras(data.getExtras()); // pass result data to onCreate()
startActivity(i);
finish();
}
Restarting the Activity is the only way to get back to onCreate().
EDIT:
Now, in your onCreate(), make a check:
Intent i = getIntent();
Bundle args = i.getExtras();
if(args != null){
....
}
and handle the data in the EditText here.
If you launch the Activity with an startActivityForResult() you can get the result very easily with an onActivityResult().
Check the code in this post and try it out.
How to manage `startActivityForResult` on Android?

Android: Passing data from one activity to another activity in ListView

I am making a Grocery list app.
In my first Activity I have a ListView and in my second activity I can add the new grocery details. I want to show those details in the first Activity's ListView. Now how can I pass data from second Activity to the first Activity in ListView.
In second activity i passed data with fooling code:
EditText editName = (EditText) findViewById(R.id.txtName);
EditText editQty=(EditText) findViewById(R.id.txtqty);
String name= editName.getText().toString();
String quantity=editQty.getText().toString();
Intent returnIntent = new Intent();
returnIntent.putExtra("name",name);
returnIntent.putExtra("quantity",quantity);
setResult(RESULT_OK,returnIntent);
finish();
And in first activity i used that Intent as follows:
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == 1) {
if(resultCode == RESULT_OK){
Bundle b = data.getExtras();
if ( b!= null ){
String strName=data.getStringExtra("name");
String strQty=data.getStringExtra("quantity");
System.out.println(strName);
System.out.println(strQty);
}
}
if (resultCode == RESULT_CANCELED) {
//Write your code if there's no result
}
}
Please help me solve this. Thanks in advance.
I suggest you to use SQLite for your issue, when you insert new grocery details, just create one table and insert that details in database table. Now , when you want to display that newely added details, just run "select" query and set your ListView Adapter.
If everytime you do not want to set your adapter, then just maintain one boolean static variable like isGroceryAdded. If grocery details added successfully, at that time make that boolean variable "true". And check in your first activity that is that variable is true, then run query again and set your adapter again, after setting the adapter, just make that variable false again.
Without having some code, my suggestion would be to create a model class that implements serializable, put that in the intent as a result and pass it back to the first Activity (note for this to work, the second activity has to be started with startActivityForResult()).
For a similar question, please have a look at https://stackoverflow.com/a/14333555/1082942
This is a general overview of one solution that should work in most cases. Considering you didn't provide code specific to your situation this may or may not be what you need.
1) To resume the first activity, send an intent from the second activity to the first activity containing the grocery details as intent extras (key-value pairs).
2) Override the first activity's onResume() method to handle the incoming intent to pull out the data you want.
3) Then you need to update the data used by your adapter with this intent extra information.
4) Then you need to call notifyDataSetChanged() on your adapter so it will recreate its views with the updated info
Hope you find this helpful.

dynamically adding item to listview with the result given by the child activity

i am stuck while developing my program.
i am not able to find the solution
what i am doing is, from one activity (A) i am calling other activity (B) for result.
now in activity A i have a list view.
for that listview i have an ArrayAdapter
the code for that purpose is :
String []name_list = myarraylist.toArray(new String[myarraylist.size()]);
ArrayAdapter<String> adapter = new ArrayAdapter <String>(this, R.layout.textview,name_list);
setListAdapter(adapter);
Activity A is ListActivity.
now , i have a menu option, clicking on which takes me to another activity, an returns with a result string.
up till this point , everything works fine. the string is also returned by the activity B.
now i want to add the string (the returned one) to the listview.....
how should i do that?
i tried doing it in onActivityResult() itself and also in onResume()
but i couldnt make it working.
help!
EDIT:
code for onActivityResult is :
protected void onActivityResult(int requestCode, int resultCode, Intent data){
super.onActivityResult(requestCode, resultCode, data);
Bundle mybundle = data.getExtras();
String pro_name= mybundle.getString("profile_name");
myarraylist.add(pro_name);
getAdapter().notifyDataSetChanged();
}
Use Arrayadapter add method http://developer.android.com/reference/android/widget/ArrayAdapter.html#add(T) in onactivityResult and call notifyDatasetchanged http://developer.android.com/reference/android/widget/ArrayAdapter.html#notifyDataSetChanged()

Android Activity onResume() and onActivityResult() conflict

Have a problem. In my main Activity I have a ListView. And I need to refresh it any time I returned to this Activity. I use onResume() method for this:
#Override
protected void onResume() {
super.onResume();
refreshCategoriesList();
}
private void refreshCategoriesList() {
// ...
categoriesListAdapter = new CategoryListItemAdapter(
this, R.layout.category_item,
categories
);
categoriesListView.setAdapter(categoriesListAdapter);
}
As you can see I use refreshing adapter extended from ArrayAdapter for changing data in ListView.
But in some cases I need scroll this list to the end, for ex. when I add new item to it. And I use onActivityResult(...) method for this:
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
// ...
refreshCategoriesList();
categoriesListView.setSelection(categoriesListAdapter.getCount() - 1);
}
But I have one problem. When I add new item to my list both this methods executed in order onActivityResult(...) and after that onResume(). And I have:
List data refreshed to times with refreshCategoriesList() (But it's not main problem);
After executing of onResume() scrolled to end list restored to first item position :( It's a problem. Because when I add new item I want scroll list to the end.
How can I resolve this problem. Can I in some cases call only onActivityResult(...) method (when I need to scroll list) and in other onResume() method (when I simply want to refresh list data)?
You can use notifyDataSetChanged() method from ArrayAdapter instead of recreating adapter every time.
private void refreshCategoriesList() {
categoriesListAdapter.notifyDataSetChanged();
}

Custom View calling startActivityForResult

I created custom compound view where I incorporate functionality to take pictures.
I'm calling it like this (from view):
Intent intent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
((Activity)mContext).startActivityForResult(intent, index);
This part works good. What I don't know how to do is how do I implement onActivityResult inside my custom view?
Or should I catch this inside Activity and than re-route into my view? Doesn't look like very nice solution..
You actually can do it like this:
#Override
public void onClick(View v) {
final FragmentManager fm = ((FragmentActivity) getContext()).getSupportFragmentManager();
Fragment auxiliary = new Fragment() {
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
//DO WHATEVER YOU NEED
super.onActivityResult(requestCode, resultCode, data);
fm.beginTransaction().remove(this).commit();
}
};
fm.beginTransaction().add(auxiliary, "FRAGMENT_TAG").commit();
fm.executePendingTransactions();
auxiliary.startActivityForResult(new Intent(getContext(), ToStartActivity.class), 3333);
}
The trick is using an auxiliary temp fragment.
I'm having the same issue, as the initial question. I know that you all posted working solution, BUT, all the solutions lack one thing: encapsulation. What do I mean - If in one activity I have 10 views that should (on some event) start another activity it should be NORMAL to be able to start that new activity from the view that needs that activity. You all are trying to convince that is better to handle all new possible activites from the initial one - than why we added different logic in each view. We may want to RE-USE code, and create one custom view that can work INDEPENDENT to where we use it (work may include showing another activity to select something for example).
I know that this is not possible (or not yet), and is a clear proof that Android SDK is not ready yet to handle real big applications.
If you want an example:in any real business app that has for example, customer list (that should be a view) ,the view should be able to launch by itself addcustomer activity, edit customer activity and so on, independent from where you put that customer list view (control) - because in big apps you need to RE-use components (you may need to show the customer list control in a order product activity, in a timesheet activity and so on.).
One possible solution could be:
- start the new activity (using the view context (normally should be the parent activity).
- on the new activity closing event, either call directly a method in the calling view (depending on the case, and posibilities: either static that is handling the code that you normally would run on activityresult, either try to pass the instance of the calling view to the new activity, and do the same. In this way, you can handle your new activity, without letting the containing activity to know anything about it.
You need to catch this from your activity. The startActivityForResult is called on your activity, so it'll be the one launching the Intent and getting the result. I'd say that it's overall bad to launch it directly from the view's code. A better solution would be with a clickListener (or checkChangeListener, or whatever you want), set by your activity, and calling a method like "openImageCapture".
When the Intent returns, your activity will take care of the result and update your views as needed.
Views are there just for displaying stuff on the screen and getting user input, the activity is there to do the actual work.
Here's a static function to implementing #riwnodennyk's solution, while overcoming the Fragment must be static and not in anonymous class error:
public static void myStartActivityForResult(FragmentActivity act, Intent in, int requestCode, OnActivityResult cb) {
Fragment aux = new FragmentForResult(cb);
FragmentManager fm = act.getSupportFragmentManager();
fm.beginTransaction().add(aux, "FRAGMENT_TAG").commit();
fm.executePendingTransactions();
aux.startActivityForResult(in, requestCode);
}
public interface OnActivityResult {
void onActivityResult(int requestCode, int resultCode, Intent data);
}
#SuppressLint("ValidFragment")
public static class FragmentForResult extends Fragment {
private OnActivityResult cb;
public FragmentForResult(OnActivityResult cb) {
this.cb = cb;
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (cb != null)
cb.onActivityResult(requestCode, resultCode, data);
super.onActivityResult(requestCode, resultCode, data);
getActivity().getSupportFragmentManager().beginTransaction().remove(this).commit();
}
}
Usage example:
Intent inPhonebook = new Intent(Intent.ACTION_PICK, ContactsContract.CommonDataKinds.Phone.CONTENT_URI);
myStartActivityForResult((FragmentActivity) getContext(),
inPhonebook, REQUEST_CODE_PICK_CONTACT, this::onContacts);
There is no way to catch onActivityResult from your view, only from Activity.
And its not safe to assume that's Context object is Activity. In general you should not rely on this fact. Even if it seems reasonable in case with views, you still should use only methods available trough Context interface. That's because your can't predict all side-effects on the Activity, when you're calling Activity specific functions.
Just make the same method inside your custom view
And inside the activitys onActivityResult call yourView.onActivityResult(...) and process the result inside your view..
Also as guys mentioned you must not always end up with Context being of Activity class. Usually when it is from inflated view.
But if you construct your view only in code and always use the activity instance you are good.

Categories

Resources