Fill Gridview with SQL database - android

**EDIT: I'll use listview instead of Gridview. **
I've been learning Android since a couple of weeks and last days I've been struggling on getting my SQL-data in a gridview. I've been searching through many, many topics and I can't seem to find a fitting answer to my question. This is the code I've got so far:
package com.example.myfirstapp;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.GridView;
import android.widget.TextView;
import android.widget.Toast;
import java.util.ArrayList;
public class DisplayMessageActivity extends AppCompatActivity {
public static ArrayList<String> ArrayofName = new ArrayList<String>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_display_message);
SQLiteDatabase db = mDbHelper.getReadableDatabase();
String selectQuery = "SELECT * FROM " + MainActivity.FeedReaderContract.FeedEntry.TABLE_NAME;
Cursor cursor = db.rawQuery(selectQuery, null);
{
// looping through all rows and adding to list
if (cursor.moveToFirst()) {
do {
String id = cursor.getString(cursor.getColumnIndex("_ID"));
String title = cursor.getString(cursor.getColumnIndex("title"));
String subtitle = cursor.getString(cursor.getColumnIndex("subtitle"));
String name = id +"\n" + title +"\n"+ subtitle;
DisplayMessageActivity.ArrayofName.add(name);
} while (cursor.moveToNext());
}
}
GridView gridView = (GridView) findViewById(R.id.gridView1);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1, ArrayofName);
gridView.setAdapter(adapter);
gridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View v,
int position, long id) {
Toast.makeText(getApplicationContext(),
((TextView) v).getText(), Toast.LENGTH_SHORT).show();
}
});
}
private static final String TEXT_TYPE = " TEXT";
private static final String COMMA_SEP = ",";
private static final String SQL_CREATE_ENTRIES =
"CREATE TABLE " + MainActivity.FeedReaderContract.FeedEntry.TABLE_NAME + " (" +
MainActivity.FeedReaderContract.FeedEntry._ID + " INTEGER PRIMARY KEY," +
MainActivity.FeedReaderContract.FeedEntry.COLUMN_NAME_TITLE + TEXT_TYPE + COMMA_SEP +
MainActivity.FeedReaderContract.FeedEntry.COLUMN_NAME_SUBTITLE + TEXT_TYPE + " )";
private static final String SQL_DELETE_ENTRIES = "DROP TABLE IF EXISTS '" + MainActivity.FeedReaderContract.FeedEntry.TABLE_NAME + "'";
public class FeedReaderDbHelper extends SQLiteOpenHelper {
// If you change the database schema, you must increment the database version.
public static final int DATABASE_VERSION = 1;
public static final String DATABASE_NAME = "FeedReader.db";
public FeedReaderDbHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
public void onCreate(SQLiteDatabase db) {
db.execSQL(SQL_CREATE_ENTRIES);
}
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// This database is only a cache for online data, so its upgrade policy is
// to simply to discard the data and start over
db.execSQL(SQL_DELETE_ENTRIES);
onCreate(db);
}
}
DisplayMessageActivity.FeedReaderDbHelper mDbHelper = new FeedReaderDbHelper(this);
public void Test (View view) {
SQLiteDatabase db = mDbHelper.getReadableDatabase();
// Define a projection that specifies which columns from the database you will actually use after this query.
String[] projection = {MainActivity.FeedReaderContract.FeedEntry._ID, MainActivity.FeedReaderContract.FeedEntry.COLUMN_NAME_TITLE, MainActivity.FeedReaderContract.FeedEntry.COLUMN_NAME_SUBTITLE};
// Filter results WHERE "title" = 'My Title'
String selection = MainActivity.FeedReaderContract.FeedEntry.COLUMN_NAME_TITLE + " = ?";
String[] selectionArgs = {"A"};
// How you want the results sorted in the resulting Cursor
String sortOrder = MainActivity.FeedReaderContract.FeedEntry.COLUMN_NAME_SUBTITLE + " DESC";
Cursor c = db.query(
MainActivity.FeedReaderContract.FeedEntry.TABLE_NAME, // The table to query
projection, // The columns to return
selection, // The columns for the WHERE clause
selectionArgs, // The values for the WHERE clause
null, // don't group the rows
null, // don't filter by row groups
sortOrder // The sort order
);
if (c.getCount()>0) {
c.moveToFirst();
int itemId = c.getInt(c.getColumnIndexOrThrow(MainActivity.FeedReaderContract.FeedEntry._ID));
String strTitel = c.getString(c.getColumnIndexOrThrow(MainActivity.FeedReaderContract.FeedEntry.COLUMN_NAME_TITLE));
String strSubtitel = c.getString(c.getColumnIndexOrThrow(MainActivity.FeedReaderContract.FeedEntry.COLUMN_NAME_SUBTITLE));
EditText edtID = (EditText) findViewById(R.id.txtInvoer);
edtID.setText(Integer.toString(itemId));
EditText edtTitle = (EditText) findViewById(R.id.txtTitel2);
edtTitle.setText(strTitel);
EditText edtSubtitle = (EditText) findViewById(R.id.txtSubtitel2);
edtSubtitle.setText(strSubtitel);
} else {
Toast.makeText(getApplicationContext(), "Geen data in db", Toast.LENGTH_LONG).show();
}
}
public void Vorige (View view) {
SQLiteDatabase db = mDbHelper.getReadableDatabase();
String[] projection = {MainActivity.FeedReaderContract.FeedEntry._ID, MainActivity.FeedReaderContract.FeedEntry.COLUMN_NAME_TITLE, MainActivity.FeedReaderContract.FeedEntry.COLUMN_NAME_SUBTITLE};
String selection = "_ID=?";
EditText edtGeselecteerdeID = (EditText) findViewById(R.id.txtInvoer);
int intVolgendeID=Integer.parseInt(edtGeselecteerdeID.getText().toString())-1;
String strVolgendeID=Integer.toString(intVolgendeID);
String[] selectionArgs = {strVolgendeID};
// How you want the results sorted in the resulting Cursor
String sortOrder = MainActivity.FeedReaderContract.FeedEntry.COLUMN_NAME_SUBTITLE + " DESC";
Cursor c = db.query(
MainActivity.FeedReaderContract.FeedEntry.TABLE_NAME, // The table to query
projection, // The columns to return
selection, // The columns for the WHERE clause
selectionArgs, // The values for the WHERE clause
null, // don't group the rows
null, // don't filter by row groups
sortOrder // The sort order
);
if (c.getCount()>0) {
c.moveToFirst();
int itemId = c.getInt(c.getColumnIndexOrThrow(MainActivity.FeedReaderContract.FeedEntry._ID));
String strTitel = c.getString(c.getColumnIndexOrThrow(MainActivity.FeedReaderContract.FeedEntry.COLUMN_NAME_TITLE));
String strSubtitel = c.getString(c.getColumnIndexOrThrow(MainActivity.FeedReaderContract.FeedEntry.COLUMN_NAME_SUBTITLE));
EditText edtID = (EditText) findViewById(R.id.txtInvoer);
edtID.setText(Integer.toString(itemId));
EditText edtTitle = (EditText) findViewById(R.id.txtTitel2);
edtTitle.setText(strTitel);
EditText edtSubtitle = (EditText) findViewById(R.id.txtSubtitel2);
edtSubtitle.setText(strSubtitel);
} else {
Toast.makeText(getApplicationContext(), "Geen data in db", Toast.LENGTH_LONG).show();
}
}
public void Volgende (View view) {
SQLiteDatabase db = mDbHelper.getReadableDatabase();
String[] projection = {MainActivity.FeedReaderContract.FeedEntry._ID, MainActivity.FeedReaderContract.FeedEntry.COLUMN_NAME_TITLE, MainActivity.FeedReaderContract.FeedEntry.COLUMN_NAME_SUBTITLE};
String selection = MainActivity.FeedReaderContract.FeedEntry._ID + " = ?";
EditText edtGeselecteerdeID = (EditText) findViewById(R.id.txtInvoer);
int intVolgendeID=Integer.parseInt(edtGeselecteerdeID.getText().toString())+1;
String strVolgendeID=Integer.toString(intVolgendeID);
String[] selectionArgs = {strVolgendeID};
// How you want the results sorted in the resulting Cursor
String sortOrder = MainActivity.FeedReaderContract.FeedEntry.COLUMN_NAME_SUBTITLE + " DESC";
Cursor c = db.query(
MainActivity.FeedReaderContract.FeedEntry.TABLE_NAME, // The table to query
projection, // The columns to return
selection, // The columns for the WHERE clause
selectionArgs, // The values for the WHERE clause
null, // don't group the rows
null, // don't filter by row groups
sortOrder // The sort order
);
if (c.getCount()>0) {
c.moveToFirst();
int itemId = c.getInt(c.getColumnIndexOrThrow(MainActivity.FeedReaderContract.FeedEntry._ID));
String strTitel = c.getString(c.getColumnIndexOrThrow(MainActivity.FeedReaderContract.FeedEntry.COLUMN_NAME_TITLE));
String strSubtitel = c.getString(c.getColumnIndexOrThrow(MainActivity.FeedReaderContract.FeedEntry.COLUMN_NAME_SUBTITLE));
EditText edtID = (EditText) findViewById(R.id.txtInvoer);
edtID.setText(Integer.toString(itemId));
EditText edtTitle = (EditText) findViewById(R.id.txtTitel2);
edtTitle.setText(strTitel);
EditText edtSubtitle = (EditText) findViewById(R.id.txtSubtitel2);
edtSubtitle.setText(strSubtitel);
} else {
Toast.makeText(getApplicationContext(), "Geen data in db", Toast.LENGTH_LONG).show();
}
}
}
So in MainActivity I've got code to add data into the database. 'DisplayMessageActivity' is for testing out new stuff. My database consists of 3 columns: ID, title and subtitle. I use the method 'Test' to display the data in Edittext objects, and the methods 'Vorige' and 'Volgende' to go through the data. Now I'm trying to display the data (id, title & subtitle) in a gridview or listview (I don't really know what to use). You can find all the code for my problem in the first onCreate class.
I'd like to achieve something like this:
So the first row displays the different column titles, and all the other rows display the data. The first row displaying the titles aren't even needed, I could easily add them by using EditText fields.
Can anyone help me out here? Other suggestions for improving my code are always welcome too ;)

