Android ListFragment: how to have both onListItemClick and onContextItemSelected? - android

I'm implementing a ListActivity and ListFragment and would like to allow the user to use short taps and long taps - short being to edit/show the details of the item and long tap to bring up a context menu with the option to delete the item. I don't seem to be able to trigger the onCreateContextMenu, however. onListItemClick works fine and captures all taps, short or long. The ListFragment is populated using a slightly custom SimpleCursorAdaptor and LoaderManager, not using a layout file.
Is is possible to have both?
Code...
LocationsListFragment.java
package com.level3.connect.locations;
//import removed for brevity
public class LocationsListFragment extends SherlockListFragment implements LoaderManager.LoaderCallbacks<Cursor>{
private static final int DELETE_ID = Menu.FIRST + 1;
private SimpleCursorAdapter adapter;
private OnLocationSelectedListener locationSelectedListener;
// the activity attaching to this fragment should implement this interface
public interface OnLocationSelectedListener {
public void onLocationSelected(String locationId);
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Fields from the database (projection)
// Must include the _id column for the adapter to work
String[] from = new String[] { LocationsTable.LOCATION_NAME,
LocationsTable.LOCATION_PHONE_NAME };
// Fields on the UI to which we map
int[] to = new int[] { R.id.titleText, R.id.phoneText };
// connect to the database
getLoaderManager().initLoader(0, null, this);
adapter = new LocationCursorAdapter(getActivity(),
R.layout.location_row, null, from, to, 0);
setListAdapter(adapter);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View root = super.onCreateView(inflater, container, savedInstanceState);
registerForContextMenu(root); //this is called fine
return root;
}
// hook up listening for the user selecting a location in the list
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
locationSelectedListener = (OnLocationSelectedListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ " must implement OnLocationSelectedListener");
}
}
// handle user tapping a location - show a detailed view - this works fine
#Override
public void onListItemClick(ListView l, View v, int position, long id) {
String projection[] = { LocationsTable.KEY_ID };
Cursor locationCursor = getActivity().getContentResolver().query(
Uri.withAppendedPath(DatabaseContentProvider.CONTENT_URI,
String.valueOf(id)), projection, null, null, null);
if (locationCursor.moveToFirst()) {
String locationUrl = locationCursor.getString(0);
locationSelectedListener.onLocationSelected(locationUrl);
}
locationCursor.close();
}
// Context menu - this is never called
#Override
public void onCreateContextMenu(ContextMenu menu, View v,
ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
menu.add(0, DELETE_ID, 0, R.string.menu_delete);
}
#Override - this is never called
public boolean onContextItemSelected(android.view.MenuItem item) {
switch (item.getItemId()) {
case DELETE_ID:
AdapterContextMenuInfo info = (AdapterContextMenuInfo) item
.getMenuInfo();
Uri uri = Uri.parse(DatabaseContentProvider.CONTENT_URI + "/"
+ info.id);
getActivity().getContentResolver().delete(uri, null, null);
return true;
}
return super.onContextItemSelected(item);
}
// Loader code
// Creates a new loader after the initLoader () call
#Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
String[] projection = { LocationsTable.KEY_ID, LocationsTable.LOCATION_NAME, LocationsTable.LOCATION_PHONE_NAME };
CursorLoader cursorLoader = new CursorLoader(getActivity(),
DatabaseContentProvider.CONTENT_URI, projection, null, null, null);
return cursorLoader;
}
#Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
adapter.swapCursor(data);
}
#Override
public void onLoaderReset(Loader<Cursor> loader) {
// data is not available anymore, delete reference
adapter.swapCursor(null);
}
}
UPDATE: I still have not figured this out and am wondering if I have to abandon this strategy and implement it in some other, not as user-friendly manner. Perhaps a swipe to view details and a tap to delete?

