Can't delete database item after page first loads - android

I have a task reminder that allows you to store info in a database and then edit or retrieve them later (like a notepad). Whenever starting the app and then going to the activity it will display the saved items but will crash if you try to select and delete one.
You can even click on it to review it, just not delete. If you first add another item then you can delete any and all of them. If I switch to another app and come back to it, it's fine. Only if the app completely shuts down before coming back to delete does it cause a problem.
I'm utterly stumped.
Here is the beginning that displays the items
#Override
public void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
mDbHelper = new RemindersDbAdapter(this);
mDbHelper.open();
fillData();
setContentView(R.layout.meds);
registerForContextMenu(getListView());
}
private void fillData() {
Cursor remindersCursor = mDbHelper.fetchAllReminders();
startManagingCursor(remindersCursor);
String[] from = new String[] { RemindersDbAdapter.KEY_TITLE };
int[] to = new int[] { R.id.text1 };
SimpleCursorAdapter reminders = new SimpleCursorAdapter(this,
R.layout.reminder_row, remindersCursor, from, to);
setListAdapter(reminders);
}
And the Context Menu for deleting
#Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
MenuInflater mi = getMenuInflater();
mi.inflate(R.menu.list_menu_item_longpress, menu);
}
#Override
public boolean onContextItemSelected(MenuItem item) {
if (item.getItemId() == R.id.menu_delete) {
AdapterContextMenuInfo info = (AdapterContextMenuInfo) item
.getMenuInfo();
long mRowId = info.id;
cancelReminder();
mDbHelper.deleteReminder(info.id);
fillData();
return true;
}
return super.onContextItemSelected(item);
}
I don't think it's in the database because it will delete just fine if the app has already stored something else.
EDIT
I have been trying to debug this problem and found the location of the error in the method cancelReminder
public void cancelReminder() {
alarmid = Integer.parseInt(malarmid);
Log.e(TAG2, "meds screen alarmid " + alarmid);
Intent i = new Intent(ReminderManager.mContext, OnAlarmReceiver.class);
PendingIntent pi = PendingIntent.getBroadcast(ReminderManager.mContext,
alarmid, i, PendingIntent.FLAG_UPDATE_CURRENT);
ReminderManager.mAlarmManager.cancel(pi);
}
The error is in the Intent for some reason. This is where I am deleting the alarm for the reminder. It is orginally set in another activity and here is where I am removing it. What really gets confusing is if the app has been running and I save another reminder I can delete them. If I start the app and go right to a reminder to delete it, it crashes.

Found the answer to the problem....
Trying to cancel the repeating alarm from this activity wouldn't work because it couldn't get the context. Instead I passed the string info for the alarm to my alarmManager class and removed it there.
#Override
public boolean onContextItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_delete:
AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();
long mRowId = info.id;
Cursor reminder = mDbHelper.fetchReminder(mRowId);
startManagingCursor(reminder);
malarmid = reminder.getString(reminder
.getColumnIndexOrThrow(RemindersDbAdapter.KEY_RANDOM));
Log.e(TAG2, "meds screen malarmid " + malarmid);
mDbHelper.deleteReminder(info.id);
fillData();
new ReminderManager(this).cancelReminder(info.id, malarmid);
return true;
}
return super.onContextItemSelected(item);
}
and the reminderManager class
public void cancelReminder(long mRowId, String malarmid) {
int alarmid = Integer.parseInt(malarmid);
Log.e(TAG2, "Reminder Manager Cancel Reminder convert from malarm to alarmid " + alarmid);
Intent i = new Intent(mContext, OnAlarmReceiver.class);
PendingIntent pi = PendingIntent.getBroadcast(mContext,
alarmid, i, PendingIntent.FLAG_UPDATE_CURRENT);
ReminderManager.mAlarmManager.cancel(pi);
}

Related

Android: get position within ListView on Long Click

