Update content in ListFragment on menu click - android

I have a ListFragment with some data. I am trying to sort the content of my list depending on which item I select from the menu. How can I update the content of the list when I select one option from the menu? I don't want to create another fragment, I just want to sort by name or by date the info that I have in the list so when I click one item in the menu the list updates immediately depending on whether I click sort by name or sort by date.
public class MainActivity extends AppCompatActivity{
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main_menu, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_sort_by_name) {
Fragment currentFragment = this.getFragmentManager().findFragmentById(R.id.fragment1);
ArrayAdapter adapter = ArrayAdapter.createFromResource(this, R.array.Months, android.R.layout.simple_list_item_1);
setListAdapter(adapter);
}
return super.onOptionsItemSelected(item);
}
And then I have the java class for the fragment:
public class EventsListFragment extends ListFragment implements OnItemClickListener {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.list_fragment, container, false);
return view;
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
ArrayAdapter adapter = ArrayAdapter.createFromResource(getActivity(), R.array.Planets, android.R.layout.simple_list_item_1);
setListAdapter(adapter);
getListView().setOnItemClickListener(this);
}
#Override
public void onItemClick(AdapterView<?> parent, View view, int position,long id) {
Toast.makeText(getActivity(), "Item: " + position, Toast.LENGTH_SHORT).show();
}

use a Sort (by comparator) or by Filter on array or custom adapter - depending on the complexity of the adapter object
some examples and references:
Sort listview with array adapter
sorting and filtering ListView with custom array adapter with two TextView?
Android filter and sort ListView with adapter set during Async task
How to sort adapter (BaseAdapter) based on current its field
Filtering ListView with custom (object) adapter
Custom Listview Adapter with filter Android
How could i filter the listview using baseadapter
basic example for array adapter:
Adapter.sort(new Comparator<Item>() {
#Override
public int compare(Item lhs, Item rhs) {
return lhs.compareTo(rhs); //Your sorting algorithm
}
});
*Item - class definition for adapter item
array adapter doc ref:
https://developer.android.com/reference/android/widget/ArrayAdapter.html
complete solution for your case:
http://www.worldbestlearningcenter.com/tips/Android-sort-ListView.htm

Related

How to delete a row from a ListView with a CursorAdapter