I've found my answer in the Android source code for the native Email app. https://android.googlesource.com/platform/packages/apps/Email/
The ListFragment must implement listeners:
public class MessageListFragment extends SherlockListFragment
implements LoaderManager.LoaderCallbacks<Cursor>, AdapterView.OnItemLongClickListener
private static final int DELETE_ID = Menu.FIRST + 1;
private SimpleCursorAdapter adapter;
// The LoaderManager needs initializing
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Fields from the database (projection)
// Must include the _id column for the adapter to work
String[] from = new String[] { BookmarksTable.BOOKMARK_NAME,
BookmarksTable.BOOKMARK_PHONE_NAME };
// Fields on the UI to which we map
int[] to = new int[] { R.id.titleText, R.id.phoneText };
// connect to the database
getLoaderManager().initLoader(0, null, this);
adapter = new BookmarkCursorAdapter(getActivity(),
R.layout.bookmark_row, null, from, to, 0);
setListAdapter(adapter);
}
// register to put up the context menu
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View root = super.onCreateView(inflater, container, savedInstanceState);
registerForContextMenu(root);
return root;
}
// set the listeners for long click
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE);
getListView().setOnItemLongClickListener(this);
}
The called methods are:
/**
* Called when a message is clicked.
*/
#Override
public void onListItemClick(ListView parent, View view, int position, long id) {
// do item click stuff; show detailed view in my case
}
#Override
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
return false; // let the system show the context menu
}
// Context menu
#Override
public void onCreateContextMenu(ContextMenu menu, View v,
ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
menu.add(0, DELETE_ID, 0, R.string.menu_delete);
}
// respond to the context menu tap
#Override
public boolean onContextItemSelected(android.view.MenuItem item) {
switch (item.getItemId()) {
case DELETE_ID:
AdapterContextMenuInfo info = (AdapterContextMenuInfo) item
.getMenuInfo();
Uri uri = Uri.parse(DatabaseContentProvider.BOOKMARK_ID_URI + Long.toString(info.id));
getActivity().getContentResolver().delete(uri, null, null);
return true;
}
return super.onContextItemSelected(item);
}
For completeness, here's the loader code
// Loader code
// Creates a new loader after the initLoader () call
#Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
String[] projection = { BookmarksTable.KEY_ID, BookmarksTable.BOOKMARK_NAME, BookmarksTable.BOOKMARK_PHONE_NAME };
CursorLoader cursorLoader = new CursorLoader(getActivity(),
DatabaseContentProvider.BOOKMARKS_URI, projection, null, null, null);
return cursorLoader;
}
#Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
adapter.swapCursor(data);
}
#Override
public void onLoaderReset(Loader<Cursor> loader) {
// data is not available anymore, delete reference
adapter.swapCursor(null);
}

Related

delete item from listfragment is not working properly