So, I know that there are plenty of similar questions on Stack; however, none of them managed to solve my issue.
I have a ListActivity activity for displaying a list of usernames;
I created a UserObj class to collect information about each user, i.e., UserObj instance (username, password, etc..).
Now I am showing successfully the username within my ListView and I also managed to show a floating ContextMenu with some items (Delete,ChangeUsername,ChangePassword,ChangeEmail) upon long-clicking on a particular username.
Below I post my ListActivity code:
public class ShowAccountList extends ListActivity {
List<UserObj> Allusers = new ArrayList<>(); // this is required to retrieve users from a local database
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_show_account_list);
final ListView UserList = (ListView)findViewById(android.R.id.list);
UserList.setLongClickable(true);
/*For completeness: here I fetch users from DB*/
DataBaseUserHelper dbusers = new DataBaseUserHelper(getApplicationContext());
dbusers.CreateTables();
Allusers = dbusers.getAllUsers();
dbusers.closeDB();
/*Let's build a 'username' list to display*/
List<String> namelist = new ArrayList<String>();
for(int i=0 ; i< Allusers.size() ; i++){
String uname = Allusers.get(i).username;
namelist.add(uname);
}
final ArrayAdapter<String> nameadapter = new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1,namelist);
UserList.setAdapter(nameadapter);
registerForContextMenu(UserList);
UserList.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
#Override
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
openContextMenu(parent);
/*This outputs the CORRECT position*/
System.out.println("Position: " + position + ", id: " + id);
return true;
}
});
}
#Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo){
super.onCreateContextMenu(menu, v, menuInfo);
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.user_context_menu, menu);
}
#Override
public boolean onContextItemSelected(MenuItem item){
AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
int selectedId = info.position; // HERE the problem shows up
// switch statement for debugging purposes
switch (item.getItemId()){
case R.id.DeleteUser:
System.out.println("DELETE USER");
return true;
case R.id.ChangeName:
System.out.println("CHANGE USERNAME");
return true;
case R.id.ChangeEmail:
System.out.println("CHANGE EMAIL");
return true;
case R.id.ChangePassword:
System.out.println("CHANGE PASSWORD");
return true;
default:
return super.onContextItemSelected(item);
}
}
}
However, what I need to do, obviously, is to actually trigger the execution of the 'delete user', 'change email', etc... tasks for the selected user; what I supposed was that the position of the corresponding list item would be required in order to know which user should have undergone these modifications.
So, following the suggestions of the majority of the questions (and of the corresponding answers) on this topic, I casted item.getMenuInfo() to AdapterContextMenuInfo within onContextItemSelected and then I tried to retrieve the position with:
int selectedId = info.position;
The problem is that when I select one menu item (e.g., the one corresponding to 'delete') the ANR dialog shows up and the following exception is reported:
java.lang.NullPointerException: Attempt to read from field 'int android.widget.AdapterView$AdapterContextMenuInfo.position' on a null object reference
What I can understand is that info.position is always null. But why?
What could be the problem in my code?
As you can see from the code above, I tried to see what happened when clicking each single menu item by printing a test string (e.g., "DELETE USER") and actually if I remove int selectedId = info.position; no crash occurs...
Thanks in advance
EDIT
After some diagnosis, I figured out that the menuInfo passed to onCreateContextMenu is NULL. So, I got a little bit closer to the origin of the problem.
Any idea why I am getting a NULL menuInfo?
I faced similar problem. My solution was to register view for context menu inside the adapter using activity.registerForContextMenu(view)
The position of the item or even UserObj can be set as tag in the view.
You can get the tag in the onCreateContextMenu() call and corresponding action could be invoked.
In the best way, you should create custom adapter, then implement custom listener in activity when event occur (onClick, onLongClick...)
About your problem, I think you was wrong when implement #rabhis idea.
Try my solution that I have implemented in my app:
(In my code, I used custom adapter with recycleview, so try to merge to your code)
Class implement:
public class ListHistoryAdapter extends RecyclerView.Adapter<ListHistoryAdapter.HistoryViewHolder> implements View.OnCreateContextMenuListener {
In public void onBindViewHolder method:
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// your code
}
});
holder.itemView.setOnCreateContextMenuListener(this);
holder.itemView.setTag(position);
Override in adapter:
#Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
MenuItem deleteItem = menu.add(Menu.NONE, 1, 1, "Delete");
final int pos = (int) v.getTag();
deleteItem.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
#Override
public boolean onMenuItemClick(MenuItem item) {
// your code
return true;
}
});
}

How do I call the Activity to start again?

