I'm population my listView using Cursor, but when I navigate away from my activity and then return back my listview is empty. Here is my code:
#Override
public void onCreate(Bundle savedInstanceState) {
...
DBAdapter db = new DBAdapter(context);
db.open();
Cursor c = db.getAll();
db.close();
startManagingCursor(c);
String[] columns = new String[] { ... };
int[] to = new int[] { ... };
SimpleCursorAdapter mAdapter = new SimpleCursorAdapter(this, R.layout.list_item, c, columns, to);
this.setListAdapter(mAdapter);
...
}
I've seen here questions about saving position of Cursor, but not the Cursor itself. Probably I just missing something, shall I save my cursor (how can I do it?) or it's better(faster, cheaper) to create new cursor every time using my DBadapter?
Thanks
startManagingCursor() makes your close() call unnecessary. As long as you didnt get exceptions about not finalizing or closing your cursor you have done anything right.
Related
I always cant delete first two sometimes three records. They are on Listview, when you press element you will see delete button on another layout. On Log im getting correct index for every element.
So here is my code:
Main Activity:
viewOfT.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Intent i=new Intent(MainActivity.this, popupWindow.class);
i.putExtra("index",id);
startActivity(i);
}
});
}
public void populateListView() {
Cursor data = db.getData();
ArrayList<String> listData = new ArrayList<>();
while(data.moveToNext()){
k.setId(data.getInt(0));
k.setTask(data.getString(1));
listData.add("- " + k.getTask());
}
ArrayAdapter<String> arrayAdapter = new ArrayAdapter<String>(
this,
android.R.layout.simple_list_item_1,
listData);
viewOfT.setAdapter(arrayAdapter);
arrayAdapter.notifyDataSetChanged();
viewOfT.invalidateViews();
Delete button in other activity:
del.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View v) {
Bundle bundle=getIntent().getExtras();
long value=bundle.getLong("index");
db.deleteRecord(value);
finish(); }
});
And SQLHelper:
public void deleteRecord(long id) {
SQLiteDatabase db = this.getWritableDatabase();
db.delete(TABLE_NAME, KEY_ID + "=" + id, null);
close();
}
1) Delete populateListView method
2) Add the following as class variables:-
SimpleCursorAdpater sca;
Cursor data;
3) in the onCreate method add :-
data = getData();
sca = new SimpleCursorAdapter(
this, // Context same as for array adapter
android.R.layout.simple_list_item_1, // layout to be used
data, // <<<<<<<< the cursor to be used for the list
new String[]{"columnname_to_be_displayed"}, // <<<<<<<< cursor column to display name
new int[android.R.id.text1], // the view into which the cursor data will be placed
0 // a flag 0 is fine
);
viewOfT.setAdapter(arrayAdapter);
4) Add a new method to override the 'onResume' method (or alter it if already overridden) :-
#Override
protected void onResume() {
super.onResume();
data = getData();
sca.swapCursor(); // can you sca.notifyDatasetChanged()
}
As you are calling another activity to delete the task, onResume will be called when returning from the other activity so the data is again retrieved from the database (deleted row will not exist) and the adpater is told to refresh the data.
You should ideally also override the onDestroy() method to close the cursor (data.close();)
Important Consideration
A cursor column named _id must exist for CursorAdapters (that's how the SimpleCursorAdapter knows what pass to the onItemClickListener).
if KEY_ID does not equate to _id; you either need to change KEY_ID to _id or amend the getData() method to include the _id column (which should be the value of the row's identifier) e.g. assuming a very basic query:
public Cursor getData() {
return db.query(TABLE_NAME,"rowid AS _id, *",null,null,null,null,null);
} // Note! will add an extra column so beware if using column offsets
or perhaps :-
public Cursor getData() {
return db.query(TABLE_NAME,KEY_ID + " AS _id, *",null,null,null,null,null);
} // Note! will add an extra column so beware if using column offsets
A Note on Column offsets
In your code you have :-
k.setId(data.getInt(0));
k.setTask(data.getString(1));
0 and 1 are column offsets (and could change e.g. the two alternative getData() methods). As such it's generally better to take advantage of the Cursor method getColumnIndex(columnname) e.g. the above could be :-
k.setId(data.getInt(data.getColumnIndex(KEY_ID));
k.setTask(data.getString(data.getColumnIndex("TASK_COLUMN")));
Note! not that you will need to create an Array as the SimpleCursorAdpater takes the cursor as the source. (KEY_ID would likely have to be prefixed with the DatabaseHelper Class).
I want to get the data from getName() method which is in Database class and put those data into ListView.Can anyone please help me out here. It crashes everytime I try to open this activity.
Caused by : java.lang.NullPointerException: Attempt to invoke virtual method 'boolean java.util.ArrayList.addAll(java.util.Collection)' on a null object reference"
This is the Error msg that appears when I run below code:
public class ListActivity extends android.app.ListActivity {
ListView mListNames;
ArrayList<String> mNames;
DBForm dbForm = new DBForm(this);`
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_list);
mListNames = (ListView) findViewById(android.R.id.list);
mNames.addAll(dbForm.getName());
this.setListAdapter(new ArrayAdapter<>(this, R.layout.list_head, mNames));
}
}
And this how I store and Retrieve the data inside DB class:
public ArrayList<String> getName() {
ArrayList<String> array_list = new ArrayList<>();
SQLiteDatabase db = this.getReadableDatabase();
Cursor res = db.rawQuery("select name from contacts" , null);
res.moveToFirst();
while (!res.isAfterLast()) {
array_list.add(res.getString(res.getColumnIndex(CONTACTS_COLUMN_NAME)));
res.moveToNext();
}
res.close();
return array_list;
}
Your problem in getName() method. Maybe your table is empty. You need to check null of your cursor before loop it. Like below:
if (cursor.moveToFirst()) {
while (cursor.isAfterLast() == false) {
String name = cursor.getString(cursor.getColumnIndex(countyname));
list.add(name);
cursor.moveToNext();
}
}
Refer to: Get all rows from SQLite
So I made a silly mistake here in defining the target XML file.I choose one layout file and instead of choosing the textView id from the same layout file I accidently put another layout files textView id.
adapter = new ArrayAdapter<>(this, R.layout.list_view, R.id.list_names, mNames);
mListNames.setAdapter(adapter);
Dear fellow senior programmers,
I encounter a runtime error of cannot use this in my databasehandler.java. Is there anywhere to overcome this problem.
Main Activity
public class DatabaseActivity extends Activity {
TextView idView;
EditText productBox;
EditText quantityBox;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_database);
idView = (TextView) findViewById(R.id.productID);
productBox = (EditText) findViewById(R.id.productName);
quantityBox = (EditText) findViewById(R.id.productQuantity);
ListView listContent = (ListView) findViewById(R.id.listView1);
Cursor cursor = MyDBHandler.queueAll();
startManagingCursor(cursor);
String[] from = new String[]{MyDBHandler.COLUMN_PRODUCTNAME};
int[] to = new int[]{R.id.text1};
SimpleCursorAdapter cursorAdapter =
new SimpleCursorAdapter(this, R.layout.rolypoly, cursor, from, to);
listContent.setAdapter(cursorAdapter);
}
MyDBHandler.java
public static Cursor queueAll(){
String[] columns = new String[]{COLUMN_ID, COLUMN_PRODUCTNAME,COLUMN_QUANTITY};
SQLiteDatabase db = **this**.getReadableDatabase();
Cursor cursor = db.query(TABLE_PRODUCTS, columns,
null, null, null, null, null);
}
Yes as error clearly says you cannot use this inside a static method. this refers to the "currently invoking" object, where as static is not tied with any object, you cannot use this in static context. Quote from Oracle tutorial:
Within an instance method or a constructor, this is a reference to the current object — the object whose method or constructor is being called
Instead of this:
this.getReadableDatabase();
You could do like this to access the getReadableDatabase();:
new YourClassName().getReadableDatabase();
I'm looking to add a new feature to my BETA version of my application.I think I need help on my approach to handling deleting a specific row.
I've been able to do everything I want with the databases in my app except for deleting a particular row or ID value from both database tables.
I'm calling a deleteClient() and passing the cursor in my DBAdapter. This table takes a long value for the rowID.
DBAdapter:
public boolean deleteClient(long rowId)
{
return db.delete(DATABASE_TABLE, KEY_ROWID + "=" + rowId, null) > 0;
}
DatabaseHandler creates a second database for other storage work but should delete the same:
public boolean delete(long rowId)
{
return db.delete(TABLE_LABELS, KEY_ID + "=" + rowId, null) > 0;
}
In my class I've tried a few variations on like this:
//db = the databaseadapter
db.open();
long loadID = contactList.getSelectedItemId();
//contact list is a spinner that is auto populated with each new entry added to it.
Cursor cursor = db.getClient(loadID);
db.deleteClient(cursor);
db.close();
AND THIS
dh.getWritableDatabase();
long currentlySelected = contactList.getSelectedItemId();
dh.delete(currentlySelected);
dh.close();
One deletes but not the right selection - the other causes an immediate crash. DDMS has given hints but I cant figure out what else could be going on.
Any thoughts on this structure in general or better techniques on this approach?
Spinner loaded like this:
private void loadSpinnerData() {
// database handler
DatabaseHandler dbh = new DatabaseHandler(getApplicationContext());
// Spinner Drop down elements
List<String> lables = dbh.getAllLabels();
// Creating adapter for spinner
ArrayAdapter<String> dataAdapter = new ArrayAdapter<String>(this,
android.R.layout.simple_spinner_item, lables);
// Drop down layout style - list view with radio button
dataAdapter
.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
// attaching data adapter to spinner
contactList.setAdapter(dataAdapter);
}
When my database is empty, or it has just been created I am getting this error,
03-10 17:34:40.758: E/AndroidRuntime(1144):
java.lang.RuntimeException: Unable to start activity
ComponentInfo{com.example.adressbooktake2/com.example.adressbooktake2.MainActivity}:
android.database.CursorIndexOutOfBoundsException: Index 0 requested, with a size of 0
Here is my code in my main class,
public class MainActivity extends Activity {
DBAdaptor db;
Cursor cursor;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
db = new DBAdaptor(this).open();
cursor = db.getAllRecords();
DisplayRecord(cursor);
}
which then calls this code in my DBAdaptor class,
public Cursor getAllRecords()
{
Cursor gaRecords = db.query(DATABASE_TABLE, new String[] {KEY_ROWID, KEY_NAME,
KEY_PHONENUMBER, KEY_EMAIL}, null, null, null, null, null);
gaRecords.moveToFirst();
return gaRecords;
}
}
I believe the problem is that when the database has just been created, there is nowhere for the moveToFirst() to go, as there is no data. But I am not sure how to get round this as I need a moveToFirst() for when there is a stocked database.
Anyone see a solution? Have a diagnosed the problem correctly?
You can check for an empty Cursor like this:
...
cursor = db.getAllRecords();
if(cursor.getCount() > 0)
DisplayRecords(cursor);
else
DisplayNoRecordsMessage();
Or since you posted DisplayRecords() in a previous question, you can also use:
...
if (c != null && !cursor.isAfterLast())
{
nameTxt.setText(c.getString(1));
phoneTxt.setText(c.getString(2));
emailTxt.setText(c.getString(3));
}
Also please read about Java naming convention which states that method names should start with a lowercase letter.
Cursor.moveToFirst() returns false in case of empty cursor.
See the doc: http://developer.android.com/reference/android/database/Cursor.html#moveToFirst()
I'd say the problem is in DisplayRecord().
Are you fetching data from the cursor in DisplayRecord() ? If so, inside of it you should check if the cursor contains some data, calling moveToFirst and checking its result for example.
Something like
private void DisplayRecord(Cursor c){
if(!c.moveToFirst()){
return;
}
// do stuff
}
Use if(cursor .moveToFirst()) to check cursor
public class MainActivity extends Activity {
DBAdaptor db;
Cursor cursor;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
db = new DBAdaptor(this).open();
cursor = db.getAllRecords();
if(cursor.moveToFirst()){
DisplayRecord(cursor);
}
}