Im doing a basic android app to learn about sqlite. The app just have a listfragment that list some products and the price like:
Pencil 1
Pen 1.20
...
And its possible to click in a item of the list to delete it. Im using cursorloader so the db operations are done in background. But Im getting a issue:
When the user clicks in a item the item is not removed from the list, but if I close and open again the app all items of the list have been removed.
Do you know where is the issue? Why the fragmentlist is not updated by removing the clicked item after click in the item and why all items are being removed?
// to list the products and the respective price
public class ProductsFragment extends ListFragment implements OnClickListener, LoaderManager.LoaderCallbacks<Cursor> {
private static final String[] PROJECTION=new String[] {
Provider.Products._ID, Provider.Products.TITLE,
Provider.Products.PRICE };
private CursorAdapter cursorAdapter;
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
Cursor cursor = getActivity().getContentResolver().query(Provider.Products.CONTENT_URI, DBHelper.ALL_COLUMNS,
null,null,null,null);
String[] from = {DBHelper.TITLE, DBHelper.PRICE};
int[] to = {R.id.title, R.id.price};
cursorAdapter = new SimpleCursorAdapter(getActivity(), R.layout.item, null, from, to, 0);
setListAdapter(cursorAdapter);
getLoaderManager().initLoader(0, null, this);
}
// to delete a product
#Override
public void onListItemClick(ListView l, View v, int pos, long id) {
super.onListItemClick(l, v, pos, id);
getActivity().getContentResolver().delete(Provider.Products.CONTENT_URI,String.valueOf(id), null);
Toast.makeText(getActivity(), "Item " + id + " clicked", Toast.LENGTH_SHORT).show();
}
// cursorloader methods
#Override
public Loader<Cursor> onCreateLoader(int i, Bundle bundle) {
return new CursorLoader(getActivity().getApplicationContext(), Provider.Products.CONTENT_URI, null, null, null, null);
}
#Override
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
cursorAdapter.swapCursor(cursor);
}
public void onLoaderReset(Loader<Cursor> loader) {
cursorAdapter.swapCursor(null);
}
// Provider class delete method:
#Override
public int delete(Uri url, String where, String[] whereArgs) {
return database.delete(DBHelper.TABLE_PRODUCTS, where, whereArgs);
}
same issue with:
#Override
public int delete(Uri url, String where, String[] whereArgs) {
int count=db.getWritableDatabase().delete(TABLE, where, whereArgs);
getContext().getContentResolver().notifyChange(url, null);
return(count);
}
item.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<TextView
android:id="#+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
/>
<TextView
android:id="#+id/price"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
/>
</RelativeLayout>
Full ProductsFragment:
public class ConstantsFragment extends ListFragment implements OnClickListener, LoaderManager.LoaderCallbacks<Cursor> {
private CursorAdapter cursorAdapter;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
}
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
Cursor cursor = getActivity().getContentResolver().query(Provider.Constants.CONTENT_URI, DatabaseHelper.ALL_COLUMNS,
null,null,null,null);
String[] from = {DatabaseHelper.TITLE, DatabaseHelper.VALUE};
int[] to = {R.id.title, R.id.value};
cursorAdapter = new SimpleCursorAdapter(getActivity(), R.layout.row, null, from, to, 0);
setListAdapter(cursorAdapter);
getLoaderManager().initLoader(0, null, this);
}
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.actions, menu);
super.onCreateOptionsMenu(menu, inflater);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId()==R.id.add) {
add();
return(true);
}
return(super.onOptionsItemSelected(item));
}
#Override
public void onClick(DialogInterface dialog, int which) {
ContentValues values=new ContentValues();
AlertDialog dlg=(AlertDialog)dialog;
EditText title=(EditText)dlg.findViewById(R.id.title);
EditText value=(EditText)dlg.findViewById(R.id.value);
values.put(DatabaseHelper.TITLE, title.getText().toString());
values.put(DatabaseHelper.VALUE, value.getText().toString());
getActivity().getContentResolver().insert(Provider.Constants.CONTENT_URI, values);
getLoaderManager().restartLoader(0, null, this);
}
#Override
public void onListItemClick(ListView l, View v, int pos, long id) {
super.onListItemClick(l, v, pos, id);
getLoaderManager().restartLoader(0, null, this);
getActivity().getContentResolver().delete(Provider.Constants.CONTENT_URI,String.valueOf(id), null);
Toast.makeText(getActivity(), "Item id " + id + "clicked", Toast.LENGTH_SHORT).show();
}
private void add() {
LayoutInflater inflater=getActivity().getLayoutInflater();
View addView=inflater.inflate(R.layout.add_edit, null);
AlertDialog.Builder builder=new AlertDialog.Builder(getActivity());
builder.setTitle(R.string.add_title).setView(addView)
.setPositiveButton(R.string.ok, this)
.setNegativeButton(R.string.cancel, null).show();
}
#Override
public Loader<Cursor> onCreateLoader(int i, Bundle bundle) {
return new CursorLoader(getActivity().getApplicationContext(), Provider.Constants.CONTENT_URI, null, null, null, null);
}
public void insertNote(String title, Double value){
ContentValues values = new ContentValues();
values.put(DatabaseHelper.TITLE, title);
values.put(DatabaseHelper.VALUE, value);
Uri noteUri = getActivity().getContentResolver().insert(Provider.Constants.CONTENT_URI, values);
Log.d("MainActivity", "Inserted" + noteUri.getLastPathSegment());
}
#Override
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
cursorAdapter.swapCursor(cursor);
}
#Override
public void onLoaderReset(Loader<Cursor> loader) {
cursorAdapter.swapCursor(null);
}
}
in on click after item deleted call to notifyDatasetChanged()

Context menu android on Listview item with CustomAdapter doesn't show