I started a small Android project to re-learn a bit of Android development, and I'm already stuck...
I do not know how to implement the deletetion of an element of my ListView!
Here is the project: https://github.com/gdurelle/Listify
Right now it aims at showing a list of lists of elements.
I use a custom CursorAdapter to show my list of elements, and I already have a (ugly) destroy button, but I do not know how to make it delete an actual element from the list (and the database).
I use ActiveAndroid to manage the database in the ActiveRecord way.
Plus: I'm not sure wether or not to use getView(), bindView(), and/or newView()...
I created an issue to remember this and reference this question here: https://github.com/gdurelle/Listify/issues/1
public class ListifyCursorAdapter extends CursorAdapter {
public String content;
public ListifyCursorAdapter(Context context, Cursor cursor) {
super(context, cursor, 0);
}
// The newView method is used to inflate a new view and return it, you don't bind any data to the view at this point.
#Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
return LayoutInflater.from(context).inflate(R.layout.element_line, parent, false);
}
// The bindView method is used to bind all data to a given view such as setting the text on a TextView.
#Override
public void bindView(View view, Context context, Cursor cursor) {
// Find fields to populate in inflated template
TextView tvBody = (TextView) view.findViewById(R.id.element_content);
// Extract properties from cursor
content = cursor.getString(cursor.getColumnIndexOrThrow("content"));
// Populate fields with extracted properties
tvBody.setText(content);
}
}
And in my MainActivity :
Cursor cursor = ListifyElement.fetchResultCursor();
adapter = new ListifyCursorAdapter(this, cursor);
listView.setAdapter(adapter);
I was thinking maybe about a:
Button delete_button = (Button) listView.findViewById(R.id.delete_button);
with something like ListifyElement.load(ListifyElement.class, the_id_of_the_element).delete(); where the_id_of_the_element would be the DB's id of the element retrieived somehow from the click on it's delete_button in the UI...
UPDATE:
#Override
public void bindView(View view, Context context, final Cursor cursor) {
// Find fields to populate in inflated template
TextView tvBody = (TextView) view.findViewById(R.id.element_content);
// Extract properties from cursor
content = cursor.getString(cursor.getColumnIndexOrThrow("content"));
// Populate fields with extracted properties
tvBody.setText(content);
Button delete_button = (Button) view.findViewById(R.id.delete_button);
delete_button.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View v){
System.out.println(cursor.getColumnName(0)); // Id
System.out.println(cursor.getColumnName(1)); // ListifyContainer
System.out.println(cursor.getColumnName(2)); // content
System.out.println(cursor.getColumnIndexOrThrow("Id")); // 0
ListifyElement.load(ListifyElement.class, cursor.getColumnIndexOrThrow("Id")).delete();
notifyDataSetChanged();
}
});
I get this error when I click the delete button:
java.lang.NullPointerException: Attempt to invoke virtual method 'void com.gdurelle.listify.models.ListifyElement.delete()' on a null object reference
If you want a Button in each row, you should add it to your xml which you inflate in the newView(). After that, you should set OnClickListener to your Button inside bindView(). Something like that:
public void bindView(View view, Context context, Cursor cursor) {
// Find fields to populate in inflated template
TextView tvBody = (TextView) view.findViewById(R.id.element_content);
Button delete_button = (Button) view.findViewById(R.id.delete_button);
delete_button.setOnClickListener(new OnClickListener(){
#Override
public void onClick(View v){
//As you're using ActiveAndroid
new Delete().from(ListfyElement.class).where("yourCondition=?",yourCondition).execute();
notifyDataSetChanged();
}
});
// Extract properties from cursor
content = cursor.getString(cursor.getColumnIndexOrThrow("content"));
// Populate fields with extracted properties
tvBody.setText(content);
}
Use below code to perform this--
ListView lv;
ArrayList<String> arr = new ArrayList<String>();
ArrayAdapter adapter;
int position;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.extra);
for(int i=0;i<5;i++)arr.add("Hi # "+i);
lv = (ListView) findViewById(R.id.listViewBirthday);
lv.setOnItemLongClickListener(this);
adapter = new ArrayAdapter(this,android.R.layout.simple_list_item_1, arr);
lv.setAdapter(adapter);
}
#Override
public void onCreateContextMenu(ContextMenu menu, View v,ContextMenuInfo menuInfo) {
// TODO Auto-generated method stub
super.onCreateContextMenu(menu, v, menuInfo);
MenuItem it1=menu.add("Delete");
}
#Override
public boolean onItemLongClick(AdapterView<?> arg0, View arg1, int p, long arg3)
{
position = p;
registerForContextMenu(lv);
return false;
}
#Override
public boolean onContextItemSelected(MenuItem item) {
// TODO Auto-generated method stub
if(item.getTitle().equals("Delete"))
{
arr.remove(position);
adapter.notifyDataSetChanged();
Toast.makeText(getBaseContext(), "deleted", Toast.LENGTH_SHORT).show();
}
return true;
}
The context menu is relatively simple to implement on a listview. It (context menu) is activated on a long press of the item. My tip is to add an intent to the menu item so you can preserve the item id from your custom adapter and use it to perform whatever you want.
public class MainActionBarTabListFragment extends ListFragment {
#Override
public void onActivityCreated(Bundle savedState) {
super.onActivityCreated(savedState);
registerForContextMenu(getListView());
}
#Override
public void onCreateContextMenu(ContextMenu menu, View v,
ContextMenuInfo menuInfo) {
AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo;
String name = adapter2.getItem(info.position).get_name();
menu.setHeaderTitle(name);
MenuInflater inflater = this.getActivity().getMenuInflater();
inflater.inflate(R.menu.menulistitem, menu);
MenuItem mi = menu.findItem(R.id.action_context_delete);
Intent i = new Intent();
i.putExtra("id", adapter2.getItem(info.position).get_id());
mi.setIntent(i);
}
}
#Override
public boolean onContextItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_context_delete:
Intent i = item.getIntent();
if (i != null) {
Bundle b = i.getExtras();
if (b != null) {
int id = b.getInt("id");
Uri deleteIdUri = ContentUris.withAppendedId(
RidesDatabaseProvider.CONTENT_URI, id);
context.getContentResolver()
.delete(deleteIdUri, null, null);
return true;
}
}
}
return super.onContextItemSelected(item);
}
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:yourapp="http://schemas.android.com/apk/res-auto" >
<item
android:id="#+id/action_context_delete"
android:icon="#drawable/action_about"
android:orderInCategory="100"
android:showAsAction="ifRoom"
android:title="delete"
yourapp:showAsAction="ifRoom"/>
</menu>
lets start from the beginning, why do you need to use ActiveAndroid? I suggest to avoid such things, IMHO. You've mixed your logic, adapter should not change your database. Set a listener to adapter (i.e. IDeleteListener with single method onDeleteRequested(long rowId)). Next you need to pass rowId, something like:
delete_button.setTag(cursor.getLong(0));
delete_button.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View v){
listener.onDeleteRequested((Long)v.getTag());
}
});
In your fragment/activity class you should set a listener to adapter and work with your database. I suggest you to use LoaderManager this will automatically re-query your db on delete and handle life cycle of activity.
Hope that helps!
I would suggest you to use an ArrayAdapter instead. Then you are just using an ArrayList (or any other array) and edit it, and call adapter.notifyDataSetChanged();, and the content of the ListView will update.
Declare the ArrayAdapter like this:
ArrayAdapter<String> adapter = new ArrayAdapter<>(getApplicationContext(), android.R.layout.simple_list_item_1, yourStringArray);
where the variable called yourStringArray is just an ArrayListof Strings.
Then, add the adapter to the ListView, like this:
yourListView.setAdapter(adapter);
Then, you can modify the contents of the list, by editing the yourStringArray list, and calling adapter.notifyDataSetChanged();. Here is a simple example:
list.add("Hello!");
adapter.notifyDataSetChanged();
Finally, to remove the selected item when the button is clicked, you can do something like this:
int selectedItemIndex = 0;
yourArrayList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
selectedItemIndex = position;
}
});
yourDestroyButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
yourStringArray.remove(selectedItemIndex);
adapter.notifyDataSetChanged();
}
});
The whole onCreate method would look something like this:
// Called when the activity is created
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ArrayList<String> yourStringArray = new ArrayList<>();
ArrayAdapter<String> adapter = new ArrayAdapter<>(getApplicationContext(), android.R.layout.simple_list_item_1, yourStringArray);
int selectedItemIndex = 0;
ListView yourListView = (ListView) findViewById(R.layout.yourListViewID);
yourListView.setAdapter(adapter);
yourListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
selectedItemIndex = position;
}
});
yourDestroyButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
yourStringArray.remove(selectedItemIndex);
adapter.notifyDataSetChanged();
}
});
}