I am creating a quiz to practice Android programming. I am able to run the Android program and it works fine. But now, I have added a ContextMenu. If I click any item, the Activity should restart with a new value. But it does not.
TextView Qsn;
Button TopicTitle;
Button Ybtn;
Button Nbtn;
String check;
#Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.history);
Qsn = (TextView) findViewById(R.id.Question);
TopicTitle = (Button)findViewById(R.id.Topictxt);
Ybtn = (Button)findViewById(R.id.Yesbtn);
Nbtn = (Button)findViewById(R.id.Nobtn);
Intent intent = getIntent();
Bundle bundle =intent.getExtras();
check=bundle.getString("Bundlekey") ;
TopicTitle.setText(check);
Toast.makeText(getApplicationContext(), check, Toast.LENGTH_SHORT) .show();
registerForContextMenu(TopicTitle);
if (check.matches("History")) {
....
}
}
The code check what topic has been selected and it works fine till here. But now I've added a ContextMenu so if the user wants to change the topic he can long-press on the button and select the topic and change his new topic for a new question.
#Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
getMenuInflater().inflate(R.menu.topic_selection_in_question, menu);
}
#Override
public boolean onContextItemSelected(MenuItem item) {
String Value_from_item ;
Value_from_item = (String) item.getTitle();
check = Value_from_item;
Intent intent = getIntent(); finish(); startActivity(intent);
return super.onContextItemSelected(item);
}
Where did I make the mistake? Is there an error in the logic? I do not get a runtime error. Everything works fine. I would be glad if you can help me out. Thanks in advance.
Instead of this code
Intent intent = getIntent(); finish(); startActivity(intent);
Use
Intent intent = new Intent(youractivity.this, Youractivity.class);
finish();
startActivity(intent);

Unable to start intent from within ListActivity OnItemListClick

I am trying to use the OnItemListClick method of ListActivity to launch a new activity with more specific information about the list item. To do this I am using a bundle as advised by the top answer of How do I pass an object from one activity to another on Android? but no matter what I try the OnItemListClick doesn't seem to do anything. I also tried without passing the bundle thinking that was causing a problem as advised here Using an intent to start new activity from ListActivity and that also does nothing onClick. How am I supposed to make it so when an item in the listview is clicked it returns the object associated with that row and passes it to a new activity?
public class TaskList extends ListActivity {
private ArrayList<Task> stuffToDo, completed;
private TaskAdapter t_adapter;
public Button add;
private File saveFile;
private Bundle clickBundle = new Bundle();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_task_list);
stuffToDo = new ArrayList<Task>();
completed = new ArrayList<Task>();
t_adapter = new TaskAdapter(this, R.layout.row_rl, stuffToDo);
setListAdapter(t_adapter);
}
#Override
protected void onListItemClick(ListView l, View v, int position, long id) {
super.onListItemClick(l, v, position, id);
// Make a bundle and put the Task selected in it then pass this to the
// intent to start the new activity
Intent launchIntent = new Intent(getApplicationContext(), TaskDisplay.class);
Log.d("Debug", "Intent made");
clickBundle.clear();
clickBundle.putSerializable("Task", stuffToDo.get(position));
Log.d("Debug", "Task put in bundle");
launchIntent.putExtras(clickBundle);
this.startActivity(launchIntent);
Log.d("Debug", "launched");
}
#Override
public boolean onMenuItemSelected(int featureId, MenuItem item) {
// TODO Auto-generated method stub
switch (item.getItemId()) {
case R.id.addtaskbutton:
promptUserForInfo();
t_adapter.notifyDataSetChanged();
// added for debug
saveInfo();
return true;
case R.id.cleartasks:
clearTasks();
t_adapter.notifyDataSetChanged();
return true;
}
return super.onMenuItemSelected(featureId, item);
}
and my code that is in the more specific activity
// Set the bundle equal to the extra put with the intent
input = this.getIntent().getExtras();
// If there are extras(a task) then assign it to the empty task variable
if (input != null){
task = (Task) input.getSerializable("Task");
}
here this mean you are pointing towards list.
change Intent launchIntent = new Intent(this, TaskDisplay.class);
to Intent launchIntent = new Intent(youractivityname.this, TaskDisplay.class);
or to Intent launchIntent = new Intent(getApplicationContext(), TaskDisplay.class);
and make this super.onListItemClick(l, v, position, id); first line of list item click method.
Try this...
this.startActivity(launchIntent);

How to get data from listview to context menu?