I'm quite new at Android developing and I was trying to put a a context menu on my Listview that uses a CursorAdapter, I followed this examples https://www.youtube.com/watch?v=Pq9YQl0nfEk Using contextmenu with listview in android but the menu doesn't appear and I don't no why, appearently everything's OK.
These is the code of my activity
public class ProductsView extends AppCompatActivity {
private FloatingActionButton botonAnadir;
private ListView lvProducts;
SetOfProductList mylist;
private ProductAdapter productAdapter;
Cursor cursor;
private ProductList productList;
private Long idProductList;
private DBManager dbManager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bundle bundle = getIntent().getExtras();
if (bundle != null){
productList = bundle.getParcelable("productList");
setTitle(getResources().getString(R.string.show_products) + " " + productList.getName());
}
setContentView(R.layout.products_view);
initialize();
}
private void initialize(){
botonAnadir = (FloatingActionButton)findViewById(R.id.button_add_product);
lvProducts = (ListView)findViewById(R.id.listViewProducts);
dbManager = new DBManager(getApplicationContext());
loadProducts();
registerForContextMenu(lvProducts);
botonAnadir.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
creaNuevaLista();
}
});
lvProducts.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Product aux = getProduct(position);
goToNewProduct(aux);
}
});
lvProducts.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
#Override
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
// markAsPurchased(position);
return true;
}
});
}
private void markAsPurchased(int position){
Product p = getProduct(position);
TextView item = (TextView) findViewById(R.id.textview_product_name);
if (p.getPurchased() == 0){
p.setPurchased(1); //mark as a purchased
item.setPaintFlags(item.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
}
else{
p.setPurchased(0); //mark as a purchased
item.setPaintFlags(item.getPaintFlags() & (~Paint.STRIKE_THRU_TEXT_FLAG));
}
editProduct(p); //makes de update
loadProducts();
}
private void editProduct(Product product){
dbManager.updateProduct(product);
}
private void goToNewProduct(Product p){
Intent intent = new Intent(this,NewProductActivity.class);
Bundle b = new Bundle();
b.putBoolean("editMode",true);
b.putParcelable("product", p);
intent.putExtras(b);
startActivity(intent);
}
private void creaNuevaLista(){
Intent i = new Intent(this,NewProductActivity.class);
Bundle b = new Bundle();
b.putParcelable("productList", productList);
i.putExtras(b);
startActivityForResult(i, 0);
}
private void loadProducts(){
cursor = dbManager.getAllProductsWithCursor(productList);
productAdapter = new ProductAdapter(this,cursor);
lvProducts.setAdapter(productAdapter);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
#Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
if (v.getId() == R.id.listViewProducts){
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.prodcut_view_context_menu,menu);
}
}
#Override
public boolean onContextItemSelected(MenuItem item) {
AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
switch (item.getItemId()){
case R.id.delete_id:
return true;
default:
return super.onContextItemSelected(item);
}
}
}
And this is the adapter that I'm using
public class ProductAdapter extends CursorAdapter {
private LayoutInflater inflater;
//Constructor
public ProductAdapter(Context context, Cursor cursor) {
super(context, cursor,false);
}
// 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) {
inflater = (LayoutInflater) context.getSystemService(context.LAYOUT_INFLATER_SERVICE);
View view = inflater.inflate(R.layout.layout_product_row,parent,false);
return view;
}
// 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) {
TextView tv_product_name = (TextView) view.findViewById(R.id.textview_product_name); // Find fields to populate in inflated template
String product_name = cursor.getString(cursor.getColumnIndexOrThrow("name"));// Extract properties from cursor
// Populate fields with extracted properties
tv_product_name.setText(product_name);
if (cursor.getInt(cursor.getColumnIndexOrThrow("purchased")) == 1){
tv_product_name.setPaintFlags(tv_product_name.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
}
}
public Product getProduct(int position, Cursor cursor) {
Product p=null;
if(cursor.moveToPosition(position)) {
Log.e("PRODUCTLISTADAPTER","nombre es: "+cursor.getString(cursor.getColumnIndex("name")));
p = new Product (cursor.getLong(cursor.getColumnIndex("_id")),cursor.getString(cursor.getColumnIndex("name")),
cursor.getString(cursor.getColumnIndex("unit_type")),cursor.getDouble(cursor.getColumnIndex("value")),cursor.getInt(cursor.getColumnIndex("purchased")),cursor.getLong(cursor.getColumnIndex("id_pl")));
}
return p;
}
}
Can anyone exaplin me why it isn't working? isn't it necessary to make something on the LongClickListener ? because I don't see that the menu is being created.
Thanks in advance.
You've set an OnItemLongClickListener for the ListView, which will run before the context Menu is created. Returning true from its onItemLongClick() method indicates that the long click is being consumed there, so the Menu will not be created.
If you don't actually need the OnItemLongClickListener, you can remove the relevant code. If you do need it as well, for some reason, you can return false from onItemLongClick(), and your Menu will then show.