How to get the value on change of the spinner in Fragment?

why doesn't fragment support spinners in it? I have the following fragment class and added spinners to it.
public class SettingFragment extends Fragment {
Spinner spinner1;
public List<String> genderitems, titleitems;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// TODO Auto-generated method stub
View rootview = inflater.inflate(R.layout.settinglayout, container,
false);
spinner1 = (Spinner) rootview.findViewById(R.id.usertitle);
titleitems = new ArrayList<String>();
setTitleSpinnerContent(rootview);
titleitems.add("Beginner");
titleitems.add("Novice");
return rootview;
}
private void setTitleSpinnerContent(View view) {
ArrayAdapter<String> adp = new ArrayAdapter<String>(getActivity(),
android.R.layout.simple_dropdown_item_1line, titleitems);
adp.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner1.setAdapter(adp);
}}
How to get the spinner change value upon selection and add it a textview on the spinner.
What is that i am missing here? Thanks in advance.
I tried even adding onitemselectedlistener() but too the result is nil.
There are no differences in adding spinners in activity and fragment. If u want to get the spinner item changed listener implement like this..
spinner.setOnItemSelectedListener(new OnItemSelectedListener() {
public void onItemSelected(AdapterView<?> parent, View view, int pos,
long id) {
Toast.makeText(parent.getContext(),
"On Item Select : \n" + parent.getItemAtPosition(pos).toString(),
Toast.LENGTH_LONG).show();
}
#Override
public void onNothingSelected(AdapterView<?> arg0) {
// TODO Auto-generated method stub
}
}
I'm a bit confused as to what your specific problem is, but if the problem is that you aren't seeing your spinner populated with the values 'Beginner' and 'Novice', it looks like have set your adapter on the empty list, and then added items to the list after the adapter is set. But you never called notifyDataSetChanged() on your adapter, so it doesn't know about your new values. Have you tried the simple solution of adding the items to your list before you set the adapter?
titleitems.add("Beginner");
titleitems.add("Novice");
setTitleSpinnerContent(rootview);

Spinner Value is not updated on the List View

I have a spinner that let user choose a meal from a set of string array in xml. After the user selected the item, I put the selection into the database, and display on a Listview.
In my model, I have a toString(),
#Override
public String toString() {
return id + " " + note +"\n meal: " + this.meal;
}
In the controller class for editing the the meal, I have this,
public class EditNoteFragment extends Fragment implements
OnItemSelectedListener{
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_edit,
container, false);
// populating the spinner with string array of time category
spinner = (Spinner) rootView.findViewById(R.id.spinner_meal_category);
ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(
getActivity().getApplicationContext(), R.array.meal_array,
android.R.layout.simple_spinner_dropdown_item);
spinner.setAdapter(adapter);
spinner.setOnItemSelectedListener(this);
}
#Override
public void onItemSelected(AdapterView<?> parent, View view, int pos,
long id) {
meal = parent.getItemAtPosition(pos).toString();
Log.i(LOGTAG, "Got the meal: " + meal);
}
public boolean onOptionsItemSelected(MenuItem item) {
// I added the field variable meal into the datebase in this block of code
//note.setMeal(meal.toString());
}
}
I used log to verified that I got the user choice and stored in the field variable "meal" in my class, but when I run the application and the list displays meal as null.
I am certain that I have successfully added the meal into the database.
Here is the view class
public static class NoteFragment extends ListFragment {
TextView tx_list_note;
NoteDataSource datasource;
#Override
public void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
datasource = new NotesDataSource(getActivity());
datasource.open();
List<Note> notes = datasource.findAll();
if (notes.size() == 0) {
createData();
notes = datasource.findAll();
}
ArrayAdapter<Note> adapter = new ArrayAdapter<Note>(getActivity(),
android.R.layout.simple_list_item_1, notes);
setListAdapter(adapter);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_notes,
container, false);
return rootView;
}
}
}
in fragment_notes.xml, I have one single listview in the relative layout
<ListView
android:id="#android:id/list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_above="#+id/textView1"
android:layout_alignParentLeft="true"
>
</ListView>
Thank you very much for you help in advance. Any suggestion would be appreciated.

