I have a ListFragment with a Custom CursorAdapter connected to a database. The items in the database are not appearing in the ListView, including the ListHeader, and instead I see only a spinning wheel.
I had my app working fine with a SimpleCursorAdapter in the ListFragment before. I have tested this on non-empty databases.
The only clue I have as to why this is not working is that I get the following error in LogCat when I try the "Delete All" option in the ContextActionMenu.
ViewRootImpl sendUserActionEvent() == null
Here is the ListFragment:
import com.actionbarsherlock.app.SherlockListFragment;
import com.actionbarsherlock.view.ActionMode;
import com.actionbarsherlock.view.ActionMode.Callback;
import com.actionbarsherlock.view.Menu;
import com.actionbarsherlock.view.MenuInflater;
import com.actionbarsherlock.view.MenuItem;
import info.mariegrap.dancejournal.R.id;
import info.mariegrap.database.DanceContentProvider;
import info.mariegrap.database.DanceDatabaseHelper;
import info.mariegrap.database.StyleCursorAdapter;
import info.mariegrap.database.StyleTable;
import info.mariegrap.model.Style;
import android.app.Activity;
import android.content.ContentValues;
import android.content.Context;
import android.net.Uri;
import android.os.Bundle;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemLongClickListener;
import android.widget.ListView;
import android.database.Cursor;
import android.database.SQLException;
public class StyleFragment extends SherlockListFragment implements LoaderManager.LoaderCallbacks<Cursor>{
private static final int LOADER_ID = 0;
private Context context;
private OnStyleSelectedListener callback;
private StyleCursorAdapter styleAdapter;
private DanceDatabaseHelper myDbHelper;
private Callback mActionModeCallback;
private ActionMode mActionMode;
private long selectedId;
#Override
public void onActivityCreated(Bundle savedInstanceState){
super.onActivityCreated(savedInstanceState);
context = this.getActivity();
setHasOptionsMenu(true);
//setRetainInstance(true);
this.getListView().setBackgroundColor(getResources().getColor(R.color.style_background));
//this.getListView().setDividerHeight(0);
this.getListView().setScrollingCacheEnabled(true);
this.getListView().addHeaderView(new ListHeader(context,
this.getResources().getString(R.string.list_header_style_title),
this.getResources().getString(R.string.list_header_style_subtitle)));
this.setActionModeCallback();
this.setLongClickListener();
/*myDbHelper = new DanceDatabaseHelper(this.context, null,
null, 1);
try {
myDbHelper.openDataBase();;
}catch(SQLException sqle){
throw sqle;
}*/
this.styleAdapter = new StyleCursorAdapter(context, null, 0);
getLoaderManager().initLoader(LOADER_ID, null, this);
this.getListView().setAdapter(this.styleAdapter);
Log.d("mgrap", "Adapter: " + styleAdapter);
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
callback = (OnStyleSelectedListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ " must implement OnStyleSelectedListener");
}
}
#Override
public void onListItemClick(ListView l, View v, int position, long id){
if (position == 0){
return;
}
this.setListAdapter(null);
this.getListView().getChildAt(position);
callback.onStyleSelected(position);
}
public interface OnStyleSelectedListener {
/** Called by StyleFragment when a list item is selected */
public void onStyleSelected(int position);
}
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.style_actionbar, menu);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.style_add:
ContentValues cv = new ContentValues();
cv.put(StyleTable.STYLE_KEY_NAME, "Tada!");
Uri uri = Uri.parse("content://info.mariegrap.dancejournal.provider/style_table/0");
Uri idUri = context.getContentResolver().insert(uri, cv);
//styleAdapter.notifyDataSetChanged();
fillData();
return true;
case R.id.style_delete_all:
Uri delete_uri = Uri.parse("content://info.mariegrap.dancejournal.provider/style_table");
context.getContentResolver().delete(delete_uri, null, null);
//styleAdapter.notifyDataSetChanged();
fillData();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
protected void fillData() {
this.getSherlockActivity().getSupportLoaderManager().restartLoader(LOADER_ID, null, this);
this.getListView().setAdapter(styleAdapter);
}
protected void deleteStyle(long id) {
Uri uri = Uri.parse("content://info.mariegrap.dancejournal.provider/style_table/" + id);
this.getSherlockActivity().getContentResolver().delete(uri, null, null);
//styleAdapter.notifyDataSetChanged();
fillData();
}
#Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
String[] projection = { StyleTable.STYLE_KEY_ID, StyleTable.STYLE_KEY_NAME };
return new CursorLoader(this.context,
DanceContentProvider.CONTENT_URI_STYLE, projection, null, null, null);
}
#Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
styleAdapter.swapCursor(data);
}
#Override
public void onLoaderReset(Loader<Cursor> loader) {
styleAdapter.swapCursor(null);
}
private void setActionModeCallback(){
mActionModeCallback = new Callback() {
#Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
MenuInflater inflater = mode.getMenuInflater();
inflater.inflate(R.menu.style_context_menu, menu);
return true;
}
#Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
return false;
}
#Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
switch (item.getItemId()) {
case R.id.style_delete:
deleteStyle(selectedId);
mode.finish();
return true;
default:
return false;
}
}
#Override
public void onDestroyActionMode(ActionMode mode) {
mActionMode = null;
}
};
}
private void setLongClickListener(){
this.getListView().setOnItemLongClickListener (new OnItemLongClickListener() {
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
if (mActionMode != null || position == 0) {
return false;
}
mActionMode = getSherlockActivity().startActionMode(mActionModeCallback);
selectedId = id;
return true;
}
});
}
}
Here is the Custom CursorAdapter:
import view.StyleListItem;
import info.mariegrap.model.Style;
import android.content.Context;
import android.database.Cursor;
import android.support.v4.widget.CursorAdapter;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
public class StyleCursorAdapter extends CursorAdapter {
public StyleCursorAdapter(Context context, Cursor c, int flags) {
super(context, c, flags);
}
#Override
public void bindView(View arg0, Context arg1, Cursor arg2) {
int id = arg2.getInt(StyleTable.STYLE_COL_ID);
String name = arg2.getString(StyleTable.STYLE_COL_NAME);
Style style = new Style(name, id);
StyleListItem listItem = (StyleListItem) arg0;
listItem.setStyle(style);
}
#Override
public View newView(Context arg0, Cursor arg1, ViewGroup arg2) {
int id = arg1.getInt(StyleTable.STYLE_COL_ID);
String name = arg1.getString(StyleTable.STYLE_COL_NAME);
Style style = new Style(name, id);
StyleListItem listItem = new StyleListItem(arg0, style);
listItem.setStyle(style);
Log.d("mgrap", "Adapter view: " + listItem.getStyleId());
return listItem;
}
}
Here is the ListItem View:
public class StyleListItem extends LinearLayout {
private TextView styleView;
private Style style;
public StyleListItem(Context context, Style style) {
super(context);
LayoutInflater inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.style_row, this, true);
styleView = (TextView)findViewById(R.id.style_label);
Log.d("mgrap", "Style View: " + styleView);
setStyle(style);
}
public void setStyle(Style style) {
this.style = style;
displayStyle(this.style);
}
public Style getStyle(){
return style;
}
private void displayStyle(Style style) {
if (style != null) {
styleView.setText(style.getName());
}
}
public int getStyleId() {
return styleView.getId();
}
}
Here is the layout xml for the list items:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<ImageView
android:id="#+id/icon"
android:layout_width="30dp"
android:layout_height="24dp"
android:layout_marginLeft="4dp"
android:layout_marginRight="8dp"
android:layout_marginTop="8dp"
android:src="#drawable/ic_launcher" >
</ImageView>
<TextView
android:id="#+id/style_label"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="6dp"
android:lines="1"
android:text="#+id/TextView01"
android:textSize="24sp"
>
</TextView>
</LinearLayout>
Here is the xml layout for the list header:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/list_header_background_color"
android:layout_marginBottom="5dip" >
<LinearLayout
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:orientation="vertical"
android:paddingTop="5dip"
android:paddingLeft="10dip"
android:paddingBottom="13dip"
android:layout_centerVertical="true"
android:layout_alignParentLeft="true">
<TextView
android:id="#+id/listview_header_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/list_header_style_title"
android:textSize="17sp"
android:textStyle="bold"
android:textColor="#color/list_header_title_color"
/>
<TextView
android:id="#+id/listview_header_subtitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/list_header_style_subtitle"
android:textSize="13sp"
android:textColor="#color/list_header_subtitle_color"
/>
</LinearLayout>
<ImageView
android:id="#+id/list_header_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_alignParentRight="true"
android:layout_marginRight="20dp"
android:layout_marginTop="5dp"
android:layout_marginBottom="13dp"
android:visibility="gone"
android:contentDescription="#string/image_desc"
/>
</RelativeLayout>
And here is the class that defines the style database table:
import android.database.sqlite.SQLiteDatabase;
import android.util.Log;
public class StyleTable {
/** Style table in the database. */
public static final String TABLE_STYLE = "style_table";
/** Style table column names and IDs for database access. */
public static final String STYLE_KEY_ID = "_id";
public static final int STYLE_COL_ID = 0;
public static final String STYLE_KEY_NAME = "name";
public static final int STYLE_COL_NAME = STYLE_COL_ID + 1;
/** SQLite database creation statement. Auto-increments IDs of inserted
* styles. Style IDs are set after insertion into the database. */
public static final String DATABASE_CREATE = "create table " +
TABLE_STYLE + " (" +
STYLE_KEY_ID + " integer primary key autoincrement, " +
STYLE_KEY_NAME + " text);";
/** SQLite database table removal statement. Only used if upgrading
* database. */
public static final String DATABASE_DROP = "drop table if exists " +
TABLE_STYLE;
/**
* Initializes the database.
*
* #param database
* The database to initialize.
*/
public static void onCreate(SQLiteDatabase database) {
database.execSQL(DATABASE_CREATE);
}
/**
* Upgrades the database to a new version.
*
* #param database
* The database to upgrade.
* #param oldVersion
* The old version of the database.
* #param newVersion
* The new version of the database.
*/
public static void onUpgrade(SQLiteDatabase database, int oldVersion,
int newVersion)
{
Log.w("mgrap", "updating database...");
database.execSQL(DATABASE_DROP);
onCreate(database);
}
}
It's hard to say without having some more logging to go with, but there are a couple things that jump out:
The adapter is being set on the list view directly instead of calling setAdapter on the ListFragment. This usually causes problems.
You're setting the list view's adapter after initializing the loader. This might not be a race condition since the callbacks would probably be called in the main loop after your call is finished, but I wouldn't count on it.
Related
My ListView works fine on start up. The problem is that whenever I click the search Button which triggers the search view, all items on my ListView disappears. Even after I clear the text field on my searchview, my ListView still is on a state where it is empty.
Loanist_Full.java (Main activity)
package com.memger.pautanganapp;
import android.content.DialogInterface;
import android.content.Intent;
import android.database.DataSetObserver;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.SearchView;
import android.text.TextUtils;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.ListView;
import android.widget.TextView;
import com.getbase.floatingactionbutton.FloatingActionButton;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
public class Loanist_Full extends AppCompatActivity {
private ListView listView;
private ListView_Adapter adapter;
private ListView_Model model;
private ArrayList<ListView_Model> arrayList = new ArrayList<ListView_Model>();
private MenuItem searchItem;
private SearchView searchView;
private TextView totalText, totalCount;
private ImageButton sortBy;
private FloatingActionButton addDebtorButton;
public static final String currency = "₱";
public static final DecimalFormat formatter = new DecimalFormat("###,###,###.##");
String mContact[] = {"Craig", "Agatha", "Dave", "Brandon", "Russel", "Gleceper", "Percy", "Test"};
double mDebt[] = {2000, 525, 8000, 5000, 955, 4000, 50123, 51247};
double mDebtTotal = 0;
String mDesc[] = {"This is a description et. cetera", "Ito bata pa dapat di pa pinapautang", "Lalo na to kakatuto lang mag bike nangungutang na", "", "", "", "", ""};
String mDate[] = {"Apr. 21, 2016", "Mar. 4, 2017", "May 14, 2011", "Mar. 1, 2000", "Jul. 14, 1971", "", "", ""};
int mImg[] = {R.drawable.debtcontact_craig, R.drawable.debtcontact_agatha, R.drawable.debtcontact_dave, R.drawable.debtcontact_brandon, R.drawable.debtcontact_russel, R.drawable.debtcontact_gleceper, R.drawable.debtcontact_lola, R.drawable.ic_launcher_background};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.loanist_full);
totalText = findViewById(R.id.TotalTextView);
totalCount = findViewById(R.id.CountTextView);
listView = findViewById(R.id.listView);
adapter = new ListView_Adapter(this, arrayList);
listView.setAdapter(adapter);
sortBy = findViewById(R.id.SortByButton);
addDebtorButton = findViewById(R.id.AddDebtorButton);
/* TO DO */
displayListViewContents();
setTextTotal();
/* OnClickListeners below */
/* Listview item */
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
makeDialog(ListView_Adapter.modellist.get(i).getModelContact(),
ListView_Adapter.modellist.get(i).getModelDebt(),
ListView_Adapter.modellist.get(i).getModelDesc(),
ListView_Adapter.modellist.get(i).getModelDate());
}
});
/* Sort by button*/
sortBy.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
sortArray();
sortArrayList();
}
});
/* Debtor Button*/
addDebtorButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
startActivity(new Intent(Loanist_Full.this, Loanist_Add_Debtor.class));
}
});
} /* END onCreate*/
/* Display listview contents */
private void displayListViewContents(){
/* Display contents of listview*/
for(int i = 0; i < mDebt.length; i++){
model = new ListView_Model(mContact[i], mDebt[i], mDesc[i], mDate[i], mImg[i]);
arrayList.add(model);
}
totalCount.setText("Count: " + adapter.getCount());
adapter.registerDataSetObserver(new DataSetObserver() {
#Override
public void onChanged() {
totalCount.setText("Count: " + adapter.getCount());
}
});
}
/* Set "Total" view text */
private void setTextTotal(){
/* Set text of Total based on total amt of mDebt*/
for (double x: mDebt) { //Compute total mDebt
mDebtTotal += x;
}
if (mDebtTotal == 0){ //If mDebtTotal == 0
totalText.setText("Create a debt with an amount first.");
} else {
totalText.setText("Total: " + currency + " " + formatter.format(mDebtTotal));
}
}
/* Sort item list */
private void sortArray(){
Arrays.sort(mContact);
adapter.notifyDataSetChanged();
}
/* Sort array list */
private void sortArrayList(){
Collections.sort(arrayList, new Comparator<ListView_Model>() {
#Override
public int compare(ListView_Model listView_model, ListView_Model t1) {
return listView_model.getModelContact().compareTo(t1.getModelContact());
}
});
adapter.notifyDataSetChanged();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_main, menu);
searchItem = menu.findItem(R.id.app_searchbutton);
searchItem.getActionView();
searchView = (SearchView) searchItem.getActionView();
searchView.setQueryHint("Enter a contact e.g 'Robert'");
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
#Override
public boolean onQueryTextSubmit(String query) {
return false;
}
#Override
public boolean onQueryTextChange(String newText) {
if (TextUtils.isEmpty(newText)){
adapter.filter("");
listView.clearTextFilter();
}
else {
adapter.filter(newText);
}
//totalCount.setText("Count: " + adapter.getCount());
return true;
}
});
return true;
}
/* Creates a dialog whenever an item on listview is clicked*/
private void makeDialog(String contact, double debtAmt, String debtDesc, String debtDate){
AlertDialog alertDialog = new AlertDialog.Builder(Loanist_Full.this).create();
alertDialog.setTitle("Debt Information");
if (debtDesc.length() < 1)
debtDesc = "N/A";
if (debtDate.length() < 1)
debtDate = "N/A";
alertDialog.setMessage("\n" + contact + "'s debt is " + this.currency + " " + debtAmt + "\n\nDescription: " + debtDesc + "\nDebt created: " + debtDate);
alertDialog.setButton(AlertDialog.BUTTON_NEUTRAL, "OK",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
alertDialog.show();
}
}
Loanist_full.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
tools:context=".Loanist_Full">
<LinearLayout
android:id="#+id/TotalBar"
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="#eaeaea"
android:orientation="horizontal"
>
<TextView
android:id="#+id/TotalTextView"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginLeft="15dp"
android:gravity="center_vertical"
android:text="Total"
android:textSize="16dp"
android:textStyle="bold"
android:layout_weight="1"
/>
<TextView
android:id="#+id/CountTextView"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginRight="15dp"
android:gravity="center_vertical"
android:text="Count"
android:textSize="14dp"
/>
<ImageButton
android:id="#+id/SortByButton"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_marginRight="15dp"
android:layout_gravity="center_vertical"
android:src="#drawable/ic_sort_black_24dp"
android:background="?android:selectableItemBackground"/>
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="3.0dip"
android:background="#drawable/divider_total"
android:layout_below="#id/TotalBar"
/>
<ListView
android:id="#+id/listView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:divider="#drawable/divider_listview"
android:dividerHeight="0.2dp"
android:layout_below="#id/TotalBar"
/>
<com.getbase.floatingactionbutton.AddFloatingActionButton
android:id="#+id/AddDebtorButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_alignParentBottom="true"
android:layout_margin="8dp"
app:fab_colorNormal="#color/lightYellow"
app:fab_colorPressed="#color/lightYellowPressed"
/>
</RelativeLayout>
ListView_Adapter.java
package com.memger.pautanganapp;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
public class ListView_Adapter extends BaseAdapter {
Context mcontext;
LayoutInflater inflater;
public static List<ListView_Model> modellist;
ArrayList<ListView_Model> arrayList;
public ListView_Adapter(Context context, List<ListView_Model> modellist){
mcontext = context;
inflater = LayoutInflater.from(mcontext);
this.modellist = modellist;
this.arrayList = new ArrayList<ListView_Model>();
this.arrayList.addAll(modellist);
}
public class ViewHolder{
TextView myContact, myDebt, myDesc, myDate;
ImageView myImg;
}
#Override
public int getCount() {
return modellist.size();
}
#Override
public Object getItem(int i) {
return modellist.get(i);
}
#Override
public long getItemId(int i) {
return i;
}
#NonNull
#Override
public View getView(int position, #Nullable View convertView, #NonNull ViewGroup parent) {
ViewHolder holder;
if (convertView == null){
holder = new ViewHolder();
convertView = inflater.inflate(R.layout.listview_row, null);
holder.myContact = convertView.findViewById(R.id.Contact);
holder.myDebt = convertView.findViewById(R.id.Debt);
holder.myDesc = convertView.findViewById(R.id.Desc);
holder.myDate = convertView.findViewById(R.id.Date);
holder.myImg = convertView.findViewById(R.id.ContactImage);
convertView.setTag(holder);
} else {
holder = (ViewHolder)convertView.getTag();
}
holder.myContact.setText(modellist.get(position).getModelContact());
holder.myDebt.setText(Loanist_Full.currency + " " + Loanist_Full.formatter.format(modellist.get(position).getModelDebt()));
holder.myDate.setText(modellist.get(position).getModelDate());
holder.myDesc.setText(modellist.get(position).getModelDesc());
holder.myImg.setImageResource(modellist.get(position).getModelImg());
return convertView;
}
/* Filter */
public void filter(String charText){
charText = charText.toLowerCase(Locale.getDefault());
modellist.clear();
if (charText.length()==0){
modellist.addAll(arrayList);
}
else {
for (ListView_Model model : arrayList){
if (model.getModelContact().toLowerCase(Locale.getDefault()).contains(charText)){
modellist.add(model); //Add to modellist those who contain the words in the search bar
}
}
}
notifyDataSetChanged();
}
}
I am currently working on an app, the final goal of it is that you click a button and it will display a random challenge that is stored in the sqlLite DB.
I can't manage to take a random row of it, even with all the tutorials and the posts on StackOverflow talking about it, maybe my current level and knowledge are to small to make it work. Perhaps the fact that I use it in a Fragment can make it even harder.
Because I can't manage to take directly a random row in my DB, I thought about using an arrayList to store the string stored in the column "Gage" of all the rows of my db, and then take a random element of this arrayList.
So, if someone knows what is wrong, please help me.
Data Base Class
package com.thebatz.game20;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
public class PenanceDB extends SQLiteOpenHelper {
private static final int DATA_BASE_VERSION = 1;
private static final String TABLE_NAME = "Penance";
private static final String ID = "ID";
private static final String Gage = "GAGE";
private static final String DATABASE_NAME = "Penance.db";
public PenanceDB(Context context){
super(context, DATABASE_NAME, null, DATA_BASE_VERSION);
}
#Override
public void onCreate(SQLiteDatabase dbPen) {
dbPen.execSQL("create table " + TABLE_NAME+ "(ID INTEGER PRIMARY KEY AUTOINCREMENT, GAGE TEXT, TIME INTEGER)" );
}
#Override
public void onUpgrade(SQLiteDatabase dbPen, int oldVersion, int newVersion) {
dbPen.execSQL("DROP TABLE IF EXISTS" + TABLE_NAME);
onCreate(dbPen);
}
public boolean insertPen(String gageNom) {
SQLiteDatabase dbPen = this.getWritableDatabase();
ContentValues contentValues = new ContentValues();
contentValues.put(Gage, gageNom);
long result = dbPen.insert(TABLE_NAME, null, contentValues);
if(result == -1)
return false;
else
return true;
}
public Cursor getDataPen(){
SQLiteDatabase dbPen = this.getWritableDatabase();
Cursor res = dbPen.rawQuery("select * from " +TABLE_NAME, null);
return res;
}
public boolean penitenceUpdate(String id, String penitence) {
SQLiteDatabase dbPen = this.getWritableDatabase();
ContentValues contentValues = new ContentValues();
contentValues.put(ID, id);
contentValues.put(Gage, penitence);
dbPen.update(TABLE_NAME, contentValues, "ID = ?", new String[] {id});
return true;
}
}
Fragment class
package com.thebatz.game20;
import android.database.Cursor;
import android.support.v7.app.AlertDialog;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.lang.String;
public class GameActivity extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.activity_game, container, false);
return rootView;
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
final Button btnViewPen = (Button) getView().findViewById(R.id.btnGamePen);
final Button btnViewAw = (Button) getView().findViewById(R.id.btnGameAw);
final PenanceDB myPen = new PenanceDB(getActivity());
final AwardDB myAw = new AwardDB(getActivity());
final List<String> Penance = new ArrayList<>();
final List<String> Award = new ArrayList<>();
btnViewPen.setOnClickListener(
new View.OnClickListener() {
#Override
public void onClick(View v) {
Cursor res = myPen.getDataPen();
if(res.getCount() == 0){
showMessage("Erreur 404", "Base de données vide");
return;
}
//Putt sqlite data into an array list
while (res.moveToNext()) {
Penance.add(res.getString(res.getColumnIndex("Gage")));
}
//Take a randome one
int iD = new Random().nextInt(Penance.size());
String item = Penance.get(iD);
//call the methode to display it
showMessage("Gages: ", item);
}
}
);
btnViewAw.setOnClickListener(
new View.OnClickListener() {
#Override
public void onClick(View v) {
Cursor res = myAw.getDataRec();
if(res.getCount() == 0){
showMessage("Erreur 404", "Base de données vide");
return;
}
while (res.moveToNext()) {
Award.add(res.getString(res.getColumnIndex("Gage")));
}
int iD = new Random().nextInt(Award.size());
String item = Award.get(iD);
showMessage("Gages", item);
}
}
);
}
public void showMessage(String title, String Message){
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setCancelable(true);
builder.setTitle(title);
builder.setMessage(Message);
builder.show();
}
}
XML file of the fragment
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.thebatz.game20.GameActivity">
<Button
android:id="#+id/btnGamePen"
style="#style/Widget.AppCompat.Button.Colored"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:layout_marginTop="138dp"
android:background="#android:color/holo_red_dark"
android:text="#string/p_nitence"
app:layout_constraintHorizontal_bias="0.501"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="#+id/btnGameAw"
style="#style/Widget.AppCompat.Button.Colored"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:layout_marginTop="8dp"
android:background="#android:color/holo_green_dark"
android:text="#string/r_compences"
android:textColorLink="#android:color/background_light"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="#+id/btnGamePen"
app:layout_constraintVertical_bias="0.509" />
</android.support.constraint.ConstraintLayout>
How about creating the random number before executing the SQL command - Then when you use your SELECT statement you could include the random number variable as the ID to query?
I'm trying to do a simple retrieval of data from SQLite Database to the SearchView.
My problem is the SearchView is not populated with respect to the data stored in the database, although it always shows the green signal of
successfully created the database
Below is the code.
fragment_search.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#E6E6E6"
android:orientation="vertical" >
<View
android:id="#+id/view1"
android:layout_width="match_parent"
android:layout_height="45dp"
android:layout_alignParentTop="true"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
android:layout_marginTop="5dp"
android:background="#FFFFFF" />
<SearchView
android:id="#+id/searchView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:layout_marginTop="3dp" >
</SearchView>
<ListView
android:id="#+id/listview_search"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="#+id/searchView"
android:layout_centerHorizontal="true"
android:divider="#E6E6E6"
android:dividerHeight="5dp" />
<LinearLayout
android:id="#+id/rightLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignBottom="#+id/view1"
android:layout_alignTop="#+id/view1"
android:orientation="vertical"
android:paddingTop="25dp" >
</LinearLayout>
</RelativeLayout>
Search_list.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<LinearLayout
android:id="#+id/hotelLayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
<TableRow
android:id="#+id/section_search"
android:layout_width="wrap_content"
android:layout_height="match_parent" >
<GridLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:columnCount="2" >
<ImageView
android:id="#+id/hotel_image"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_gravity="left"
android:src="#drawable/aaa" />
<EditText
android:id="#+id/hotel_name"
android:layout_width="209dp"
android:layout_height="56dp"
android:layout_gravity="fill_horizontal" >
<requestFocus />
</EditText>
<EditText
android:id="#+id/hotel_city"
android:layout_width="96dp"
android:layout_column="1"
android:layout_gravity="left|bottom"
android:layout_row="0"
android:ems="10" />
<EditText
android:id="#+id/hotel_country"
android:layout_width="106dp"
android:layout_column="1"
android:layout_gravity="right|bottom"
android:layout_row="0"
android:ems="10" />
</GridLayout>
</TableRow>
</LinearLayout>
</RelativeLayout>
TableData.java
package com.mytry.test;
import android.provider.BaseColumns;
public class TableData
{
public TableData()
{
}
public static abstract class TableInfo implements BaseColumns
{
public static final String DATABASE_NAME = "tourDguide";
public static final String TABLE_NAME = "Hotels";
public static final String HOTEL_ID = "id";
public static final String HOTEL_NAME = "hotel_name";
public static final String HOTEL_ADDRESS = "hotel_address";
public static final String HOTEL_CITY = "hotel_city";
public static final String HOTEL_COUNTRY = "hotel_country";
public static final String HOTEL_POSTAL = "postal_code";
}
}
DataBaseHandler.java
package com.mytry.test;
import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;
import com.mytry.test.TableData.TableInfo;
public class DataHandler
{
public static final int DATABASE_VERSION = 1;
SQLiteDatabase db;
DataBaseHelper dbhelper;
Context ctx;
private static class DataBaseHelper extends SQLiteOpenHelper
{
public String CREATE_QUERY = "CREATE TABLE "+TableInfo.TABLE_NAME+"("+TableInfo.HOTEL_ID+" INTEGER PRIMARY KEY AUTOINCREMENT,"+TableInfo.HOTEL_NAME+" VARCHAR,"+TableInfo.HOTEL_ADDRESS+" VARCHAR,"+TableInfo.HOTEL_CITY+" VARCHAR,"+TableInfo.HOTEL_COUNTRY+" VARCHAR,"+TableInfo.HOTEL_POSTAL+" INT );";
public DataBaseHelper(Context ctx) {
super(ctx,TableInfo.DATABASE_NAME, null, DATABASE_VERSION);
Log.d("Database Operations", "Successfully Created Database");
// TODO Auto-generated constructor stub
}
#Override
public void onCreate(SQLiteDatabase db) {
// TODO Auto-generated method stub
try{
db.execSQL(CREATE_QUERY);
Log.d("Database Operations", "Successfully Created Table");
}
catch(SQLException e)
{
e.printStackTrace();
}
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("Drop table if exists "+TableInfo.TABLE_NAME);
onCreate(db);
}
}
public DataHandler(Context ctx) {
this.ctx = ctx;
dbhelper = new DataBaseHelper(ctx);
// TODO Auto-generated constructor stub
}
public DataHandler open()
{
dbhelper = new DataBaseHelper(ctx);
db = dbhelper.getReadableDatabase();
return this;
}
public void close()
{
dbhelper.close();
}
public Cursor searchHotels(String inputText) throws SQLException
{
String query = "Select "+TableInfo.HOTEL_ID+" as _id,"+TableInfo.HOTEL_NAME+","+TableInfo.HOTEL_ADDRESS+","+TableInfo.HOTEL_CITY+","+TableInfo.HOTEL_COUNTRY+","+TableInfo.HOTEL_POSTAL+" from "+TableInfo.TABLE_NAME+" where "+TableInfo.HOTEL_NAME+" LIKE '" + inputText + "';";
Log.d("table operations","Successfully transferred query");
Cursor cr = db.rawQuery(query, null);
if(cr!=null)
{
cr.moveToFirst();
}
return cr;
}
}
SeachViewActivity.java
package com.mytry.test;
import com.mytry.test.TableData.TableInfo;
import android.R.anim;
import android.app.Activity;
import android.app.DownloadManager.Query;
import android.content.Context;
import android.database.Cursor;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.SearchView;
import android.widget.SimpleAdapter;
import android.widget.SimpleCursorAdapter;
import android.widget.TextView;
import android.widget.AdapterView.OnItemClickListener;
public class SearchViewActivity extends Activity implements SearchView.OnQueryTextListener,SearchView.OnCloseListener
{
private ListView list;
private SearchView search;
private DataHandler dbHandler;
private TextView name,city,country;
private EditText edit;
Context ctx=this;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.fragment_search);
search = (SearchView) this.findViewById(R.id.searchView);
list = (ListView) this.findViewById(R.id.listview_search);
name = (TextView)this.findViewById(R.id.hotel_name);
city = (TextView)this.findViewById(R.id.hotel_city);
country = (TextView)this.findViewById(R.id.hotel_country);
search.setIconifiedByDefault(false);
search.setOnQueryTextListener(this);
search.setOnCloseListener(this);
dbHandler = new DataHandler(getBaseContext());
dbHandler.open();
}
public boolean onQueryTextSubmit(String query)
{
showResults(query + "*");
return false;
}
public boolean onQueryTextChange(String newText)
{
showResults(newText + "*");
return false;
}
public boolean onClose()
{
showResults("");
return false;
}
private void showResults(String query)
{
Cursor cr = dbHandler.searchHotels((query!=null?query.toString(): "####"));
if(cr==null)
{
}
else
{
String[] from = new String[]
{TableInfo.HOTEL_NAME,TableInfo.HOTEL_ADDRESS,TableInfo.HOTEL_CITY,TableInfo.HOTEL_COUNTRY,TableInfo.HOTEL_POSTAL};
int[] to = new int[]{R.id.hotel_name,R.id.hotel_city,R.id.hotel_country};
SimpleCursorAdapter hotels = new SimpleCursorAdapter(this,R.layout.search_list, cr, from, to);
list.setAdapter(hotels);
list.setOnItemClickListener(new OnItemClickListener()
{
public void onItemClick(AdapterView<?> parent, View view, int position, long id)
{
Cursor cr = (Cursor)list.getItemAtPosition(position);
String hotel_name = cr.getString(cr.getColumnIndexOrThrow("hotel_name"));
String hotel_city = cr.getString(cr.getColumnIndexOrThrow("hotel_city"));
String hotel_country = cr.getString(cr.getColumnIndexOrThrow("hotel_country"));
LinearLayout hotelLayout = (LinearLayout)findViewById(R.id.hotelLayout);
if(hotelLayout == null){
//Inflate the Customer Information View
LinearLayout leftLayout = (LinearLayout)findViewById(R.id.rightLayout);
View hotelInfo = getLayoutInflater().inflate(R.layout.search_list, leftLayout, false);
leftLayout.addView(hotelInfo);
}
name.setText(hotel_name);
city.setText(hotel_city);
country.setText(hotel_country);
search.setQuery("", true);
}
});
}
}
}
I am trying to fetch values from the database when I click on the view button which is another activity for navigation when I click on the view all button the CustodianViewActivity is triggered to display all the values from the database on a list view but in my case the application crashes every time I try to view the data from the database. Am not sure where I am going wrong.
Database Class
import android.content.ContentValues;
import android.content.Context;import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;
public class DBHandler extends SQLiteOpenHelper {
private static DBHandler instance;
// Database Name
public static final String DATABASE_NAME ="AssetDB.db";
//Database version
public static final int Databasevr = 1;
//Custodian Table Name
public static final String TABLE_CUSTODIAN = " Custodian";
// Columbs in the Custodian Table
public static final String CUSTODIAN_ID = "_CustID";
public static final String CUSTODIAN_NAME = "CustName";
public static final String CUSTODIAN_DESIGNATION = "CustDesign";
public static final String CUSTODIAN_DEPARTMENT = "CustDepart";private static final String CREATE_TABLE_CUSTODIAN = "CREATE TABLE" + TABLE_CUSTODIAN + "("
+ CUSTODIAN_ID + " INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,"
+ CUSTODIAN_NAME + " TEXT NOT NULL,"
+ CUSTODIAN_DESIGNATION + " TEXT NOT NULL,"
+ CUSTODIAN_DEPARTMENT + " TEXT NOT NULL" + ");";
// constructor passing parameter passing Database name and Database version
public DBHandler(Context ct)
{
super(ct, DATABASE_NAME, null, Databasevr);
}
#Override
public void onCreate(SQLiteDatabase db) {
// TODO Auto-generated method stub
// Creating the tables
db.execSQL(CREATE_TABLE_CUSTODIAN);
db.execSQL(CREATE_TABLE_ASSET);
Log.d("Tables","Tables have been created");
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// TODO Auto-generated method stub
// dropping the tables
db.execSQL("DROP TABLE IF EXISTS " + CREATE_TABLE_CUSTODIAN );
db.execSQL("DROP TABLE IF EXISTS " + CREATE_TABLE_ASSET);
// recreate the tables
onCreate(db);
}
public Cursor getAllCustodians(){
try {
SQLiteDatabase db_database = getWritableDatabase();
Cursor cursor = db_database.rawQuery("SELECT * FROM" + TABLE_CUSTODIAN, null);
if (cursor != null) {
return cursor;
} else {
return null;
}
}
catch(Exception e)
{
return null;
}
}}
CustodianViewActivity
package com.example.nfcams;
import android.app.Activity;
import android.content.Context;
import android.database.Cursor;
import android.os.Bundle;
import android.os.Handler;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CursorAdapter;
import android.widget.ListView;
import android.widget.TextView;
public class CustodianViewActivity extends Activity {
ListView CustodianListview;
DBHandler db_database;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_custodian_view);
db_database = new DBHandler(getApplicationContext());
CustodianListview = (ListView) findViewById(R.id.custodianlistView);
new Handler().post(new Runnable() {
#Override
public void run() {
populateCustoListView();
}
});
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_custodian_view, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
private void populateCustoListView()
{
Cursor c = db_database.getAllCustodians();
CustodianListview.setAdapter(new CustodiansListAdapter(this,c));
}
private class CustodiansListAdapter extends CursorAdapter
{
private Cursor cursor;
public CustodiansListAdapter(Context context, Cursor cur) {
super(context, cur);
cursor = cur;
}
#Override
public void bindView(View view, Context context, Cursor cursor) {
TextView custID = (TextView) view.findViewById(R.id.Custodianid_view);
int CustodID = cursor.getInt(cursor.getColumnIndex("_CustID"));
custID.setText(String.valueOf(CustodID));
TextView name = (TextView) view.findViewById(R.id.Custodianname_view);
String Custname = cursor.getString(cursor.getColumnIndex("CustName"));
name.setText(Custname);
TextView Designation = (TextView) view.findViewById(R.id.CustodianDesignation_view);
String CustDesignation = cursor.getString(cursor.getColumnIndex("CustDesign"));
Designation.setText(CustDesignation);
TextView Department = (TextView) view.findViewById(R.id.CustodianDepartment_view);
String CustDepartment = cursor.getString(cursor.getColumnIndex("CustDepart"));
Department.setText(CustDepartment);
}
#Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
LayoutInflater inflater = LayoutInflater.from(context);
View retView = inflater.inflate(R.layout.custodianrow_views, parent, false);
bindView(retView,context,cursor);
return retView;
}
}
}
Custodianview Activity layout
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
android:layout_height="match_parent" android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
android:paddingBottom="#dimen/activity_vertical_margin"
tools:context="com.example.nfcams.CustodianViewActivity">
<ListView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/custodianlistView"
android:layout_centerHorizontal="true"
android:layout_alignParentTop="true" />
</RelativeLayout>
List view layout
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="#color/list_item_bg"
android:descendantFocusability="blocksDescendants" >
<RelativeLayout
android:id="#+id/layout_item"
android:layout_width="fill_parent"
android:layout_height="wrap_content" >
<TextView
android:id="#+id/Custodianname_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="6dp" />
<TextView
android:id="#+id/Custodianid_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="#+id/Custodianname_view"
android:padding="6dp" />
<TextView
android:id="#+id/CustodianDesignation_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/Custodianid_view"
android:padding="6dp" />
<TextView
android:id="#+id/CustodianDepartment_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/CustodianDesignation_view"
android:padding="6dp" />
</RelativeLayout>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_below="#+id/layout_item"
android:background="#color/view_divider_color" />
</RelativeLayout>
Error Log
05-30 09:42:16.471 1334-1334/com.example.nfcams E/AndroidRuntime﹕ FATAL EXCEPTION: main
Process: com.example.nfcams, PID: 1334
java.lang.IllegalArgumentException: column '_id' does not exist
at android.database.AbstractCursor.getColumnIndexOrThrow(AbstractCursor.java:303)
at android.widget.CursorAdapter.init(CursorAdapter.java:172)
at android.widget.CursorAdapter.<init>(CursorAdapter.java:120)
at com.example.nfcams.CustodianViewActivity$CustodiansListAdapter.<init>(CustodianViewActivity.java:95)
at com.example.nfcams.CustodianViewActivity.populateCustoListView(CustodianViewActivity.java:84)
at com.example.nfcams.CustodianViewActivity.access$000(CustodianViewActivity.java:17)
at com.example.nfcams.CustodianViewActivity$1.run(CustodianViewActivity.java:42)
at android.os.Handler.handleCallback(Handler.java:733)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:157)
at android.app.ActivityThread.main(ActivityThread.java:5356)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1265)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1081)
at dalvik.system.NativeStart.main(Native Method)
I am creating a checklist and it allows the user to add new items to the list, I am trying to allow the user to delete an item when they want to. So I am creating a contextual menu using this that comes us when the user long-presses an item in the list. Right now, it recognizes the long-press but nothing happens, so the contextual menu doesn't appear.
Here is my activity page: (ViewTask.java)
package com.example.androidhive;
import java.util.ArrayList;
import java.util.List;
import android.os.Bundle;
import android.app.Activity;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.util.Log;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView.AdapterContextMenuInfo;
import android.widget.ArrayAdapter;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
public class ViewTask extends Activity {
protected TaskerDbHelper db;
List<Task> list;
MyAdapter adapt;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_view_task);
db = new TaskerDbHelper(this);
list = db.getAllTasks();
adapt = new MyAdapter(this, R.layout.list_inner_view, list);
ListView listTask = (ListView) findViewById(R.id.listView1);
listTask.setAdapter(adapt);
}
public void addTaskNow(View v) {
EditText t = (EditText) findViewById(R.id.editText1);
String s = t.getText().toString();
if (s.equalsIgnoreCase("")) {
Toast.makeText(this, "Enter a goal please!",
Toast.LENGTH_LONG);
} else {
Task task = new Task(s, 0);
db.addTask(task);
Log.d("tasker", "data added");
t.setText("");
adapt.add(task);
adapt.notifyDataSetChanged();
}
}
#Override
public void onCreateContextMenu(ContextMenu menu, View v,
ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.layout.cmenu, menu);
}
#Override
public boolean onContextItemSelected(MenuItem item) {
AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();
switch (item.getItemId()) {
case R.id.Delete_Task:
db.deleteTask(info.id);
return true;
default:
return super.onContextItemSelected(item);
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.layout.activity_view_task, menu);
return true;
}
private class MyAdapter extends ArrayAdapter<Task> {
Context context;
List<Task> taskList = new ArrayList<Task>();
int layoutResourceId;
public MyAdapter(Context context, int layoutResourceId,
List<Task> objects) {
super(context, layoutResourceId, objects);
this.layoutResourceId = layoutResourceId;
this.taskList = objects;
this.context = context;
}
/**
* This method will DEFINe what the view inside the list view will
* finally look like Here we are going to code that the checkbox state
* is the status of task and check box text is the task name
*/
#Override
public View getView(int position, View convertView, ViewGroup parent) {
CheckBox chk = null;
if (convertView == null) {
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.list_inner_view,
parent, false);
chk = (CheckBox) convertView.findViewById(R.id.chkStatus);
convertView.setTag(chk);
chk.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
CheckBox cb = (CheckBox) v;
Task changeTask = (Task) cb.getTag();
changeTask.setStatus(cb.isChecked() == true ? 1 : 0);
db.updateTask(changeTask);
if(cb.isChecked())
{
Toast.makeText(
getApplicationContext(),
"Goal Accomplished!", Toast.LENGTH_LONG).show();
}
}
});
} else {
chk = (CheckBox) convertView.getTag();
}
Task current = taskList.get(position);
chk.setText(current.getTaskName());
chk.setChecked(current.getStatus() == 1 ? true : false);
chk.setTag(current);
Log.d("listener", String.valueOf(current.getId()));
return convertView;
}
}
}
Here is the xml page associated to this page:(activity_view_task.xml)
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#DE8126"
android:orientation="vertical" >
<!-- Header Start -->
<LinearLayout
android:id="#+id/header"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="#layout/header_gradient"
android:orientation="vertical"
android:paddingBottom="5dip"
android:paddingTop="5dip" >
<!-- Logo Start -->
<ImageView
android:id="#+id/logoButton"
android:layout_width="match_parent"
android:layout_height="132dp"
android:src="#drawable/logo" />
<!-- Logo Ends -->
</LinearLayout>
<!-- Header End -->
<!-- Goals Title Start -->
<LinearLayout
android:id="#+id/goalsTitle"
android:layout_width="match_parent"
android:layout_height="80dp"
android:paddingTop="5dip"
android:paddingBottom="5dip">
<TextView
android:id="#+id/gTitle"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:text="My Goals"
android:textSize="50sp"
android:textScaleX="1.5"
android:textStyle="bold"
android:gravity="center"/>
</LinearLayout>
<!-- Goals Title End -->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ViewTask" >
<EditText
android:id="#+id/editText1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:ems="10" >
<requestFocus />
</EditText>
<Button
android:id="#+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:layout_marginRight="14dp"
android:text="#string/Save"
android:onClick="addTaskNow"/>
<ListView
android:id="#+id/listView1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_below="#+id/button1" >
</ListView>
</RelativeLayout>
</LinearLayout>
And here is the menu itself: (cmenu.xml)
<?xml version="1.0" encoding="UTF-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="#+id/Edit_Task"></item>
<item android:id="#+id/Delete_Task"></item>
</menu>
Thanks you for the responses, now I cannot get the item to actually be deleted.
here is my database helper page:(TaskerDbHelper.java)
package com.example.androidhive;
import java.util.ArrayList;
import java.util.List;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.database.sqlite.SQLiteOpenHelper;
public class TaskerDbHelper extends SQLiteOpenHelper{
private static final int DATABASE_VERSION = 1;
// Database Name
private static final String DATABASE_NAME = "taskerManager";
// tasks table name
private static final String TABLE_TASKS = "tasks";
// tasks Table Columns names
private static final String KEY_ID = "id";
private static final String KEY_TASKNAME = "taskName";
private static final String KEY_STATUS = "status";
public TaskerDbHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
#Override
public void onCreate(SQLiteDatabase db) {
String sql = "CREATE TABLE IF NOT EXISTS " + TABLE_TASKS + " ( "
+ KEY_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
+ KEY_TASKNAME+ " TEXT, "
+ KEY_STATUS + " INTEGER)";
db.execSQL(sql);
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldV, int newV) {
// Drop older table if existed
db.execSQL("DROP TABLE IF EXISTS " + TABLE_TASKS);
// Create tables again
onCreate(db);
}
public void addTask(Task task) {
SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(KEY_TASKNAME, task.getTaskName()); // task name
// status of task- can be 0 for not done and 1 for done
values.put(KEY_STATUS, task.getStatus());
// Inserting Row
db.insert(TABLE_TASKS, null, values);
db.close(); // Closing database connection
}
public boolean deleteTask(long task)
{
SQLiteDatabase db = this.getWritableDatabase();
return db.delete(TABLE_TASKS, KEY_TASKNAME + "=" + task, null) > 0;
}
public List<Task> getAllTasks() {
List<Task> taskList = new ArrayList<Task>();
// Select All Query
String selectQuery = "SELECT * FROM " + TABLE_TASKS;
SQLiteDatabase db = this.getWritableDatabase();
Cursor cursor = db.rawQuery(selectQuery, null);
// looping through all rows and adding to list
if (cursor.moveToFirst()) {
do {
Task task = new Task();
task.setId(cursor.getInt(0));
task.setTaskName(cursor.getString(1));
task.setStatus(cursor.getInt(2));
// Adding contact to list
taskList.add(task);
} while (cursor.moveToNext());
}
// return task list
return taskList;
}
public void updateTask(Task task) {
// updating row
SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(KEY_TASKNAME, task.getTaskName());
values.put(KEY_STATUS, task.getStatus());
db.update(TABLE_TASKS, values, KEY_ID + " = ?",new String[] {String.valueOf(task.getId())});
db.close();
}
}
That file above contains my deleteTask().
I don't see registerForContextMenu() anywhere. This is necessary for the list to actually know that it has a contextmenu.
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_view_task);
db = new TaskerDbHelper(this);
list = db.getAllTasks();
adapt = new MyAdapter(this, R.layout.list_inner_view, list);
ListView listTask = (ListView) findViewById(R.id.listView1);
listTask.setAdapter(adapt);
registerForContextMenu(listTask); // <-- Register!
}
In addition you should put a String value in your menu xml file. Obviously it is better to refer to your string xml file for the actual string.
<item
android:id="#+id/Edit_Task"
android:title="Edit">
</item>
<item
android:id="#+id/Delete_Task"
android:title="Delete">
</item>
Concerning the delete task:
To delete your task from the sql database you need some kind of identifier. As far as I can tell, you have only a task name and a status integer. If you allow tasks to have the same name, this cannot be used as an unique identifier. Perhaps you should add that to your Task class. You can then use this to find and remove the specific task in your database. (Your info.id will not work, because it is merely the identifier of the view) You can use info.position to retrieve the position of the Task in taskList, or more specifically, the current list in the adapter.
case R.id.Delete_Task:
Task task = list.get(info.position);
if (db.deleteTask(task.getUniqueIdentifier())) { // <-- Determine the unique id
list.Remove(info.position);
listTask.invalidate();
return true;
}
return false;
I'm not sure whether invalidate() will do the trick. But give it a try. You could also give the adapter the new list and call notifyDataSetChanged() as you do for the addTaskNow().
You need to add this line to your onCreate method
registerForContextMenu(listTask);
Your onCreateContextMenu() needs to look like this
#Override
public void onCreateContextMenu(ContextMenu menu, View v,
ContextMenuInfo menuInfo) {
if (v.getId() == R.id.listView1) { //YOUR VIEW THAT IS ATTACHED TO LISTASK
AdapterView.AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuInfo;
menu.setHeaderTitle("Options");
String[] menuItems = { "Option1", "Option2", "Option3", "Option4"} };
for (int i = 0; i < menuItems.length; i++) {
menu.add(Menu.NONE, i, i, menuItems[i]);
}
}
}
and finally your OnContextMenuItemSelected()
#Override
public boolean onContextItemSelected(android.view.MenuItem item) {
AdapterView.AdapterContextMenuInfo info = (AdapterContextMenuInfo) item
.getMenuInfo();
menuItemIndex = item.getItemId();
String[] menuItems = { "Option 1, Option 2, Option 3" };
String menuItemName = menuItems[menuItemIndex];
return true;
}