CursorAdapter doesnt want to update

I made the delete posibility from cursor , the function works , but CursorAdapter doesnt update on notifyDataSetChanged(), any one has any idea ??? The only way at the moment to see the changes is to exit app and run again
public class DiaryFragment extends Fragment implements LoaderManager.LoaderCallbacks<Cursor>, AdapterView.OnItemClickListener {
private GridView mGridView;
private View mEmptyViews;
private TextView mAddNewDiaryEntry;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_diary, container, false);
setHasOptionsMenu(true);
getLoaderManager().initLoader(0, null, this);
mGridView = (GridView) view.findViewById(R.id.gridview);
mGridView.setAdapter(new DiaryAdapter(getActivity()));
mGridView.setOnItemClickListener(this);
return view;
}
#Override
public void onResume() {
super.onResume();
GALogEvent.logScreen(getActivity(), "Diary");
getLoaderManager().restartLoader(0, null, this);
}
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
getActivity().getMenuInflater().inflate(R.menu.diary, menu);
}
private CursorAdapter getAdapter() {
return ((CursorAdapter) mGridView.getAdapter());
}
public static Fragment newInstance() {
return new DiaryFragment();
}
#Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
return new CursorLoader(getActivity(),ContentProvider. URI, null, null, null, ContentProvider.DIARY_DATE + " DESC");
}
#Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
getAdapter().swapCursor(data);
if (data != null && data.getCount() > 0) {
mGridView.setVisibility(View.VISIBLE);
mEmptyViews.setVisibility(View.GONE);
}
}
#Override
public void onLoaderReset(Loader<Cursor> loader) {
getAdapter().swapCursor(null);
}
#Override
public void onItemClick(AdapterView<?> parent, View view, final int position, long id) {
Cursor c = (Cursor) parent.getAdapter().getItem(position);
int diaryEntryId = c.getInt(c.getColumnIndex(ContentProvider.ID));
Intent intent = new Intent(getActivity(), AddDiaryEntryActivity.class);
boolean didSmoke = c.getInt(c.getColumnIndex(ContentProvider.DIARY_DID_SMOKE)) != 0;
intent.putExtra(Constants.DIARY_UPDATE_STATUS, didSmoke);
intent.putExtra(Constants.DIARY_ENTRY, diaryEntryId);
startActivity(intent);
}
private class DiaryAdapter extends CursorAdapter {
private final LayoutInflater mLayoutInflater;
public DiaryAdapter(Context context) {
super(context, null, true);
mLayoutInflater = LayoutInflater.from(context);
}
#Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
return mLayoutInflater.inflate(R.layout.row_diary, parent, false);
}
#Override
public void bindView(View view, Context context, final Cursor cursor) {
final int idCraving = cursor.getInt(cursor.getColumnIndex(ContentProvider.ID));
final ImageView deleteDiaryEntry;
deleteDiaryEntry = (ImageView) view.findViewById(R.id.remove_registry_from_diary);
deleteDiaryEntry.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
getActivity().getContentResolver().delete(ContentProvider. URI, " _id = ? ", new String[]{"" + idCraving});
getAdapter().notifyDataSetChanged();
}
});
}
}
}
Within the delete() method in your ContentProvider, you need to have the following line of code:
getContext().getContentResolver().notifyChange(uri, null);
From the official documentation, this line will notify CursorAdapter objects that a change occurred. If you do not have this line, you will see the change only when the code does a fresh lookup of the database which occurs when you exit and reopen the app.