How to disable the particular list item in list-view in android?

How to disable the particular list item in list-view in android?
I mean if once i selected any one of item from a list-view,that item suppose to be disabled which means that item should not be select-able again.
How to do this?
Suggestions please
Thanks for your precious time!..
try using this code in setOnItemClicklistener()
if(listview.getChildAt(selectedPosition).isEnabled())
{
listview.getChildAt(selectedPosition).setEnabled(false);
}
When you pass a list of data elements to BaseAdapter, add a field in this list's element class called isEnabled and set it to true/false as needed, then override isEnabled method of BaseAdapter like this:
#Override
public boolean isEnabled(int position) {
return list.get(position).isEnabled;
}
where list is your list of data element objects.
Try overriding BaseAdapter.isEnabled() in your adapter, and calling this method from your onItemClick().
When you click the item have it set off a boolean.. And what method would use that item have it check to see if the boolean has been triggered, set to false for example. Then in your on click portion use BaseAdapter.isEnabled() = false;
Or with just that boolean alone they can never click it again.
mlistView.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener()
{
public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2,long arg3)
{
arg1.setEnabled(false);
}
}
In order to disable list items on list creation you have to subclass from ArrayAdapter. You have to override the following methods: isEnabled(int position)
class MenuAdapter extends ArrayAdapter<String> {
public boolean isEnabled(int position) {
// return false if position == positionYouWantToDisable
}
}
Or in Activity class
public class MainActivity extends Activity {
ListView listview;
ArrayAdapter<String> arrayadapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
listview = (ListView)findViewById(R.id.listView1);
button = (Button)findViewById(R.id.button1);
arrayadapter = new ArrayAdapter<String>(MainActivity.this,
android.R.layout.simple_list_item_1, subjects);
listview.setAdapter(arrayadapter);
listview.getChildAt(1).setEnabled(false);
}
}

