can you help me, if there is any way, how to call method startActivityForResult(..) from class extends ArrayAdapter?
Thanks.
EDIT: ADDED CODE OF ARRAYADAPTER:
There is code of MyAdapter class:
public class MyAdapter extends ArrayAdapter {
public static final String bundle_text = "some_text";
public MyAdapter(Context context, int textViewResourceId, List<MyAdapterItem> data) {
super(context, textViewResourceId, data);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View row = convertView;
// ...
row.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Intent intent = new Intent(getContext(), MyNewActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
int id = 1;
Bundle bundle = new Bundle();
bundle.putLong(MyAdapter.bundle_text, id);
intent.putExtras(bundle);
getContext().startActivity(intent);
}
});
return super.getView(position, convertView, parent);
}
}
All works, but from ArrayAdapter class is not possible to call startActivityForResult, I can call only startActivty.
But after MyNewActivity is finished, I would like to refresh listview, but I do not know how, when I cannot call startActivityForResult.
This a common misconception (as is old thread, I will just give an outline)
Adapter is only for data to list view - it does return a view as in your getView for a row, but doesn't really handle any GUI events - those are done in activity. In fact, if adapter is loading a lot of rows from internet or database it should be done outside the UI thread.
ACTIVITY IS FOR EVENTS. You attach a click listener to a listview within your activity. Then there is no problem calling e.g. a detail edit activity - it is all on UI thread. So no problem starting an activity from UI thread.
PROBLEM OF UPDATING ADAPTER! If you back return from detail activity you will find the list is NOT updated as adapter was NOT updated. To do this, start detail Activity for RESULT. Don't clutter up the detail "form" with any adapter stuff. In fact, you may choose to return the POJO that was created or edited in detail record, and not bother with the database at all.
Now in your activity you listen for onActivityResult() and do the insert into the adapter (and database backend if you have e.g. SQLite in app), then notify Data changed for list view. It will update the list view automatically.
PERFORMANCE can be an issue if listview is reloaded. In most cases you can get away by adding to adapter and simply notify the list view data is changed. Since data display is "incremental" you may have edited row 3 of rows 1 - 5 shown. Then list view will only refresh those 1-5 rows display positions. But if you reload say 500 rows when only 1 is changed you could get performance issues :)
Related
I am still stuck with this issue, can anyone help. It seems that my problem is that I cant update the data list. I have tried every solution that I've searched for on google etc.. but half the time i'm not even sure that I'm doing the correct thing.
I've used the onResume() to call notifyDataSetChanged, it didn't work. I've tried putting a refresh method into the adapter which i then called in OnResume(). Again it didn't work. Some people suggest clearing the adpater (adapter.clear();) in onResume and then using the addAll() function to relist the data but nothing works.
There has to be a simple solution to this. I have literally been stuck on this for 2 days now. very frustrated.
Here's my Fragment code again...
enter code here
public class SavedAppFragment extends ListFragment {
private static final String TAG = "AppClicked"; //DEBUGGER
private ArrayList<App> mSavedApps;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//Populate the ArrayList
mSavedApps = SavedAppData.get(getActivity()).getApps();
AppAdapter adapter = new AppAdapter(mSavedApps);
setListAdapter(adapter);
}
//LIST ITEM CLICKED: /*Control what happens when list item is clicked: I.E. Load up a quiz while putting an EXTRA key containg the package name of the App to be launhced should the user get the question correct */ #Override public void onListItemClick(ListView l, View v, int position,long id) { //Return the crime for the list item that was clicked App c = ((AppAdapter) getListAdapter()).getItem(position); Log.d(TAG, "was clicked");
//Start the Activity that will list the detail of the app
Intent i = new Intent(getActivity(), Quiz_Activity.class);
String name = c.getPackage();
i.putExtra("packagename", name);
startActivity(i);
}
private class AppAdapter extends ArrayAdapter {
private ArrayList<App> mSavedApps;
public AppAdapter(ArrayList<App> apps) {
super(getActivity(), 0, apps);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
//If we weren't given a view, inflate one
if (null == convertView) {
convertView = getActivity().getLayoutInflater().inflate(R.layout.list_item_app, null);
//((AppAdapter) getListAdapter()).notifyDataSetChanged();
}
((AppAdapter) getListAdapter()).notifyDataSetChanged();
//Configure the view for this crime
App c = getItem(position);
TextView nameTextView = (TextView) convertView.findViewById(R.id.app_name);
nameTextView.setText(c.getName());
// nameTextView.setText(applicationInfo.loadLabel(packageManager));
TextView packageTextView = (TextView) convertView.findViewById(R.id.app_package);
packageTextView.setText(c.getPackage());
CheckBox appCheckBox = (CheckBox) convertView.findViewById(R.id.app_checked);
appCheckBox.setChecked(c.isChecked());
//Return the view object to the ListView
return convertView;
}
}
}
THANKS!!!
When you return to Activity B, the previous Activity B hasn't been destroyed. Thus, it skips the onCreate. Move all of the stuff you want to make sure happens every time into the onResume. I think you want to make your Adapter a class variable (I'll call it mAdapter) in onCreate, and add code that will get data from the list directly. If you need to do something, put a "refresh" function in the adapter. I'm assuming you have a custom Adapter, because I've never heard of AppAdapter. If you don't, then extend AppAdapter and add that functionality. Thus, your onCreate should look like this:
mAdapter = new AppAdapter(mSavedApps);
setListAdapter(mAdapter);
Your onRefresh could update the data contained in the adapter by some new update function, like so:
mAdapter.update(SavedAppData.get(getActivity()).getApps());
I'm working on a fragment that contains a listview (this fragment is PlaceHolderFragment generated when create activity). I extends ArrayAdapter to make my custom adapter and fill my listview with this adapter.
One important thing is in one row of listview, there are 2 buttons: first is the enable/disable button to change status of an user (when user's status is active then it's disable, otherwise enable), second is the delete button (to delete user). So I have to implement OnClickListener for this 2 buttons in method getView() of adapter
When click either buttons, it will send request to server and manipulate database (change user's status or delete user from database). The thing is when I click enable button (for example), it is success and user's status in database is changed, or when I click delete button, user will be delete from database successfully
BUT after I click that button, it's state does not changed (I mean if user is enabled, now the button must change to disable, or if user is deleted, that row must be remove from screen). I have to reload this fragment by hand (switch to other fragment and then come back)
The question is how can I reload activity (I already implement onResume to load all data to adapter, so if I can make this method onResume of fragment run, it will work as my expectation), or at least how can I reload the listview to update new data?
Note: notifyDataSetChanged() DOES NOT work because the data in adapter actually doesn't change yet, only data on server are changed
Note 2: if you need me to post my code, please comment and I will edit my post, because I think my code is long
Thank you and best regards!
EDIT 1
I've posted my solution in the answer below, it fix the problem but I have to say that this is a very very BAD practice in android. For example, when you want to delete an item with this approach, you may want to put a AlertDialog for user to confirm, but AlertDialog can only show in Activity (or Fragment), it can't be show from Adapter. So instead, you should use some different methods such as ContextMenu or CustomDialog.
After couple of weeks searching google and try different methods, I finally found a way to archive what I want, and it's very simple. I post my answer here for anyone facing this problem like me in the future
public class CustomAdapter extends ArrayAdapter<YourClass> {
private List<YourClass> items;
private CustomAdapter adapter;
private Context context;
private Button button;
private YourClass item;
public CustomAdapter(Context context, List<YourClass> items) {
super(context, R.layout.custom_list_item, items);
this.items = items;
this.context = context;
this.adapter = this; //This is an important line, you need this line to keep track the adapter variable
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
if (v == null) {
LayoutInflater li = LayoutInflater.from(getContext());
v = li.inflate(R.layout.custom_list_item, null);
}
item = items.get(position);
button = (Button) v.findViewById(R.id.button); //Find the button
button.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View view) {
//Do something inside here like update, remove your item...
//But the important is
items.remove(item); //Actually change your list of items here
adapter.notifyDataSetChanged(); //notify for change
}
});
}
return v;
}
That's it, all you need to implement when you need the listview to reload in case you need to implement OnClick inside the adapter. Hope you guy find it easier than me when you face this problem
What I understand from your question that you want to refresh the list data when click on one of the button as you need.
Now You should call notifydataset change rather reloading the activity again.
For this you need to change the array that yu are using for the adapter(Don't change the array object just the Item of the array)
like arraylst.get(index).activ=true etc etc and then call notifiydataset change.
I''m struggling a little with the hierarchy here. I'd like to get references to every ImageButton view with the id delete_img in my listView. The imagebutton is added via the XML in the row layout xml.
Essentially i want to be able to set the visibility of a certain element within every row but i cant figure out how to get that sort of reference. Is there an alternative way of doing this? The method deleteShow() is my attempt to get at it so far but its obviously wrong as i am getting a Null Pointer when trying to set the Visibility.
NotesFragment
public class NotesFragment extends ListFragment {
private CommentsDataSource datasource;
private View v = null;
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
Cursor theNotes = (Cursor) returnNotes();
String[] projection = { MySQLiteHelper.COLUMN_ID,
MySQLiteHelper.COLUMN_COMMENT,
MySQLiteHelper.COLUMN_COMMENTNAME,
MySQLiteHelper.COLUMN_FOLDERFK };
int[] to = new int[] { R.id.id_txt, R.id.content_txt, R.id.title_text };
#SuppressWarnings("deprecation")
SimpleCursorAdapter sca = new SimpleCursorAdapter(getActivity(),
R.layout.notes_list_layout, theNotes, projection, to);
setListAdapter(sca);
View v = inflater.inflate(R.layout.notesfragment, container, false);
deleteShow();
return v;
}
#Override
public void onListItemClick(ListView parent, View v, int position, long id) {
Intent intentView = new Intent(getActivity().getApplicationContext(),
ViewNote.class);
intentView.putExtra("id", id);
startActivity(intentView);
}
public Cursor returnNotes() {
Cursor theNotesCursor = null;
datasource = new CommentsDataSource(getActivity());
datasource.open();
theNotesCursor = datasource.getAllCommentsAsCursor();
return theNotesCursor;
}
public void deleteShow() {
ImageButton b = (ImageButton) getActivity().findViewById(R.id.delete_img);
b.setVisibility(View.INVISIBLE);
}
public void onPause() {
super.onPause();
datasource.close();
}
}
The hierarchy for dealing with ListView is not that complicated once you understand what's going on. Think of the ListView as the framwork that holds a bunch of child views or Items. Those Items each have child views that consist of the individual elements that make up a row in the ListView. To modify a list Item you either need to (1) change the data backing that item and update your ArrayAdapter or (2) find the individual Item you are trying to modify from within the ListView and then act on the child views for that individual item.
The easiest way to do this is to modify the data in the adapter backing the list and then call notifyDataSetChanged() on your ArrayAdapter to update the ListView. I don't know how your adapter is set up so to give you direct advice is difficult but the general idea is that you want to change the data backing the Item you want to modify, change that data, and then call notifyDataSetChanged() on the ArrayAdapter so that the ListView reflects the changes.
To modify an individual item directly is much more complicated. You cannot do it in one step as your code proposes - finding the individual view by id and then changing its visibility - will not operate accross the entire list as you suspect. findViewById is likley returning null because it is not looking within an indvidual list element but within the whole list - i.e. the outer list structure - for a view that is not there.
To do what you want programatically you need to (1) get a reference to the ListView itself; (2) find the first displayed view within the list by calling getFirstVisiblePosition(); (3) figure out how far down from that first visibile item is the item you want to modify; (4) get that item; (5) modify it
This ends up just being a pain in the ass. Its much easier to modify the data backing the list and update than to find single view.
I'm working on refreshing a list in Android but can't seem to get it right.
I've used notifyDataSetChanged(); at every point that I thought applicable (currently using dialogs for input), but it doesn't work, and I've got to the point of plastering it around all over the place and it still won't refresh.
Am I right in saying this should refresh the list while your looking at it, or it will rebuild the list and you still have to refresh the view?
If anyone has got any suggestions for the positioning of it in relation to constructing a list I'd be glad to hear.
Is this a ListActivity? I have a ListActivity in my project at the moment and I have my own adapter class within it that extends ArrayAdapter.
My experience is that calling notifyDataSetChanged() on my extended list adapter class instance does immediately cause a refresh of the list View being displayed. So, as soon as I call .notifyDataSetChanged() on my adapter instance, the list View is regenerated which therefore causes my adapter's implementation of getView() to be called to generate each individual row view again. So, the user selects a context menu item which triggers some change to the data and then a call to .notifyDataSetChanged(), and the screen instantly refreshes with the new data.
So to add some code snippets to be clear:
I have a ListActivity
public class VarListActivity extends ListActivity {
Within it, I extend ArrayAdapter
class VarAdapter extends ArrayAdapter{
...
#Override
public View getView(int position, View convertView, ViewGroup parent){
// Creates the views based upon myData
...
#Override
public int getCount(){
...
And I create an instance of that array adapter
la = new VarAdapter(this, R.layout.row0);
And when a context menu item is selected
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.a_context_menu_option:
// Does a call to perform modifications to myData
la.notifyDataSetChanged();
return true;
I'm just chucking this all down just in case it's of any similarity to your situation, but really we need to know a bit more about your code.
I have a problem with listView, I used ArrayList to store data, and a customized Adapter. But, when I remove all the data, and add one item again, it does not display anything in this list. What happens to my List, can anyone help me?
static ArrayList<String> chattingListData=new ArrayList<String>();
static IconicAdapter chattingListDataAdapter;
#Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
chattingListDataAdapter=new IconicAdapter(this);
setListAdapter(chattingListDataAdapter);
registerForContextMenu(this.getListView());
}
class IconicAdapter extends ArrayAdapter {
Activity context;
IconicAdapter(Activity context) {
super(context, R.layout.chatting_list, chattingListData);
this.context=context;
}
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater=context.getLayoutInflater();
View row=inflater.inflate(R.layout.chatting_list, null);
TextView label=(TextView)row.findViewById(R.id.chattinglist_userName);
label.setText(chattingListData.get(position));
return(row);
}
}
I use static ArrayList to modify data from outside, when I start the ListView activity and add data, it's Ok, but when I remove all data, I can not add anymore to the data list. Please help me.
I use static ArrayList to modify data from outside
Don't do that.
Step #1: Use a non-static ArrayList data member as the basis for your ArrayAdapter.
Step #2: Expose methods on your activity that adds and removes items via the add(), insert(), and remove() methods on ArrayAdapter. By using these methods, your ListView will automatically update when you make the changes.
Step #3: Use the methods you wrote in Step #2 to modify the contents of your ListView, by whoever is doing this (not shown in your code).
You can also use the Adapter's notifyDataSetChanged() method, in order to force it to refresh.