actually i got a problem while creating my project. I am having one list view in one screen where data comes from database & binds to it. I created one context menu here with two menus (view & delete). The problem i am facing is when i make a long click context menu occur & when i click on anyone of the menu it navigates to another screen. here i want the listview(which was clicked) item data to pass to next screen. By i am not getting it. This is the following code...
Main.java
/*******some code****/
DbHandler dbh=new DbHandler(GroupName.this);
ast=dbh.selectgroupnam(s);
//here "ast" is of ArrayList defined globally
ArrayAdapter<String> adp=new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1,ast);
lv.setAdapter(adp);
registerForContextMenu(lv);
lv.setOnItemClickListener(new OnItemClickListener(){
#Override
public void onItemClick(AdapterView<?> arg0, View v, int p, long arg3) {
// TODO Auto-generated method stub
TextView tv=(TextView)v;
String gnam=tv.getText().toString();
}});
}//on create
//context menu code
#Override
public void onCreateContextMenu(ContextMenu menu, View v,
ContextMenuInfo menuInfo) {
// TODO Auto-generated method stub
super.onCreateContextMenu(menu, v, menuInfo);
menu.add(0, v.getId(), 0, "View");
menu.add(0, v.getId(), 0, "Delete");
}
#Override
public boolean onContextItemSelected(MenuItem item) {
// TODO Auto-generated method stub
Toast.makeText(getApplicationContext(), "group name" + gnam,30).show();
if (item.getTitle() == "Delete") {
Toast.makeText(getApplicationContext(), "selected group" + gnam, 30).show();
startActivity(new Intent(GroupName.this,GroupEdit.class));
}
else
{
startActivity(new Intent(GroupName.this,GroupEdit.class));
}
return super.onContextItemSelected(item);
}
As per the following code how to get the list view data (which was long clicked for context menu) & pass the data to GroupEdit.class.
Waiting for reply......
So you start activity startActivity(new Intent(GroupName.this,GroupEdit.class))
but any data you are adding to intent.
So try it with putExtra(<key>,<data>) or if you want to use Bundle so putExtras(<bundle>)
You should to it like this:
Intent i = new Intent(GroupName.this,GroupEdit.class);
i.putExtra("key", <data>);
startActivity(i);
Then in new Activity GroupEdit you get this data with getIntent() method that return the intent that started this activity and getExtras() with it you retrieve a map of extended data from the intent.
So in GroupEdit String text = getIntent().getExtras().getString("keyOfField")
Of you will use Bundle so
Intent i = new Intent(GroupName.this,GroupEdit.class);
i.putExtras(bundle);
startActivity(i);
in GroupEdit you retrieve data with Bundle data = getIntent().getExtras()
Regards

Force close if not select a list?

In my app I get a Force Close, and I don't know how to solve this. The problem is that I have a class that extends ListActivity. In this class there is a list of shops, and the user should select one of the shops. If he not select a shop and press button Back I get Force Close, because the previous class expect the name of the shop. How can I catch this error?
Here is my class for selecting a shop :
public class SelectShop extends ListActivity {
private ListView lv1;
SimpleCursorAdapter adapter = null;
Cursor cursor;
DbAdapter db;
ImageView iconshop;
private static final int ADD=Menu.FIRST;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.shopselect);
iconshop = (ImageView) findViewById(R.id.iconshop);
lv1 = getListView();
DbApplication myApplication = (DbApplication) this.getApplication();
db= myApplication.getDatabaseAdapter();
cursor = db.getAllShops();
startManagingCursor(cursor);
if (cursor != null && cursor.moveToFirst()){
adapter = new SimpleCursorAdapter(this, R.layout.shopsrow, cursor,
new String[] { DbAdapter.NAME, DbAdapter.ADRESS }, new int[] {
R.id.title, R.id.address });
setListAdapter(adapter);
}else Toast.makeText(this,
"Choose Menu for adding a shop",
Toast.LENGTH_LONG).show();
lv1.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View v,
int position, long id) {
Intent j = new Intent(SelectShop.this,
com.ShoppingList.NewList.class);
Cursor c = (Cursor) parent.getAdapter().getItem(position);
j.putExtra("shop", c.getString(c.getColumnIndex(db.NAME)));
setResult(RESULT_OK, j);
finish();
}
});
}
/*Adaugarea meniului Add Shop*/
public boolean onCreateOptionsMenu(Menu menu) {
menu.add(0, ADD, 0, "Add Shop").setIcon(R.drawable.additem);
return true;
}
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case ADD:
Intent j = new Intent(SelectShop.this, Shops.class);
startActivityForResult(j, 0);
return true;
}
return false;
}
}
and in previuos class I have this:
public void onActivityResult(int requestCode, int resultCode, Intent intent) {
super.onActivityResult(requestCode, resultCode, intent);
switch (requestCode) {
case 0: {
Bundle b = intent.getExtras();
shopselect = b.getString("shop");
shop.setText(shopselect);
}
break;
}
}
You have to check the null condition in onActivityResult like below.
if(b != null)
{
shopselect = b.getString("shop"); shop.setText(shopselect);
}
I think you need to implement a mechanism that won't let your user get back to previous activity without choosing any item in the list. Override your onKeyDown() method, and when the user presses Back key you should check whether any item is chosen. If it's not you can throw an alert dialog to inform user what he must do to proceed. Hope this helps!
Check the result code. do your thing only if the result code is Activity.RESULT_OK.

Categories

Resources