Should I extend ListActivity ? (already working well without it so far)

I am working on an app whose purpose is to display a listview with some content from a database. So I have an activity called ResultListViewActivity (extending something else than ListActivity!), in which I have a displayListView() method.
So far everything is working : I can see my listview, the content from my database is displayed perfectly, I can arrange it the way I want in my XML file, and all of this without extending the ListActivity class.
My next step is to set a onClickItemListener to open a new activity with different content depending on the button clicked.
Everytime I read tutorials, it's always about using tons of stuff, creating other classes with adapters, holder pattern, content provider, etc. I don't understand half of this, in my app I just have one class for my ListView and it works fine without using all the stuff I read in tutorials. So here is my question: will I have to find a way to extend ListActivity eventually (to use the onClickItemListener method for example)?
Here is the code of my activity displaying the listview:
public class ResultListViewActivity extends Base_Activity {
private SimpleCursorAdapter cursorAdapter;
private DatabaseAdapter dbHelper;
ListView listView;
TextView poititle;
private static String TAG = ResultListViewActivity.class.getSimpleName();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_result_list_view);
poititle = (TextView) findViewById(R.id.poititle);
dbHelper = new DatabaseAdapter(this);
dbHelper.open();
displayListView();
}
private void displayListView() {
Bundle bundle = getIntent().getExtras();
String title = bundle.getString("title", "Choose here :");
String inInterval = bundle.getString("inInterval");
poititle.setText(title);
Cursor c = dbHelper.findPoiInTable(inInterval);
String[] columns = new String[] { DatabaseAdapter.COL_NAME, DatabaseAdapter.COL_STREET, DatabaseAdapter.COL_WEBSITE };
int[] to = new int[] {R.id.name, R.id.street, R.id.website};
cursorAdapter = new SimpleCursorAdapter(this, R.layout.poi_info, c,
columns, to, 0);
ListView listView = (ListView) findViewById(R.id.poilistview);
// Assign adapter to ListView
listView.setAdapter(cursorAdapter);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getSupportMenuInflater().inflate(R.menu.main, menu);
return true;
} }
Should I add an inside class and make my code this way to allow further operations on the list view :
public class ResultListViewActivity extends Base_Activity {
//declaration of variables
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_result_list_view);
poititle = (TextView) findViewById(R.id.poititle);
dbHelper = new DatabaseAdapter(this);
dbHelper.open();
displayListView();
}
public class MyListView extends ListActivity {
#Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(....)
listview.setOnClickListener ....
.....
private void displayListView() {
// same method as in the code above
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getSupportMenuInflater().inflate(R.menu.main, menu);
return true;
} }
As you can see, I would add an "inside" class MyListView extending ListActivity just so all which is related to listview would be in this class instead of the one extending Base_Activity. I don't know if it's a correct way to do : I don't remember seeing this in a tutorial.
You can add onClickItemListener like this (you don't need extend ListActivity)
// Click event for single list row
listView.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) {
// Do somthing here
}
});
Hope this helped you.

Categories

Resources