listview not refresh even after calling restart loader

I have List fragment with Context menu on long press of list item. The list item clicked and the list item removed from my Database. But the list not refresh even after calling restart loader?
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
setEmptyText("Loading...");
myAdapter = new MySimpleCursorAdapter(getActivity().getApplicationContext(), R.layout.my_list_item, null, new String[] {DBConstants.NAME,DBConstants.ITEM1,DBConstants.SYMBOL}, new int[] {R.id.my_companyname,R.id.my_item1,R.id.my_symbol},0);
setListAdapter(myAdapter);
registerForContextMenu(getListView());
MyLoader = getActivity().getSupportLoaderManager().initLoader(1, null, this);
}
#Override
public Loader<Cursor> onCreateLoader(int arg0, Bundle arg1) {
DBHelper dbHelper=new DBHelper(getActivity());
return new MyLoader(getActivity(),dbHelper);
}
#Override
public void onLoadFinished(Loader<Cursor> arg0, Cursor c) {
if(c!=null && c.getCount()>0){
myAdapter.swapCursor(c);
if (isResumed()) {
setListShown(true);
} else {
setListShownNoAnimation(true);
}
}
else
{
setEmptyText("Not selected");
}
}
#Override
public void onLoaderReset(Loader<Cursor> arg0) {
myAdapter.swapCursor(null);
}
#Override
public boolean onContextItemSelected(MenuItem item) {
String selectedItem = item.getTitle().toString();
Log.i("context", "selected context menu item->"+selectedItem);
if(selectedItem.equalsIgnoreCase("Remove"))
{
AdapterView.AdapterContextMenuInfo menuInfo=(AdapterView.AdapterContextMenuInfo)item.getMenuInfo();
String[] args={String.valueOf(menuInfo.id)};
Log.i("context", String.valueOf(menuInfo.id));
new DBHelper(getActivity()).getWritableDatabase().delete(DBConstants.MYSTOCKS_TABLE, "_ID=?", args);
getActivity().getSupportLoaderManager().restartLoader(1, null, this);
/*
Cursor cursor = myAdapter.getCursor();
myAdapter.swapCursor(cursor);
*/
//getLoaderManager().initLoader(0, null, this);
}
return super.onContextItemSelected(item);
}
#Override
public void onCreateContextMenu(ContextMenu menu, View v,ContextMenuInfo menuInfo) {
//super.onCreateContextMenu(menu, v, menuInfo);
getActivity().getMenuInflater().inflate(R.menu.mystocks_context, menu);
}
Do you add the fragment in activity's onCreate or onResume? If the latter, you might want to move the fragment setup (transaction creation, addition of the fragment, committing) to onCreate. After doing that restartLoader() will work properly.

SherlockListFrgament with CommonsWare Loaderex, can't update data