Related

How to make a checkbox from information found in DataBase?

I have a table in DataBase, and I want to make a table.
Now it makes no sense that I will do a lot of CheckBox and show you only some of them according to the information in the table. I heard about the listview
But how do I do listview of checkbox I found an example of listview on the Internet and when I tried to insert large information, only half the information came in, so I was told to do adapter.
Do you have an example of how to do this?
It DatabaseHandler:
package budgetreport.com.budgetreport;
public class DatabaseHandler extends SQLiteOpenHelper {
// All Static variables
// Database Version
private static final int DATABASE_VERSION = 4;
// Database Name
private static final String DATABASE_NAME = "Records_Item Purcashes";
// Contacts table name
private static final String TABLE_RECORDS = "Records";
// Contacts Table Columns names
private static final String KEY_ID = "ID";
private static final String KEY_PRICE = "Price";
private static final String KEY_ITEM = "Item";
private static final String KEY_DETAILS = "Details";
private static final String KEY_DATE = "Date";
public DatabaseHandler(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
// Creating Tables
#Override
public void onCreate(SQLiteDatabase db) {
String CREATE_CONTACTS_TABLE = "CREATE TABLE " + TABLE_RECORDS + "("
+ KEY_ID + " INTEGER PRIMARY KEY,"
+ KEY_PRICE + " INTEGER," + KEY_ITEM + " TEXT,"
+ KEY_DETAILS + " TEXT, " + KEY_DATE + " TEXT" + ")";
db.execSQL(CREATE_CONTACTS_TABLE);
}
// Upgrading database
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// Drop older table if existed
db.execSQL("DROP TABLE IF EXISTS " + TABLE_RECORDS);
// Create tables again
onCreate(db);
}
// Adding new contact
public void addRecord(Record record) {
SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(KEY_ID, record.getId()); // Contact Name
values.put(KEY_PRICE, record.getPrice()); // Contact Name
values.put(KEY_ITEM, record.getItem()); // Contact Name
values.put(KEY_DETAILS, record.getDetails()); // Contact Name
values.put(KEY_DATE, record.getDetails()); // Contact Phone Number
// Inserting Row
db.insert(TABLE_RECORDS, null, values);
db.close(); // Closing database connection
}
// Getting single contact
public Record getRecord(int id) {
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor = db.query(TABLE_RECORDS, new String[] { KEY_ID, KEY_PRICE,
KEY_ITEM, KEY_DETAILS, KEY_DATE }, KEY_ID + "=?",
new String[] { String.valueOf(id) }, null, null, null, null);
if (cursor != null)
cursor.moveToFirst();
Record record = new Record(Integer.parseInt(cursor.getString(0)),
Integer.parseInt(cursor.getString(1)), cursor.getString(2), cursor.getString(3), cursor.getString(4));
// return contact
return record;
}
// Getting All Contacts
public List<Record> getAllContacts() {
List<Record> contactList = new ArrayList<Record>();
// Select All Query
String selectQuery = "SELECT * FROM " + TABLE_RECORDS;
SQLiteDatabase db = this.getWritableDatabase();
Cursor cursor = db.rawQuery(selectQuery, null);
// looping through all rows and adding to list
if (cursor.moveToFirst()) {
do {
Record record = new Record();
record.setId(Integer.parseInt(cursor.getString(0)));
record.setPrice(Integer.parseInt(cursor.getString(1)));
record.setItem(cursor.getString(2));
record.setDetails(cursor.getString(3));
record.setDate(cursor.getString(4));
// Adding contact to list
contactList.add(record);
} while (cursor.moveToNext());
}
// return contact list
return contactList;
}
// Getting contacts Count
public int getRecordsCount() {
String countQuery = "SELECT * FROM " + TABLE_RECORDS;
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor = db.rawQuery(countQuery, null);
// cursor.close();
// return count
return cursor.getCount();
}
// Updating single contact
public int updateContact(Record record) {
SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(KEY_ID, record.getId());
values.put(KEY_PRICE, record.getPrice());
values.put(KEY_DETAILS, record.getDetails());
values.put(KEY_DATE, record.getDate());
// updating row
return db.update(TABLE_RECORDS, values, KEY_ID + " = ?",
new String[] { String.valueOf(record.getPrice()) });
}
// Deleting single contact
public void deleteContact(Record record) {
SQLiteDatabase db = this.getWritableDatabase();
db.delete(TABLE_RECORDS, KEY_ID + " = ?",new String[]
{String.valueOf(record.getPrice()) });
db.close();
}
}
Deletion of checked Items as per I want to erase the lines I have marked.
This is relatively simple to progress to.
It involves
- a) adding a method to the database helper to delete according to id.
- b) (i)amend the onClick listener to invoke the delete method (simple loop) and to then (ii)update the listview (after the loop).
However, the original custom adapter has some flaws in that the original cursor is retained via mCsr and no consideration was given to the number of checkboxes being changed when the Cursor is changed (swapped).
As such the adapter has had references to mCsr removed and replaced by the Cursor passed or via calling the getCursor method. Also the swapCursor() method has been overidden to adjust the number of elements of and re-initialise the elemnets (set to false), of mCheckBoxes.
a) The new deleteRecord method :-
public boolean deleteRecord(long id) {
SQLiteDatabase db = this.getWritableDatabase();
return (db.delete(TABLE_RECORDS,KEY_ID + "=?",new String[]{Long.toString(id)})> 0);
}
b)(i) onCLickListener amendments (note includes grouping all deletes into a single transaction) :-
// <<<<< DO IT BUTTON HANDLER i.e. get list of ID's for checked items
mDoItButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// get the ID's for the checked Items
mCheckedIdList = mMCA.getCheckedRecordIdList();
Toast.makeText(mContext,"You have " + mCheckedIdList.length + " Items checked.",Toast.LENGTH_SHORT).show();
//<<<< to delete
SQLiteDatabase db = mDBHandler.getWritableDatabase();
db.beginTransaction();
for (long id: mCheckedIdList) {
mDBHandler.deleteRecord(id);
}
db.setTransactionSuccessful();
db.endTransaction();
refreshListView();
}
});
b(ii) Update the Listview (new method in the Activity) :-
private void refreshListView() {
mCsr = mDBHandler.getAllRecords();
mMCA.swapCursor(mCsr);
}
Notes
this is added as a method to the activity.
mMCA.notifyDatasetChanged(); is an alternative (I personally prefer `swapCursor1 as it's more decsriptive).
The modified Custom Cursor Adapter should be :-
public class MyCustomCursorAdapter extends CursorAdapter {
private Context mContext;
private String[] mColumns;
private int[] mViews;
private int mLayout;
private boolean[] mCheckBoxStates;
private int mCheckBoxView;
// Constructor for the Custom Cursor Adapter
MyCustomCursorAdapter(Context context, int layout, Cursor csr, String[] from_columns, int[] to_views, int checkbox_view) {
super(context,csr, false);
mContext = context;
mLayout = layout;
mColumns = from_columns;
mViews = to_views;
mCheckBoxView = checkbox_view;
}
#Override
// Inflate the layout we are going to use (as passed via 2nd parameter)
public View newView(Context context, Cursor csr, ViewGroup parent) {
// Initialise an int array for the checkboxes (all will be 0)
mCheckBoxStates = new boolean[csr.getCount()];
return LayoutInflater.from(context).inflate(mLayout,parent,false);
}
#Override
// Tie the from_columns to the display views
public void bindView(View view, Context context, Cursor csr) {
final Cursor fcsr = csr;
// Place the data from the cursor into the respective View (TextView)
for (int i = 0; i < mColumns.length; i++) {
((TextView) view.findViewById(mViews[i])).setText(csr.getString(csr.getColumnIndex(mColumns[i])));
}
// Set the checkbox (note should be false, unless otherwise changed)
CheckBox currentCheckBox = (CheckBox) view.findViewById(mCheckBoxView);
currentCheckBox.setChecked(mCheckBoxStates[csr.getPosition()]);
currentCheckBox.setTag(new Long(csr.getLong(csr.getColumnIndex(DatabaseHandler.KEY_ID))));
//
currentCheckBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
final int position = fcsr.getPosition();
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
// Store the checkbox status
mCheckBoxStates[position] = ((CheckBox) buttonView).isChecked();
int restore_cursor_position = fcsr.getPosition();
//Move the Cursor to the respective row
//NOTE! 1st position in Lisview is 1 but equates to cursor row 0 etc hence -1
fcsr.moveToPosition(position);
Toast.makeText(mContext,
"You Changed the CheckBox for row " +
Integer.toString(position + 1) +
" Item is " +
fcsr.getString(fcsr.getColumnIndex(DatabaseHandler.KEY_ITEM))
,
Toast.LENGTH_SHORT
).show();
//restore the Cursor's position
fcsr.moveToPosition(restore_cursor_position);
}
});
}
// get the list of items (the ID's as long) that have been checked.
public long[] getCheckedRecordIdList() {
Cursor csr = this.getCursor();
// using ArrayList as we can add as we don't yet know how many
ArrayList<Long> rva = new ArrayList<>();
// Just in case save the current position of the Cursor
int restore_cursor_position = csr.getPosition();
// Loop through the checkbox states
for (int i=0; i < mCheckBoxStates.length; i++) {
// If the checkbox reflected as being checked then handle, else ignore it
if (mCheckBoxStates[i]) {
// Move to the respective cursor row
csr.moveToPosition(i);
// get the respective ID and store in the arraylist
rva.add(csr.getLong(csr.getColumnIndex(DatabaseHandler.KEY_ID)));
}
}
// Done with the Cursor so re-position it
csr.moveToPosition(restore_cursor_position);
// Create the long array to be returned
long[] rv = new long[rva.size()];
// Populate the long array with the id's from the arraylist
for (int i=0; i < rva.size(); i++) {
rv[i] = rva.get(i);
}
// return the long[]
return rv;
}
#Override
public Cursor swapCursor(Cursor csr) {
mCheckBoxStates = new boolean[csr.getCount()];
for (int i=0; i < mCheckBoxStates.length; i++) {
mCheckBoxStates[i] = false;
}
return super.swapCursor(csr);
}
}
here's an example based upon you code.
1) The Activity's layout (i.e a ListView with an id of lv001) as file activity_main.xml :-
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="mjt.budgetreport.MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
android:layout_margin="10dp"
/>
<ListView
android:id="#+id/lv001"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</ListView>
</LinearLayout>
2) A layout for each row (Item in ListView terminology) as file listviewitem_record.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="#+id/record_price"
android:layout_width="0dp"
android:layout_weight="8"
android:layout_height="wrap_content"
android:layout_margin="5dp"/>
<TextView
android:id="#+id/record_item"
android:layout_width="0dp"
android:layout_weight="10"
android:layout_height="wrap_content"
android:layout_margin="5dp"/>
<TextView
android:id="#+id/record_details"
android:layout_width="0dp"
android:layout_weight="20"
android:layout_height="wrap_content"
android:layout_margin="5dp"/>
<TextView
android:id="#+id/record_date"
android:layout_width="0dp"
android:layout_weight="10"
android:layout_height="wrap_content"
android:layout_margin="5dp"/>
<CheckBox
android:id="#+id/record_checkbox"
android:layout_width="0dp"
android:layout_weight="2"
android:layout_height="wrap_content"
android:layout_margin="5dp"/>
</LinearLayout>
Note! the inclusion of a CheckBox, as well as TextViews for all columns.
3) To simplify matters I used this as DatabaseHandler.java :-
public class DatabaseHandler extends SQLiteOpenHelper {
// All Static variables
// Database Version
private static final int DATABASE_VERSION = 4;
// Database Name
public static final String DATABASE_NAME = "Records_Item Purcashes";
// Contacts table name
public static final String TABLE_RECORDS = "Records";
// Contacts Table Columns names
public static final String KEY_ID = "_id";
public static final String KEY_PRICE = "Price";
public static final String KEY_ITEM = "Item";
public static final String KEY_DETAILS = "Details";
public static final String KEY_DATE = "Date";
public DatabaseHandler(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
// Creating Tables
#Override
public void onCreate(SQLiteDatabase db) {
String CREATE_CONTACTS_TABLE = "CREATE TABLE " +
TABLE_RECORDS +
"(" +
KEY_ID + " INTEGER PRIMARY KEY," +
KEY_PRICE + " INTEGER," +
KEY_ITEM + " TEXT," +
KEY_DETAILS + " TEXT, " +
KEY_DATE + " TEXT" +
")";
db.execSQL(CREATE_CONTACTS_TABLE);
}
// Upgrading database
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// Drop older table if existed
db.execSQL("DROP TABLE IF EXISTS " + TABLE_RECORDS);
// Create tables again
onCreate(db);
}
public void insertRecord(int price, String item, String details, String date) {
ContentValues cv = new ContentValues();
cv.put(KEY_PRICE,price);
cv.put(KEY_ITEM,item);
cv.put(KEY_DETAILS,details);
cv.put(KEY_DATE,date);
SQLiteDatabase db = this.getWritableDatabase();
db.insert(TABLE_RECORDS,null,cv);
}
public Cursor getAllRecords() {
SQLiteDatabase db = this.getWritableDatabase();
return db.query(TABLE_RECORDS,null,null,null,null,null,null);
}
/*
// Adding new contact
public void addRecord(AlphabeticIndex.Record record) {
SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(KEY_ID, record.getId()); // Contact Name
values.put(KEY_PRICE, record.getPrice()); // Contact Name
values.put(KEY_ITEM, record.getItem()); // Contact Name
values.put(KEY_DETAILS, record.getDetails()); // Contact Name
values.put(KEY_DATE, record.getDetails()); // Contact Phone Number
// Inserting Row
db.insert(TABLE_RECORDS, null, values);
db.close(); // Closing database connection
}
*/
/*
// Getting single contact
public AlphabeticIndex.Record getRecord(int id) {
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor = db.query(TABLE_RECORDS, new String[] { KEY_ID, KEY_PRICE,
KEY_ITEM, KEY_DETAILS, KEY_DATE }, KEY_ID + "=?",
new String[] { String.valueOf(id) }, null, null, null, null);
if (cursor != null)
cursor.moveToFirst();
AlphabeticIndex.Record record = new AlphabeticIndex.Record(Integer.parseInt(cursor.getString(0)),
Integer.parseInt(cursor.getString(1)), cursor.getString(2), cursor.getString(3), cursor.getString(4));
// return contact
return record;
}
*/
/*
// Getting All Contacts
public List<AlphabeticIndex.Record> getAllContacts() {
List<AlphabeticIndex.Record> contactList = new ArrayList<AlphabeticIndex.Record>();
// Select All Query
String selectQuery = "SELECT * FROM " + TABLE_RECORDS;
SQLiteDatabase db = this.getWritableDatabase();
Cursor cursor = db.rawQuery(selectQuery, null);
// looping through all rows and adding to list
if (cursor.moveToFirst()) {
do {
AlphabeticIndex.Record record = new AlphabeticIndex.Record();
record.setId(Integer.parseInt(cursor.getString(0)));
record.setPrice(Integer.parseInt(cursor.getString(1)));
record.setItem(cursor.getString(2));
record.setDetails(cursor.getString(3));
record.setDate(cursor.getString(4));
// Adding contact to list
contactList.add(record);
} while (cursor.moveToNext());
}
// return contact list
return contactList;
}
*/
/*
// Getting contacts Count
public int getRecordsCount() {
String countQuery = "SELECT * FROM " + TABLE_RECORDS;
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor = db.rawQuery(countQuery, null);
// cursor.close();
// return count
return cursor.getCount();
}
*/
/*
// Updating single contact
public int updateContact(AlphabeticIndex.Record record) {
SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(KEY_ID, record.getId());
values.put(KEY_PRICE, record.getPrice());
values.put(KEY_DETAILS, record.getDetails());
values.put(KEY_DATE, record.getDate());
// updating row
return db.update(TABLE_RECORDS, values, KEY_ID + " = ?",
new String[] { String.valueOf(record.getPrice()) });
}
*/
/*
// Deleting single contact
public void deleteContact(AlphabeticIndex.Record record) {
SQLiteDatabase db = this.getWritableDatabase();
db.delete(TABLE_RECORDS, KEY_ID + " = ?",new String[]
{String.valueOf(record.getPrice()) });
db.close();
}
*/
}
Notes about Changes to DatabaseHandler.java
The rowid alias has been changed from ID to _id, this is because CursorAdapter's need a column named _id and that column should be an alias for for the rowid (not going into technicalities here).
Instead of using a Record class I've commented out your code that uses this class, for my convenience.
I've changed TABLE and COLUMN names definitions to public, so they can be accessed elsewhere.
I've added two new methods insertRecord and getAllRecords:-
insertRecord just to add some data for testing/example
getAllRecords retrieves all rows as a Cursor, as opposed to an array.
NOTE! The database is not closed, this would result in an exception because a Cursor needs access to the database (opening and closing a database can be detrimental anyway).
4) The Activity itself (just displays the ListView after adding some data for the first run) as file MainActivity.java :-
public class MainActivity extends AppCompatActivity {
DatabaseHandler mDBHandler;
ListView mListView;
SimpleCursorAdapter mSCA;
Cursor mCsr;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mListView = (ListView) this.findViewById(R.id.lv001); // Get the ListView from it's id
mDBHandler = new DatabaseHandler(this); // Get an instance of the Database Handler
// Add some data but only if there is no data
if (DatabaseUtils.queryNumEntries(mDBHandler.getWritableDatabase(),DatabaseHandler.TABLE_RECORDS) < 1) {
mDBHandler.insertRecord(100,"Rock","A large stone.","31/12/2017");
mDBHandler.insertRecord(50,"Boulder","A Rock.","31/12/2018");
mDBHandler.insertRecord(322,"Soil","Loose earth.","31/7/2015");
mDBHandler.insertRecord(237,"Stone","A small rock.","31/8/2014");
mDBHandler.insertRecord(32,"Pebble","A small smooth stone.","11/12/2017");
}
// get all rows into a Cursor
mCsr = mDBHandler.getAllRecords();
// Prepare a list of the columns to get the data from, for the ListViewt
String[] columns_to_get_data_from = new String[]{
DatabaseHandler.KEY_PRICE,
DatabaseHandler.KEY_ITEM,
DatabaseHandler.KEY_DETAILS,
DatabaseHandler.KEY_DATE
};
// Prepare a list of the Views into which to place the data
int[] itemviews_to_place_data_in = new int[]{
R.id.record_price,
R.id.record_item,
R.id.record_details,
R.id.record_date
};
// get and instance of SimpleCursorAdapter
mSCA = new SimpleCursorAdapter(this,
R.layout.listviewitem_record,
mCsr,
columns_to_get_data_from,
itemviews_to_place_data_in,
0);
// get and instance of SimpleCursorAdapter the listviewitem_record layout
mListView.setAdapter(mSCA);
}
}
Result :-
Notes
This doesn't go into handling the checkboxes, this would likely need a CustomAdapter. There's plenty of tutorials for that e.g. how do i create a custom cursor adapter for a listview for use with images and text?.
Edit Amended to Include CheckBox handling
1) The Activity's layout activity_main.xml - Added a Button for getting Checked Items :-
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="mjt.budgetreport.MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
android:layout_margin="10dp"
/>
<Button
android:id="#+id/doitbutton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="DO ALL CHECKED ROWS"
/>
<ListView
android:id="#+id/lv001"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</ListView>
</LinearLayout>
2) The Custom Cursor Adapter MyCustomCursorAdapter.java
Signature similar to SimpleCursorAdapter BUT with an extra parameter for the id of the CheckBox.
Includes method getCheckedRecordIdList, which will return a list of Id's that have been checked.
Issues a Toast when a checkbox is checked or unchecked which displays the item, as in the ListView's Item # (not the Item in the table), clicked and the Item clicked (as in the Item value from the table).
:-
public class MyCustomCursorAdapter extends CursorAdapter {
private Context mContext;
private Cursor mCsr;
private String[] mColumns;
private int[] mViews;
private int mLayout;
private boolean[] mCheckBoxStates;
private int mCheckBoxView;
// Constructor for the Custom Cursor Adapter
MyCustomCursorAdapter(Context context, int layout, Cursor csr, String[] from_columns, int[] to_views, int checkbox_view) {
super(context,csr, false);
mContext = context;
mLayout = layout;
mCsr = csr;
mColumns = from_columns;
mViews = to_views;
mCheckBoxView = checkbox_view;
}
#Override
// Inflate the layout we are going to use (as passed via 2nd parameter)
public View newView(Context context, Cursor csr, ViewGroup parent) {
// Initialise an int array for the checkboxes (all will be 0)
mCheckBoxStates = new boolean[csr.getCount()];
return LayoutInflater.from(context).inflate(mLayout,parent,false);
}
#Override
// Tie the from_columns to the display views
public void bindView(View view, Context context, Cursor csr) {
// Place the data from the cursor into the respective View (TextView)
for (int i = 0; i < mColumns.length; i++) {
((TextView) view.findViewById(mViews[i])).setText(csr.getString(csr.getColumnIndex(mColumns[i])));
}
// Set the checkbox (note should be false, unless otherwise changed)
CheckBox currentCheckBox = (CheckBox) view.findViewById(mCheckBoxView);
currentCheckBox.setChecked(mCheckBoxStates[mCsr.getPosition()]);
currentCheckBox.setTag(new Long(mCsr.getLong(mCsr.getColumnIndex(DatabaseHandler.KEY_ID))));
//
currentCheckBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
final int position = mCsr.getPosition();
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
// Store the checkbox status
mCheckBoxStates[position] = ((CheckBox) buttonView).isChecked();
int restore_cursor_position = mCsr.getPosition();
//Move the Cursor to the respective row
//NOTE! 1st position in Lisview is 1 but equates to cursor row 0 etc hence -1
mCsr.moveToPosition(position);
Toast.makeText(mContext,
"You Changed the CheckBox for row " +
Integer.toString(position + 1) +
" Item is " +
mCsr.getString(mCsr.getColumnIndex(DatabaseHandler.KEY_ITEM))
,
Toast.LENGTH_SHORT
).show();
//restore the Cursor's position
mCsr.moveToPosition(restore_cursor_position);
}
});
}
// get the list of items (the ID's as long) that have been checked.
public long[] getCheckedRecordIdList() {
// using ArrayList as we can add as we don't yet know how many
ArrayList<Long> rva = new ArrayList<>();
// Just in case save the current position of the Cursor
int restore_cursor_position = mCsr.getPosition();
// Loop through the checkbox states
for (int i=0; i < mCheckBoxStates.length; i++) {
// If the checkbox reflected as being checked then handle, else ignore it
if (mCheckBoxStates[i]) {
// Move to the respective cursor row
mCsr.moveToPosition(i);
// get the respective ID and store in the arraylist
rva.add(mCsr.getLong(mCsr.getColumnIndex(DatabaseHandler.KEY_ID)));
}
}
// Done with the Cursor so re-position it
mCsr.moveToPosition(restore_cursor_position);
// Create the long array to be returned
long[] rv = new long[rva.size()];
// Populate the long array with the id's from the arraylist
for (int i=0; i < rva.size(); i++) {
rv[i] = rva.get(i);
}
// return the long[]
return rv;
}
}
3) The amended MainActivity to use the Custom Adapter and to get the list of checked Records (displays number selected via Toast) - MainActivity.java
Changed/Added Lines/Methods are marked with <<<<<.
:-
public class MainActivity extends AppCompatActivity {
DatabaseHandler mDBHandler;
ListView mListView;
SimpleCursorAdapter mSCA;
MyCustomCursorAdapter mMCA; // <<<<<
Cursor mCsr;
Button mDoItButton;
Context mContext; //<<<<<
long[] mCheckedIdList; //<<<<<
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mContext = this;
mListView = (ListView) this.findViewById(R.id.lv001); // Get the ListView from it's id
mDoItButton = (Button) this.findViewById(R.id.doitbutton); //<<<<<
mDBHandler = new DatabaseHandler(this); // Get an instance of the Database Handler
// Add some data but only if there is no data
if (DatabaseUtils.queryNumEntries(mDBHandler.getWritableDatabase(),DatabaseHandler.TABLE_RECORDS) < 1) {
mDBHandler.insertRecord(100,"Rock","A large stone.","31/12/2017");
mDBHandler.insertRecord(50,"Boulder","A Rock.","31/12/2018");
mDBHandler.insertRecord(322,"Soil","Loose earth.","31/7/2015");
mDBHandler.insertRecord(237,"Stone","A small rock.","31/8/2014");
mDBHandler.insertRecord(32,"Pebble","A small smooth stone.","11/12/2017");
}
mDBHandler.increasePrice(1,213);
// get all rows into a Cursor
mCsr = mDBHandler.getAllRecords();
// Prepare a list of the columns to get the data from, for the ListViewt
String[] columns_to_get_data_from = new String[]{
DatabaseHandler.KEY_ID,
DatabaseHandler.KEY_PRICE,
DatabaseHandler.KEY_ITEM,
DatabaseHandler.KEY_DETAILS,
DatabaseHandler.KEY_DATE
};
// Prepare a list of the Views into which to place the data
int[] itemviews_to_place_data_in = new int[]{
R.id.record_id,
R.id.record_price,
R.id.record_item,
R.id.record_details,
R.id.record_date
};
// get and instance of SimpleCursorAdapter the listviewitem_record layout
mSCA = new SimpleCursorAdapter(this,
R.layout.listviewitem_record,
mCsr,
columns_to_get_data_from,
itemviews_to_place_data_in,
0);
// Tie the adapter to the Listview
mListView.setAdapter(mSCA);
// <<<<<< Alternate Custom Cursor Adapter
mMCA = new MyCustomCursorAdapter(this,
R.layout.listviewitem_record,
mCsr,
columns_to_get_data_from,
itemviews_to_place_data_in,
R.id.record_checkbox //<<<<<< id of the checkbox
);
// Hijack the Listview
mListView.setAdapter(mMCA); //<<<<<<
// <<<<< DO IT BUTTON HANDLER i.e. get list of ID's for checked items
mDoItButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// get the ID's for the checked Items
mCheckedIdList = mMCA.getCheckedRecordIdList();
Toast.makeText(mContext,"You have " + mCheckedIdList.length + " Items checked.",Toast.LENGTH_SHORT).show();
}
});
}
}
Note! you wouldn't typically have two adapters, but I left the SimpleCursorAdapter in for comparison.
Note! be a little patient, as if you click too much too soon you may get consfused.
Note! See other answer for deleting checked items.

Read events from android calendar

I have a little problem with my code .I use Android Studio .
I try to make an application to the phone's calendar events displaying time . I don't have any errors but when I tried to run it to my phone
Caused by:
java.lang.NullPointerException
at net.jimblackler.readcalendar.Example.readCalendar(Example.java:29)
at net.jimblackler.readcalendar.MainActivity.onCreate(MainActivity.java:14)
Here is my cod :
Java Class:
import java.util.Date;
import java.util.HashSet;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.text.format.DateUtils;
public class Example {
public static void readCalendar(Context context) {
ContentResolver contentResolver = context.getContentResolver();
// Fetch a list of all calendars synced with the device, their display names and whether the
// user has them selected for display.
final Cursor cursor = contentResolver.query(Uri.parse("content://calendar/calendars"),
(new String[] { "_id", "displayName", "selected" }), null, null, null);
HashSet<String> calendarIds = new HashSet<String>();
while (cursor.moveToNext()) {
final String _id = cursor.getString(0);
final String displayName = cursor.getString(1);
final Boolean selected = !cursor.getString(2).equals("0");
System.out.println("Id: " + _id + " Display Name: " + displayName + " Selected: " + selected);
calendarIds.add(_id);
}
// For each calendar, display all the events from the previous week to the end of next week.
for (String id : calendarIds) {
Uri.Builder builder = Uri.parse("content://calendar/instances/when").buildUpon();
long now = new Date().getTime();
ContentUris.appendId(builder, now - DateUtils.WEEK_IN_MILLIS);
ContentUris.appendId(builder, now + DateUtils.WEEK_IN_MILLIS);
Cursor eventCursor = contentResolver.query(builder.build(),
new String[] { "title", "begin", "end", "allDay"}, "Calendars._id=" + id,
null, "startDay ASC, startMinute ASC");
while (eventCursor.moveToNext()) {
final String title = eventCursor.getString(0);
final Date begin = new Date(eventCursor.getLong(1));
final Date end = new Date(eventCursor.getLong(2));
final Boolean allDay = !eventCursor.getString(3).equals("0");
System.out.println("Title: " + title + " Begin: " + begin + " End: " + end +
" All Day: " + allDay);
}
}
}
}
MainActivity:
package net.jimblackler.readcalendar;
import android.app.Activity;
import android.os.Bundle;
public class MainActivity extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Example.readCalendar(this);
}
}
First, please check the uri address . For example 'content://calendar/calendars' , it's not used over Android 2.1.
Before Android 14:
calanderURL = "content://calendar/calendars";
calanderEventURL = "content://calendar/events";
calanderRemiderURL= "content://calendar/reminders";
After:
calanderURL = "content://com.android.calendar/calendars";
calanderEventURL = "content://com.android.calendar/events";
calanderRemiderURL = "content://com.android.calendar/reminders";
However, you'd better use like this:
private Uri calendarsUri = Calendars.CONTENT_URI;
private Uri eventsUri = Events.CONTENT_URI;
private Uri remindersUri = Reminders.CONTENT_URI;
private Uri attendeesUri = Attendees.CONTENT_URI;
Second , please check the table column name . You can print the following columns and have a look .
/** Calendars table columns */
public static final String[] CALENDARS_COLUMNS = new String[] {
Calendars._ID, // 0
Calendars.ACCOUNT_NAME, // 1
Calendars.CALENDAR_DISPLAY_NAME, // 2
Calendars.OWNER_ACCOUNT // 3
};
/** Events table columns */
public static final String[] EVENTS_COLUMNS = new String[] {
Events._ID,
Events.CALENDAR_ID,
Events.TITLE,
Events.DESCRIPTION,
Events.EVENT_LOCATION,
Events.DTSTART,
Events.DTEND,
Events.EVENT_TIMEZONE,
Events.HAS_ALARM,
Events.ALL_DAY,
Events.AVAILABILITY,
Events.ACCESS_LEVEL,
Events.STATUS,
};
/** Reminders table columns */
public static final String[] REMINDERS_COLUMNS = new String[] {
Reminders._ID,
Reminders.EVENT_ID,
Reminders.MINUTES,
Reminders.METHOD,
};
/** Reminders table columns */
public static final String[] ATTENDEES_COLUMNS = new String[] {
Attendees._ID,
Attendees.ATTENDEE_NAME,
Attendees.ATTENDEE_EMAIL,
Attendees.ATTENDEE_STATUS
};
Third, you code manner is very bad .You should declare these above parameters as 'static final' ones .

How to avoid duplicate contact name (data ) while loading contact info to listview?

I am populating contact list details to list view successfully.
My code:
String order = ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + " ASC";
Cursor curLog = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null,null,null,order);
How can I avoid the duplicate data In List view as the contact details is repeating if its joined contact i.e. joined with both phone and Google?. The screen is like
I want to select programmatically only 1 name not the both? Any Idea how I can select?
I have used a rough way to avoid this problem which helped me so much and working nicely.
i.e
Use local database (SQLite) to avoid duplicate data by make phone number to unique.
I have made one SQLite DB to handle this problem:
ContactMerger.java:
public class ContactMerger {
private static final String CONTACT_TABLE = "_contact_table";
private static final String CONTACT_ID = "_contactId";
private static final String CONTACT_NAME = "_contactName";
private static final String CONTACT_MOBILE_NUMBER = "_contactNumber";
private static final String CONTACT_DATE = "_contactDate";
private static final int DATABASE_VERSION = 1;
private static final String DATABASE_NAME = "DB_Contact";
private final Context context;
private SQLiteDatabase ourDatabase;
private DbHelper ourHelper;
private class DbHelper extends SQLiteOpenHelper {
public DbHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
#Override
public void onCreate(SQLiteDatabase db) {
// TODO Auto-generated method stub
String contactQuery = "CREATE TABLE " + CONTACT_TABLE + " ("
+ CONTACT_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
+ CONTACT_NAME + " TEXT NOT NULL, " + CONTACT_DATE
+ " TEXT NOT NULL, " + CONTACT_MOBILE_NUMBER
+ " TEXT NOT NULL UNIQUE);";
db.execSQL(contactQuery);
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// TODO Auto-generated method stub
db.execSQL("DROP TABLE IF EXISTS " + CONTACT_TABLE);
onCreate(db);
}
}
public ContactMerger(Context context) {
this.context = context;
}
public ContactMerger open() throws SQLException {
ourHelper = new DbHelper(context);
ourDatabase = ourHelper.getWritableDatabase();
return this;
}
public void close() {
ourHelper.close();
}
// Insert Data to Contact Table
public long insertContacts(String name, String number, String date) throws SQLException {
ContentValues cv = new ContentValues();
cv.put(CONTACT_NAME, name);
cv.put(CONTACT_DATE, date);
cv.put(CONTACT_MOBILE_NUMBER, number);
Log.d("Insert Data", cv.toString());
return ourDatabase.insert(CONTACT_TABLE, null, cv);
}
//Get Contact details from Contact Table
public ArrayList<ContactHolder> getContactDetails() throws Exception{
ArrayList<ContactHolder> contactDetails = new ArrayList<ContactHolder>();
String[] columns = new String[] { CONTACT_ID, CONTACT_NAME, CONTACT_DATE, CONTACT_MOBILE_NUMBER };
Cursor c = ourDatabase.query(CONTACT_TABLE, columns, null, null, null,null, null);
int iContactName = c.getColumnIndex(CONTACT_NAME);
int iContactDate = c.getColumnIndex(CONTACT_DATE);
int iContactMobileNumber = c.getColumnIndex(CONTACT_MOBILE_NUMBER);
for (c.moveToFirst(); !c.isAfterLast(); c.moveToNext()) {
ContactHolder data = new ContactHolder();
data.setName(c.getString(iContactName));
data.setDate(c.getString(iContactDate));
data.setNumber(c.getString(iContactMobileNumber));
contactDetails.add(data);
}
return contactDetails;
}
}
Here ContactHolder is just a getter/setter class to handle contact entities.
First I inserted all Contact information once in my MainActivity by the help of a background thread. It prevents to insert the contact info multiple times.
Something like:
private ArrayList<ContactHolder> contactHolder;
private void setCallLogs(Cursor managedCursor) {
contactHolder = new ArrayList<ContactHolder>();
int _number = managedCursor
.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER);
int _name = managedCursor
.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME);
int _id = managedCursor
.getColumnIndex(ContactsContract.CommonDataKinds.Phone._ID);
while (managedCursor.moveToNext()) {
ContactHolder holder = new ContactHolder();
holder.setNumber(managedCursor.getString(_number));
holder.setName(managedCursor.getString(_name));
holder.setDate(managedCursor.getString(_id));
contactHolder.add(holder);
}
Thread t = new Thread(new Runnable() {
#Override
public void run() {
for(int i=0; i<contactHolder.size(); i++){
try{
ContactMerger merger = new ContactMerger(HomeActivity.this);
merger.open();
merger.insertContacts(contactHolder.get(i).getName(),
contactHolder.get(i).getNumber(),
contactHolder.get(i).getdate());
merger.close();
} catch(Exception e){
e.printStackTrace();
}
}
}
});
t.start();
}
At last I gtt all contact information inside an Asynctask(doInbackground()) and put in adapter/listview in its onPostExecute() method in the class I want to show.
Here:
#Override
protected ArrayList<ContactHolder> doInBackground(String... parameters) {
ArrayList<ContactHolder> filterContacts = new ArrayList<ContactHolder>();
ContactMerger merger = new ContactMerger(Aaja_Contact.this);
merger.open();
try {
filterContacts = merger.getContactDetails();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
merger.close();
return filterContacts;
}
I believe this may happen if the contact number is stored in two different ways/formats: for example in your case the number for Akshay may be saved as 982-0123456 and 9820123456
Did you try displaying the number along with the Name by including the Number as well in the list view?
You need to retrieve the data from the Cursor to HashSet (which don't allows duplicate itmes) and then pass the HashSet object to your ListView's Adapter
This is a dump solution but it will help you:
ListView listView;
Set<String> listItems;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
listView = (ListView) findViewById(R.id.listView);
listItems = new HashSet<String>();
String order = ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + " ASC";
Cursor curLog = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null,null,null,order);
if(curLog != null) {
while(curLog.moveToNext()) {
String str = curLog.getString(curLog.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME_PRIMARY));
listItems.add(str);
}
}
String listString = listItems.toString();
listString = listString.substring(1,listString.length()-1);
String[] newList = listString.split(", ");
ArrayAdapter<String> adapter = new ArrayAdapter<String>(MainActivity.this, android.R.layout.simple_list_item_1, newList);
listView.setAdapter(adapter);
}
Good luck..
Since you're querying Phone.CONTENT_URI, I'm assuming you're looking for contacts with phone number.. then you can use ContactsContract.Contacts.CONTENT_URI
String order = ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + " ASC";
Cursor curLog = getContentResolver().query(ContactsContract.Contacts.CONTENT_URI, null,
ContactsContract.Contacts.HAS_PHONE_NUMBER + "=?", new String[] { "1" }, order);
Its because the listview is showing both normal contacts as well as whatsapp( or like this) linked contacts. Best is to store all the contacts in a Database and then retrieve the contacts using "select distinct..." command of SQL.
String order = ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + " ASC";
Cursor phones = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null,null,null, order);
String temp_name="";
while (phones.moveToNext())
{
String name=phones.getString(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
if (name.equals(temp_name))
continue;
temp_name=name;
//add name to your list or adapter here`enter code here`
}
phones.close();
When you loop through your contacts, here's something you can do in the looping statement while you add your next object to avoid creating a duplicate contact:
UserList object=new UserList(name,number);
if(arrayList.size()==0)
{
arrayList.add(object);
}
if(arrayList.size()>0) {
position = arrayList.size();
if (!(arrayList.get(arrayList.position - 1).getName().equals(number) ||
arrayList.get(position - 1).getNumber().equals(number)))
{
arrayList.add(object); }
}
Here, in my object of 'UserList' class, the name and number would repeat from the contact list, so this code just checks if the previous object has the same name or number before adding in the new one.
Old question but still relevant. I could not find suitable query to skip dupes with contentresolver but it's possible to compare all contacts for duplicates by phone number.
With com.googlecode.libphonenumber library it's really simple. Method public MatchType isNumberMatch(CharSequence firstNumber, CharSequence secondNumber) compares number, coutry code, mask and return one of MatchType enum value.

Android SQLite: attempt to re-open an already-closed object

I'm trying to get certain book data from my Inventory table based on the ISBN.
However, I'm getting an error: "attempt to re-open an already-closed object". The error only occurs when I click a listView object, go to a different screen, go back to this page via "finish()", and then try to click on another listView object. I moved the String searchEntries[] = InventoryAdapter.getInventoryEntriesByISBN(searchQuery, isbn[position]); from the onClickListener to the previous for loop before the onClickListener and now it works.
Why does it not work if I try to getInventoryEntriesByISBN after returning to this activity from another activity via "finish()"?
The error occurs at SearchResultsScreen:
String searchEntries[] = InventoryAdapter.getInventoryEntriesByISBN(searchQuery, isbn[position]);
and by extension, occurs at InventoryAdapter:
Cursor cursor = db.rawQuery(query, new String[] {ISBN});
SearchResultsScreen.java
// Set up search array
for(int i = 0; i < isbn.length; i++)
{
searchArray.add(new InventoryItem(isbn[i], InventoryAdapter.getTitleAndAuthorByISBN(isbn[i])));
}
Toast.makeText(getApplicationContext(), "searchArray.size()="+searchArray.size(), Toast.LENGTH_LONG).show();
// add data in custom adapter
adapter = new CustomAdapter(this, R.layout.list, searchArray);
ListView dataList = (ListView) findViewById(R.id.list);
dataList.setAdapter(adapter);
// On Click ========================================================
dataList.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) {
String searchEntries[] = InventoryAdapter.getInventoryEntriesByISBN(searchQuery, isbn[position]);
InventoryAdapter.java (Most relevant parts)
public String[] getInventoryEntriesByISBN(String search, String ISBN)
{
String[] searchEntry = new String [9];
//Query
String query = "select * from INVENTORY where ISBN = ?";
Cursor cursor = db.rawQuery(query, new String[] {ISBN});
if(cursor.getCount()<1) // title Not Exist
{
cursor.close();
for(int i = 0; i < 9; i++)
searchEntry[i] = "Not Found";
return searchEntry;
}
cursor.moveToFirst();
//put data into respective variable
int publish = cursor.getInt(cursor.getColumnIndex("PUBLISH_DATE"));
String publishdate = ((Integer)publish).toString();
String title = cursor.getString(cursor.getColumnIndex("TITLE"));
String author = cursor.getString(cursor.getColumnIndex("AUTHOR"));
String callNumber = cursor.getString(cursor.getColumnIndex("CALL_NUMBER"));
int available = cursor.getInt(cursor.getColumnIndex("AVAILABLE_COUNT"));
String availablecount = ((Integer)available).toString();
int inventory = cursor.getInt(cursor.getColumnIndex("INVENTORY_COUNT"));
String inventorycount = ((Integer)inventory).toString();
int due = cursor.getInt(cursor.getColumnIndex("DUE_PERIOD"));
String dueperiod = ((Integer)due).toString();
int checkoutcount = cursor.getInt(cursor.getColumnIndex("COUNT"));
String count = ((Integer)checkoutcount).toString();
//combine variables into one array
searchEntry[0] = ISBN;
searchEntry[1] = title;
searchEntry[2] = author;
searchEntry[3] = publishdate;
searchEntry[4] = callNumber;
searchEntry[5] = availablecount;
searchEntry[6] = inventorycount;
searchEntry[7] = dueperiod;
searchEntry[8] = count;
cursor.close();
return searchEntry;
}
public String getTitleAndAuthorByISBN(String ISBN)
{
int entriesFound = getNumSearchEntries(ISBN);
if(entriesFound==0)
entriesFound = 1;
String searchEntry;
//Query
String query = "select * from INVENTORY where ISBN = ?";
Cursor cursor = db.rawQuery(query, new String[] {ISBN});
if(cursor.getCount()<1) // title Not Exist
{
cursor.close();
searchEntry = "Not Found";
return searchEntry;
}
cursor.moveToFirst();
//put data into respective variable
String title = cursor.getString(cursor.getColumnIndex("TITLE"));
String author = cursor.getString(cursor.getColumnIndex("AUTHOR"));
//combine variables into one String
searchEntry = title + " / " + author;
//close cursor and return
cursor.close();
return searchEntry;
}
DataBaseHelper.java
public class DataBaseHelper extends SQLiteOpenHelper
{
// Database Version
private static final int DATABASE_VERSION = 1;
// Database Name
private static final String DATABASE_NAME = "database.db";
// ============================ End Variables ===========================
public DataBaseHelper(Context context, String name, CursorFactory factory, int version)
{
super(context, name, factory, version);
}
public DataBaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
// Called when no database exists in disk and the helper class needs
// to create a new one.
#Override
public void onCreate(SQLiteDatabase _db)
{
_db.execSQL(LoginDataBaseAdapter.USER_TABLE_CREATE);
_db.execSQL(CheckOutDataBaseAdapter.CHECKOUT_TABLE_CREATE);
_db.execSQL(InventoryAdapter.INVENTORY_TABLE_CREATE);
_db.execSQL(StatisticsAdapter.STATISTICS_TABLE_CREATE);
}
// Called when there is a database version mismatch meaning that the version
// of the database on disk needs to be upgraded to the current version.
#Override
public void onUpgrade(SQLiteDatabase _db, int _oldVersion, int _newVersion)
{
// Log the version upgrade.
Log.w("TaskDBAdapter", "Upgrading from version " +_oldVersion + " to " +_newVersion + ", which will destroy all old data");
// Upgrade the existing database to conform to the new version. Multiple
// previous versions can be handled by comparing _oldVersion and _newVersion
// values.
// on upgrade drop older tables
_db.execSQL("DROP TABLE IF EXISTS " + LoginDataBaseAdapter.USER_TABLE_CREATE);
_db.execSQL("DROP TABLE IF EXISTS " + CheckOutDataBaseAdapter.CHECKOUT_TABLE_CREATE);
_db.execSQL("DROP TABLE IF EXISTS " + InventoryAdapter.INVENTORY_TABLE_CREATE);
_db.execSQL("DROP TABLE IF EXISTS " + StatisticsAdapter.STATISTICS_TABLE_CREATE);
// Create a new one.
onCreate(_db);
}
}
Check Database Connection before executing query:
if (!dbHelper.db.isOpen())
dbHelper.open();
you can also use cursor.requery(); for again same query.
and in last you have to close the cursor and database also.
cursor.close();
db.close();
Edited:
I have created DBHelper class which extends SQLiteOpenHelper, this class is inner class of DatabaseHelper class and that class have following methods.
/** For OPEN database **/
public synchronized DatabaseHelper open() throws SQLiteException {
dbHelper = new DBHelper(context);
db = dbHelper.getWritableDatabase();
return this;
}
/** For CLOSE database **/
public void close() {
dbHelper.close();
}
If you have still doubt then feel free to ping me. Thank you.
The error only occurs when I click an item, go to a different screen, go back to this page via "finish()", and then try to click on another listView object.
I moved the String searchEntries[] = InventoryAdapter.getInventoryEntriesByISBN(searchQuery, isbn[position]); from the onClickListener to the previous for loop before the onClickListener and now it works.
The correct SearchResultsScreen is below:
SearchResultsScreen.java
// Set up search array
final String Entries[][] = new String[isbn.length][9];
for(int i = 0; i < isbn.length; i++)
{
searchArray.add(new InventoryItem(isbn[i], InventoryAdapter.getTitleAndAuthorByISBN(isbn[i])));
Entries[i] = InventoryAdapter.getInventoryEntriesByISBN(searchQuery, isbn[i]);
}
Toast.makeText(getApplicationContext(), "searchArray.size()="+searchArray.size(), Toast.LENGTH_LONG).show();
// add data in custom adapter
adapter = new CustomAdapter(this, R.layout.list, searchArray);
ListView dataList = (ListView) findViewById(R.id.list);
dataList.setAdapter(adapter);
// On Click ========================================================
dataList.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) {
String searchEntries[] = Entries[position];
This is your problem
if(cursor.getCount()<1) // title Not Exist
{
cursor.close();
for(int i = 0; i < 9; i++)
searchEntry[i] = "Not Found";
return searchEntry;
}
cursor.moveToFirst();
cursor.close();
Change to
for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
{
String title = cursor.getString(cursor.getColumnIndex("TITLE"));
String author = cursor.getString(cursor.getColumnIndex("AUTHOR"));
//combine variables into one String
searchEntry = title + " / " + author;
}
public String[] getInventoryEntriesByISBN(String search, String ISBN)
{
String[] searchEntry = new String [9];
//Query
String query = "select * from INVENTORY where ISBN = ?";
Cursor cursor = db.rawQuery(query, new String[] {ISBN});
Add SQLiteDatabase db = this.getWritableDatabase(); in this code before executing the raw Query

"Null" appended to database input values from a delimited string

I wonder if someone could show me the error of my ways--I've been struggling with this issue for two days, and realize it must be a fundamental error of initializing variables, but...that reflects the level of my java knowledge.
I'm getting a database result on a delimited string wherein each of the segments has "null" appended to it. It seems that no matter how I change the initialization...well, two days!
I'm declaring the following in the class heading area:
private String strListContent;
private SQLiteDatabase database;
private DatabaseHelper helper2 = new DatabaseHelper(this);
private static final String fields[] = { "_id", "listTitle", "listType",
"listContent", "dateCreated", "dateModified" };
private ArrayList<String> textArray = new ArrayList<String>();
private ArrayList<Integer> imageArray = new ArrayList<Integer>();
Then concatenating my items in
final ImageButton addItem = (ImageButton) findViewById(R.id.btnToAddItem);
addItem.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
itemEdit = (EditText) findViewById(R.id.editTextItem);
if (itemEdit.getText().toString().equals("")) {
showToastMessage("Please enter an item to add...");
} else {
String newListItem = itemEdit.getText().toString();
strListContent += newListItem + "|~|";
...
}}}
I'm using the following bare-bones SQLiteOpenHelper:
public class DatabaseHelper extends SQLiteOpenHelper {
public static final String KEY_ID = "_id";
public DatabaseHelper(Context context) {
super(context, "Cursor", null, 1);
}
#Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("CREATE TABLE IF NOT EXISTS list_data ("
+ KEY_ID
+ " INTEGER PRIMARY KEY AUTOINCREMENT, listTitle TEXT, listType TEXT, listContent TEXT, dateCreated TEXT, dateModified TEXT)");
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// Steps to upgrade the database for the new version ...
}
}
To insert the values as so:
ImageButton saveAndBack = (ImageButton) findViewById(R.id.btnSaveBack);
saveAndBack.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
String title = null;
String listContent = null;
Calendar javaCalendar = null;
title = titleEdit.getText().toString();
title = (title=="" || title==null)?"Untitled List":title;
strListContent = (strListContent=="" || strListContent==null)?"No Items|~|":strListContent;
listContent = strListContent;
String type = "R"; //"Regular List"
javaCalendar = Calendar.getInstance();
String currentDate = javaCalendar.get(Calendar.MONTH) + "/" + (javaCalendar.get(Calendar.DATE) + 1) + "/" + javaCalendar.get(Calendar.YEAR);
database = helper2.getWritableDatabase();
ContentValues values = new ContentValues();
values.put("listTitle", title);
values.put("listType", type);
values.put("listContent", listContent);
values.put("dateCreated", currentDate);
values.put("dateModified", currentDate);
database.insert("list_data", null, values);
Intent i = new Intent(RegularList.this, ActivityMain.class);
startActivity(i);
}
});
}
//
//End of OnCreate(){}
//
Then, when I retrieve from another activity:
DatabaseHelper helper = new DatabaseHelper(this);
database = helper.getWritableDatabase();
Cursor data = database.query("list_data", fields, null, null, null,
null, null);
Integer tindex = data.getColumnIndex("listTitle");
Integer iindex = data.getColumnIndex("listType");
Integer cindex = data.getColumnIndex("listContent");
itemCount = 0;
for (data.moveToFirst(); !data.isAfterLast(); data.moveToNext()) {
showToastMessage(data.getString(cindex));
titleArrayList.add(data.getString(tindex));
if (data.getString(iindex) == "R") {
imageArrayList.add(R.drawable.listview_regular);
} else if (data.getString(iindex) == "L") {
imageArrayList.add(R.drawable.listview_location);
} else {
imageArrayList.add(R.drawable.listview_regular);
}
itemCount++;
}
data.close();
...
I can see in the toast message that each item from the delimited string has "null" appended to the front of it...the other values are fine. I hope this hasn't been too verbose, but...any recommendations? Thanks!
To me it looks like you may have simply not initialised the String strListContent before you first append to it with:
strListContent += newListItem + "|~|";
When you do that, you'll get a "null" prefixed in front of the value you are trying to append, just as you observe.
Perhaps you can just initialise in the declaration:
private String strListContent = "";

Categories

Resources