public class NewFriendsListFragment extends SherlockListFragment implements
LoaderManager.LoaderCallbacks<Cursor> {
int monthchange, daychange;
Dialog dialog;
int pos;
CheckedTextView ctv_name;
private SimpleCursorAdapter mAdapter=null;
private SQLiteCursorLoader loader=null;
String mCurFilter;
private static Handler responseHandler;
boolean loaded=false;
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
//some more stuff...
setHasOptionsMenu(true);
mAdapter = new FriendListSCA(getSherlockActivity().getApplicationContext(),
R.layout.friend_item, null,null, null, null, null, NAME),
new String[]{NAME,MONTH,UID}, new int[]{R.id.name,R.id.info,R.id.profile_pic});
setListAdapter(mAdapter);
setListShown(false);
registerForContextMenu(getListView());
getLoaderManager().initLoader(0, null, this);
responseHandler = new Handler()
{
//handler code
};
}
public Loader<Cursor> onCreateLoader(int loaderId, Bundle args) {
//loader code
return(loader);
}
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
mAdapter.changeCursor(cursor);
// Showin List
if (isResumed()) {
setListShown(true);
} else {
setListShownNoAnimation(true);
}
}
public void onLoaderReset(Loader<Cursor> loader) {
mAdapter.changeCursor(null);
}
#Override
public boolean onContextItemSelected(android.view.MenuItem item) {
AdapterContextMenuInfo info;
try {
info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
} catch (ClassCastException e) {
return false;
}
pos=info.position;
switch (item.getItemId()) {
case R.id.edit_item:
show_dialog();
return true;
}
return(super.onOptionsItemSelected(item));
}
#Override
public void onListItemClick(ListView l, View v, final int position, long id) {
Log.e("onListItemClick","Inside onListItemClick");
ContentValues cv= new ContentValues();
//MORE CODE
loader.update(TABLE_NAME_INCLUDE, cv, _ID+" = ?", new String[]{Integer.toString(position)});
}
private class FriendListSCA extends SimpleCursorAdapter
{
public FriendListSCA(Context context, int layout, Cursor c,
String[] from, int[] to) {
super(context, layout, c, from, to,0);
setViewBinder(new FriendsListDataViewBinder());
}
}
public class FriendsListDataViewBinder implements SimpleCursorAdapter.ViewBinder
{
//_ID + "," + UID+","+NAME+","+MONTH+","+DAY+","+WISH
#Override
public boolean setViewValue(View view, Cursor c, int columnIndex)
{
switch (view.getId())
{
case R.id.name:
CheckedTextView ctv= (CheckedTextView)view;
ctv.setText(c.getString(2));
if(c.getInt(5)==0 || c.getInt(4)==-1)
{
ctv.setPaintFlags(ctv.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
ctv.setChecked(false);
}
else
{
ctv.setPaintFlags(ctv.getPaintFlags() & (~ Paint.STRIKE_THRU_TEXT_FLAG));
ctv.setChecked(true);
}
return true;
case R.id.info:
if(c.getInt(4)!=-1)
{
((TextView)view).setText(Utility.MONTH_NAME[c.getInt(3)-1] + " " + Integer.toString(c.getInt(4)));
}
else
{
((TextView)view).setText("Tap and hold to manually enter");
}
return true;
case R.id.profile_pic:
if(!loaded)
return true;
((ImageView)view).setImageBitmap(Utility.model.getImage(
Long.toString( c.getLong(1) ), getURL(c.getLong(1)) ));
return true;
}
return false;
}
}
private void show_dialog()
{
//DATE PICKER CODE
okay.setOnClickListener(new Button.OnClickListener() {
#Override
public void onClick(View v)
{
ContentValues cv=new ContentValues();
cv.put(MONTH, monthchange);
cv.put(DAY, daychange);
loader.update(TABLE_NAME_INCLUDE, cv, _ID+" = ?" , new String[]{Integer.toString(pos)});
//getLoaderManager().restartLoader(0, null, NewFriendsListFragment.this);
//I tried calling restart loader, but nothing, when I checked
//it turned out the sqlite database wasn't being updated
responseHandler.sendEmptyMessage(1); //just dismisses dialog
}
});
dialog.show();
}
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
// Place an action bar item for searching.
MenuItem item = menu.add("Search");
item.setIcon(android.R.drawable.ic_menu_search);
item.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
View searchView = SearchViewCompat.newSearchView(getActivity());
if (searchView != null) {
SearchViewCompat.setOnQueryTextListener(searchView,
new OnQueryTextListenerCompat() {
#Override
public boolean onQueryTextChange(String filtext) {
mCurFilter = !TextUtils.isEmpty(filtext) ? filtext : null;
getLoaderManager().restartLoader(0, null, NewFriendsListFragment.this);
return true;
}
});
item.setActionView(searchView);
}
}
#Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
// TODO Auto-generated method stub
}
}
I'm using a SherlockListFragment from the ActionBarSherlock library to display a list using a CommonsWare Loaderex sqlite cursor loader, and evrything seems to work fine, the names and birthdays and profile pics are all displayed fine, but I can't seem to be able to update any of the data in the table using loader.update(...), nothing happens when I call it.
What's wrong?
You have:
loader.update(TABLE_NAME_INCLUDE, cv, _ID+" = ?", new String[]{Integer.toString(position)});
In all likelihood, that should be:
loader.update(TABLE_NAME_INCLUDE, cv, _ID+" = ?", new String[]{Integer.toString(id)});
(replacing position with id)

Categories

Resources