I am new to Android and SQLite database. I have been following online examples for storing and retrieving data from database but I get error when reading.
The code below is simple code for writing and reading data from database. When writing there is no error in application but when reading data, the application closes by displaying error. I am using Android studio 1.2.2 and testing it on Android version 5.0.1 Galaxy S4. Can any one tell me what is the problem here ?
/*********************activity_main.xml *************/
<LinearLayout 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=".MainActivity">
<TextView android:text="Hello Hello"
android:id="#+id/msg"
android:layout_width="wrap_content" android:layout_height="wrap_content" />
<ListView android:id="#+id/contactListView"
android:layout_width="match_parent" android:layout_height="wrap_content"
android:layout_below="#+id/msg"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_marginTop="48dp" />
</LinearLayout>
/*********************row.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="match_parent"
android:padding="10dip" >
<TextView android:id="#+id/Name"
android:layout_height="wrap_content" android:layout_width="match_parent"
android:layout_marginLeft="25dp" />
</LinearLayout>
/****************** Main Activity *****************/
public class MainActivity extends ActionBarActivity {
List<String> stringList = new ArrayList<String>();
ListAdapter adapter = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ListView listview = (ListView) findViewById(R.id.contactListView);
adapter = new ListAdapter(this, stringList);
listview.setAdapter(adapter);
NameDatabase db = null;
db = new NameDatabase(this);
db.addContact(1, "Sujan Raj Shrestha");
db.addContact(2, "Kim Sae Hyun");
db.addContact(3, "Kim Jong Kwon");
Cursor cr = db.getData(0);
adapter.add(cr.getString(1).toString());
}
public class ListAdapter extends ArrayAdapter<String>{
public ListAdapter(Context context, List<String> object){
super(context, R.layout.row, object);
}
#Override
public View getView(int position, View convertView, ViewGroup parent){
View row = convertView;
String nm = stringList.get(position);
if (row == null){
LayoutInflater inflater = getLayoutInflater();
row = inflater.inflate(R.layout.row, null);
}
((TextView) row.findViewById(R.id.Name)).setText(nm);
return row;
}
}
#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_main, menu);
return true;
}
}
/ *************** NameDatabase.java ****************/
public class NameDatabase extends SQLiteOpenHelper {
private static final int DATABASE_VERSION = 1;
private static final String NAMELIST = "nametable";
public NameDatabase (Context context){
super(context, NAMELIST, null, DATABASE_VERSION);
}
public void onCreate(SQLiteDatabase db){
String CREATE_CONTACTS_TABLE = "CREATE TABLE contacts" +" (id INTEGER PRIMARY KEY, name TEXT NOT NULL )";
db.execSQL(CREATE_CONTACTS_TABLE);
}
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion){
db.execSQL("Drop TABLE IF EXISTS" + NAMELIST);
onCreate(db);
}
public boolean addContact(int id, String name){
SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues();
values.put("id", id);
values.put("name", name);
db.insert(NAMELIST, null, values);
db.close();
return true;
}
public Cursor getData(int id){
SQLiteDatabase db = this.getReadableDatabase();
Cursor res = db.rawQuery("select * from nametable where id=" + id + "", null);
return res;
}
}
I just figured out your issue the main issue is the table from where you are querying on is not correct, indeed it is your database name, They correct version of getData() is following:
public Cursor getData(int id){
SQLiteDatabase db = this.getReadableDatabase();
Cursor res = db.rawQuery("select * from contacts where id=" + id + "", null);
return res;
}
You are trying to access the content of table using database name. Try using table name as "contacts". Replace NAMELIST = "contacts" , also Pass the Database name in Constructor
like super(context, DATABASE_NAME, null, DATABASE_VERSION);
and add variable
String DATABASE_NAME = "someName";
For getting Cursor results add
res.moveToNext();
below of
Cursor res = db.rawQuery("select * from nametable where id=" + id + "", null);
Since you are querying the table but your cursor remains at -1 position by default. Therefore we have to move cursor to row 1 and so on.
Hope this works. :)
Peace V
try this to fetch the data from database
cur = db.query(true, "contacts", new String[] {
"id", "name"
}, "id = " + id, null, null, null, null, null);
Related
**Good day everyone ...
I badly need your help.
Can I ask on why my listview doesnt display and also my alert dialog?
here is my code
I've already inserted table values in the sqlite database and Im confused on why nothing displays on my listview and dialog.
the listview uses an adapter that i queried in the DBHelper
MainActivity
public class MainActivity extends AppCompatActivity {
private QuestionaireDB commandQuery;
private ListView showQuestion;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
commandQuery = new QuestionaireDB(this);
ShowTables();
ArrayList getQuestion = commandQuery.getAllQuestions();
ArrayAdapter arrayAdapter = new ArrayAdapter(this,android.R.layout.simple_list_item_1,getQuestion);
showQuestion = (ListView)findViewById(R.id.viewAll);
showQuestion.setAdapter(arrayAdapter);
}
private void ShowTables(){
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this);
alertDialogBuilder.setMessage("You have "+commandQuery.numberOfRows()+"");
alertDialogBuilder.setNegativeButton("NO", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialogInterface, int i) {
finish();
}
});
}
}
QuestionaireDB
public class QuestionaireDB extends SQLiteOpenHelper{
//tblQuestion
public static final String DATABASE_NAME = "QuestionaireDB.db";
public static final String DATABASE_TABLE_tblQuestion = "tblQuestion";
public static final String DATABASE_TABLE_tblChoices = "tblChoices";
public static final String DATABASE_TABLE_tblAnswers = "tblAnswers";
public static final String DATABASE_TABLE_tblCategory = "tblCategory";
public QuestionaireDB(Context context) {
super(context, DATABASE_NAME , null, 3);
}
#Override
public void onCreate(SQLiteDatabase db) {
//tblQuestion
String CreatetblQueston="CREATE TABLE "+DATABASE_TABLE_tblQuestion +
"(questionID INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,categoryID INTEGER,
questionName TEXT)";
//tblChoices
String CreatetblChoices="CREATE TABLE "+DATABASE_TABLE_tblChoices +
"(questionID INTEGER NOT NULL, ID INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
questionChoices TEXT)";
//tblAnswers
String CreatetblAnswers="CREATE TABLE "+DATABASE_TABLE_tblAnswers+
"(questionID INTEGER NOT NULL, questionCorrectAnswer TEXT, ID INTEGER PRIMARY KEY
AUTOINCREMENT NOT NULL)";
//tblCategory
String CreateCategory="CREATE TABLE "+DATABASE_TABLE_tblCategory+
" (categoryID INTEGER NOT NULL,categoryName TEXT, PRIMARY KEY (categoryID ASC))";
db.execSQL(CreatetblQueston);
db.execSQL(CreatetblChoices);
db.execSQL(CreatetblAnswers);
db.execSQL(CreateCategory);
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
String confirmationQuestion="DROP TABLE IF EXISTS "+DATABASE_TABLE_tblQuestion ;
String confirmationChoices="DROP TABLE IF EXISTS "+DATABASE_TABLE_tblChoices ;
String confirmationAnswers="DROP TABLE IF EXISTS "+DATABASE_TABLE_tblAnswers ;
String confirmationCategory="DROP TABLE IF EXISTS "+DATABASE_TABLE_tblCategory ;
db.execSQL(confirmationQuestion);
db.execSQL(confirmationChoices);
db.execSQL(confirmationAnswers);
db.execSQL(confirmationCategory);
}
public ArrayList<String> getAllQuestions() {
ArrayList<String> array_list = new ArrayList<String>();
SQLiteDatabase db = this.getReadableDatabase();
Cursor res = db.rawQuery( "select * from tblQuestion", null );
res.moveToFirst();
while(res.isAfterLast() == false){
array_list.add(res.getString(res.getColumnIndex("questionName")));
res.moveToNext();
}
return array_list;
}
public int numberOfRows(){
SQLiteDatabase db = this.getReadableDatabase();
int numRows = (int) DatabaseUtils.queryNumEntries(db, DATABASE_TABLE_tblQuestion);
return numRows;
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
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=".MainActivity">
<ListView
android:id="#+id/viewAll"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
</LinearLayout>
`
First of all you need to call show() method of dialog like written below,
alertDialogBuilder.show(); //add this line in your ShowTables()
Replace line
ArrayList getQuestion=commandQuery.getAllQuestions();
with
ArrayList<String> getQuestion=commandQuery.getAllQuestions();
And check whether you are getting atleast one data from your database(check list size)
The goal of the sample application is to display items from a SQLite database, but hide the second text view if the database record has a hide flag active (otherwise display the second text view).
The problem is that it doesn't hide the right things. And as scroll actions cause items to go out of view, and back into view, the second text view gets hidden and and shown on various list items in an erratic manner.
The hidden flag has been set on items 5, 10, 15, 20, and here is how it comes-up:
Scrolling down, various other strange items are hidden, and it doesn't seem to be the same each time. Entry 14, Entry 16, are hidden, for instance.
After Scrolling to the top, we see the first set of items no longer has the same hidden second lines.
Then a whole new set of entries are hidden scrolling back and forth. Not quite random, but inexplicable. You've got to see it to believe it.
The 'real' application that this sample is based-upon (not shown here) actually is attempting to show and hide an ImageView, but the same kind of problem surrounds hiding a TextView, so that's what's I've shown here.
Below is the application. Everything you need should be included (including sample data), should you wish to run this crazy thing. Or you can find it on github: https://github.com/sengsational/LvCaApp
LvCaActivity.java:
public class LvCaActivity extends AppCompatActivity {
private SimpleCursorAdapter dataAdapter;
private DbAdapter dbHelper;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_lv_ca);
dbHelper = new DbAdapter(this);
dbHelper.open();
dbHelper.deleteAll();
dbHelper.insertSome();
Cursor bCursor = dbHelper.fetchAll(DbAdapter.bColumns);
dataAdapter = new MySimpleCursorAdapter(
this, R.layout.b_item,
bCursor,
DbAdapter.bColumns,
ViewHolder.viewsArray,
0);
ListView listView = (ListView) findViewById(R.id.listView1);
listView.setAdapter(dataAdapter);
}
}
activity_lv_ca.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent" android:layout_height="fill_parent"
android:orientation="vertical">
<ListView android:id="#+id/listView1" android:layout_width="fill_parent"
android:layout_height="fill_parent" />
</LinearLayout>
b_item.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="wrap_content"
android:orientation="vertical"
android:padding="6dip"
android:id="#+id/b_item_layout">
<TextView
android:id="#+id/bName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:textAppearance="?android:attr/textAppearanceListItem"
android:ellipsize="end"
android:singleLine="true"
android:paddingTop="30dp"/>
<TextView
android:id="#+id/bSecondLine"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/bName"
android:textAppearance="?android:attr/textAppearanceSmall" />
<TextView
android:id="#+id/bDbItem"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:visibility="gone"
/>
<TextView
android:id="#+id/bHidden"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:visibility="gone"
/>
</RelativeLayout>
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest package="com.company.cpp.lvcaapp"
xmlns:android="http://schemas.android.com/apk/res/android">
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".LvCaActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
</manifest>
DbAdapter.java:
public class DbAdapter {
private static final String TAG = "DbAdapter";
private DatabaseHelper mDbHelper;
private SQLiteDatabase mDb;
private static final String DATABASE_NAME = "adbname";
private static final String SQLITE_TABLE = "atablename";
private static final int DATABASE_VERSION = 1;
private final Context mCtx;
public static final String[] bColumns = new String[] {
"_id",
"NAME",
"SECOND_LINE",
"HIDDEN",
};
private static final String DATABASE_CREATE =
"CREATE TABLE if not exists " + SQLITE_TABLE + " (" +
"_id INTEGER PRIMARY KEY AUTOINCREMENT, " +
"NAME TEXT, " +
"SECOND_LINE, " +
"HIDDEN" +
");";
private static class DatabaseHelper extends SQLiteOpenHelper {
DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
#Override
public void onCreate(SQLiteDatabase db) {
Log.w(TAG, DATABASE_CREATE);
db.execSQL(DATABASE_CREATE);
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
Log.w(TAG, "Upgrading database from version " + oldVersion + " to "
+ newVersion + ", which will destroy all old data");
db.execSQL("DROP TABLE IF EXISTS " + SQLITE_TABLE);
onCreate(db);
}
}
public DbAdapter(Context ctx) {
this.mCtx = ctx;
}
public DbAdapter open() throws SQLException {
mDbHelper = new DatabaseHelper(mCtx);
mDb = mDbHelper.getWritableDatabase();
return this;
}
public void close() {
if (mDbHelper != null) {
mDbHelper.close();
}
}
public Cursor fetchAll(String[] fields) {
Cursor mCursor = mDb.query(SQLITE_TABLE, fields, null, null, null, null, null);
if (mCursor != null) {
mCursor.moveToFirst();
}
return mCursor;
}
public void insertSome() {
AListItem.getInstance();
String sampleData = "[{\"name\":\"Entry 1\",\"second_line\":\"Second Line 1\",\"hidden\":\"F\"},{\"name\":\"Entry 2\",\"second_line\":\"Second Line 2\",\"hidden\":\"F\"},{\"name\":\"Entry 3\",\"second_line\":\"Second Line 3\",\"hidden\":\"F\"},{\"name\":\"Entry 4\",\"second_line\":\"Second Line 4\",\"hidden\":\"F\"},{\"name\":\"EntryH 5\",\"second_line\":\"Second Line 5\",\"hidden\":\"T\"},{\"name\":\"Entry 6\",\"second_line\":\"Second Line 6\",\"hidden\":\"F\"},{\"name\":\"Entry 7\",\"second_line\":\"Second Line 7\",\"hidden\":\"F\"},{\"name\":\"Entry 8\",\"second_line\":\"Second Line 8\",\"hidden\":\"F\"},{\"name\":\"Entry 9\",\"second_line\":\"Second Line 9\",\"hidden\":\"F\"},{\"name\":\"EntryH 10\",\"second_line\":\"Second Line 10\",\"hidden\":\"T\"},{\"name\":\"Entry 11\",\"second_line\":\"Second Line 11\",\"hidden\":\"F\"},{\"name\":\"Entry 12\",\"second_line\":\"Second Line 12\",\"hidden\":\"F\"},{\"name\":\"Entry 13\",\"second_line\":\"Second Line 13\",\"hidden\":\"F\"},{\"name\":\"Entry 14\",\"second_line\":\"Second Line 14\",\"hidden\":\"F\"},{\"name\":\"EntryH 15\",\"second_line\":\"Second Line 15\",\"hidden\":\"T\"},{\"name\":\"Entry 16\",\"second_line\":\"Second Line 16\",\"hidden\":\"F\"},{\"name\":\"Entry 17\",\"second_line\":\"Second Line 17\",\"hidden\":\"F\"},{\"name\":\"Entry 18\",\"second_line\":\"Second Line 18\",\"hidden\":\"F\"},{\"name\":\"Entry 19\",\"second_line\":\"Second Line 19\",\"hidden\":\"F\"},{\"name\":\"EntryH 20\",\"second_line\":\"Second Line 20\",\"hidden\":\"T\"},{\"name\":\"Entry 21\",\"second_line\":\"Second Line 21\",\"hidden\":\"F\"},{\"name\":\"Entry 22\",\"second_line\":\"Second Line 22\",\"hidden\":\"F\"},{\"name\":\"Entry 23\",\"second_line\":\"Second Line 23\",\"hidden\":\"F\"}]";
String[] items = sampleData.split("\\},\\{");
for(String item: items){
AListItem.clear();
AListItem.load(item);
if(AListItem.getName().contains("Hide")){
AListItem.setHidden("T");
}
mDb.insert(SQLITE_TABLE, null, AListItem.getContentValues());
ContentValues values = AListItem.getContentValues();
Log.v(TAG, "values.toString()" + values.toString());
}
}
public boolean deleteAll() {
int doneDelete = 0;
doneDelete = mDb.delete(SQLITE_TABLE, null , null);
Log.w(TAG, Integer.toString(doneDelete));
return doneDelete > 0;
}
}
AListItem.java:
public class AListItem {
static String rawInputString;
static String name;
static String second_line;
static String hidden;
static AListItem aListItem;
private AListItem() {
}
public static AListItem getInstance(){
if (aListItem == null) {
aListItem = new AListItem();
}
return aListItem;
}
public static void clear() {
rawInputString = null;
name = null;
second_line = null;
hidden = null;
}
public static ContentValues getContentValues() {
ContentValues values = new ContentValues();
values.put("NAME", name);
values.put("SECOND_LINE", second_line);
values.put("HIDDEN", hidden);
return values;
}
public static void load(String string) {
StringBuffer buf = new StringBuffer(string);
if (buf.substring(0,2).equals("[{")){
buf.delete(0,2);
}
rawInputString = buf.toString();
parse();
}
public static void parse() {
if (rawInputString == null) {
System.out.println("nothing to parse");
return;
}
rawInputString = rawInputString.replaceAll("\"\\:null,", "\"\\:\"null\",");
String[] nvpa = rawInputString.split("\",\"");
for (String nvpString : nvpa) {
String[] nvpItem = nvpString.split("\":\"");
if (nvpItem.length < 2) continue;
String identifier = nvpItem[0].replaceAll("\"", "");
String content = nvpItem[1].replaceAll("\"", "");
switch (identifier) {
case "name":
setName(content);
break;
case "second_line":
setSecond_line(content);
break;
case "hidden":
setHidden(content);
break;
default:
System.out.println("nowhere to put [" + nvpItem[0] + "] " + nvpString + " raw: " + rawInputString);
break;
}
}
}
public static String getName() {
return name;
}
public static void setName(String name) { AListItem.name = name; }
public static void setSecond_line(String second_line) {
AListItem.second_line = second_line;
}
public static String getSecond_line() {
return second_line;
}
public static void setHidden(String hidden) {
AListItem.hidden = hidden;
}
public static String getHidden() {
return hidden;
}
public String toString() {
return getName() + ", " +
getSecond_line() + ", " +
getHidden();
}
}
MySimpleCursorAdapter.java:
public class MySimpleCursorAdapter extends SimpleCursorAdapter {
Context context;
Cursor cursor;
public static final String TAG = "MySimpleCursorAdapter";
public MySimpleCursorAdapter(Context context, int layout, Cursor cursor, String[] from, int[] to, int flags) {
super(context, layout, cursor, from, to, flags);
this.context = context;
this.cursor = cursor;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
Log.v(TAG,"getView() >>>>>>STARTING");
ViewHolder viewHolder;
LayoutInflater inflater = LayoutInflater.from(context);
if (null == convertView || null == convertView.getTag()) {
convertView = inflater.inflate(R.layout.b_item, null);
viewHolder = new ViewHolder(convertView);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
for (int i = 0; i < cursor.getColumnCount(); i++) {
Log.v(TAG, "getView cursor " + i + ": " + cursor.getString(i));
}
String hidden = cursor.getString(ViewHolder.HIDDEN);
if (hidden == null) hidden = "F";
Log.v(TAG,"Hidden State: " + hidden);
switch (hidden) {
case "F":
viewHolder.showSecondLine(); // DRS 20160827 - Added line suggested by aiwiguna
break;
case "T":
Log.v(TAG,">>>>>Hidden was TRUE<<<<<<<: " + cursor.getString(ViewHolder.NAME));
viewHolder.hideSecondLine();
break;
}
convertView.setTag(viewHolder);
View returnView = super.getView(position, convertView, parent);
Log.v(TAG,"getView() ENDING<<<<<<<<<");
return returnView;
}
}
ViewHolder.java:
class ViewHolder {
public static final String TAG = "ViewHolder";
public static final int DB_ITEM = 0;
public static final int NAME = 1;
public static final int SECOND_LINE = 2;
public static final int HIDDEN = 3;
public static final int[] viewsArray = new int[] {
R.id.bDbItem,
R.id.bName,
R.id.bSecondLine,
R.id.bHidden,
};
public static final TextView[] textViewArray = new TextView[viewsArray.length];
public ViewHolder( final View root ) {
Log.v(TAG, "ViewHolder constructor");
for (int i = 0; i < viewsArray.length; i++) {
textViewArray[i] = (TextView) root.findViewById(viewsArray[i]);
Log.v(TAG, " textViewArray[" + i + "]: " + textViewArray[i]);
}
}
public void hideSecondLine() {
textViewArray[SECOND_LINE].setVisibility(View.INVISIBLE);
}
//DRS 20160827 - Addition recommended by aiwiguna
public void showSecondLine() {
textViewArray[SECOND_LINE].setVisibility(View.VISIBLE);
}
}
In order to get this application working,
the ListView must be replaced by a RecyclerView, plus
the SimpleCursorAdapter implementation needs to be replaced by a RecyclerCursorAdapter implementation.
MyRecyclerCursorAdapter, a new class in the example, extends RecyclerView.Adapter:
//DRS 20160829 - Added class. Replaces MySimpleCursorAdapter
public class MyRecyclerCursorAdapter extends RecyclerView.Adapter{
private Cursor cursor;
private Context context;
private static final String TAG = MyRecyclerCursorAdapter.class.getSimpleName();
public MyRecyclerCursorAdapter(Context context, Cursor cursor) {
this.cursor = cursor;
this.context = context;
}
//DRS 20160829 - Critical method within new class
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
Log.v(TAG, "onCreateViewHolder ");
Context context = parent.getContext();
LayoutInflater inflater = LayoutInflater.from(context);
View itemView = inflater.inflate(R.layout.b_item, parent, false);
ViewHolder viewHolder = new ViewHolder(itemView, cursor);
return viewHolder;
}
//DRS 20160829 - Critical method within new class
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
cursor.moveToPosition(position);
((ViewHolder)holder).bindFields(cursor);
}
#Override
public int getItemCount() {
return cursor.getCount();
}
}
Note that this class carries a Cursor object, which is the link to the SQLite database entries that will be populating the list.
Also, in order to gain access to the Recycler View, a dependency must be added to build.gradle:
// DRS 20160829 - Added recyclerview
dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:24.2.0'
compile 'com.android.support:recyclerview-v7:24.2.0'
}
b_item.xml required no changes.
activity_lv_ca.xml required a RecyclerView in place of the old ListView:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent" android:layout_height="fill_parent"
android:orientation="vertical">
<!-- DRS 20160829 - Commented ListView, Added RecyclerView
<ListView android:id="#+id/listView1" android:layout_width="fill_parent"
android:layout_height="fill_parent" / -->
<android.support.v7.widget.RecyclerView
android:id="#+id/recyclerView1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="vertical" />
</LinearLayout>
The ViewHolder class now extends Recycler.ViewHolder. Beyond the standard ViewHolder implementation, this customized ViewHolder also has a Cursor which is used to set the text for the TextViews that appear on each row of the list. And this is where the visibility is managed (in a method I called bindFields():
public class ViewHolder extends RecyclerView.ViewHolder {
public static final String TAG = "ViewHolder";
private final Cursor cursor;
public TextView bDbItem;
public TextView bName;
public TextView bSecondLine;
public TextView bHidden;
public static final int DB_ITEM = 0;
public static final int NAME = 1;
public static final int SECOND_LINE = 2;
public static final int HIDDEN = 3;
public ViewHolder(View root, Cursor cursor ) {
super(root);
this.cursor = cursor;
Log.v(TAG, "ViewHolder constructor");
bDbItem = (TextView) itemView.findViewById(R.id.bDbItem);
bName = (TextView) itemView.findViewById(R.id.bName);
bSecondLine = (TextView) itemView.findViewById(R.id.bSecondLine);
bHidden = (TextView) itemView.findViewById(R.id.bHidden);
}
public void bindFields(Cursor cursor) {
bDbItem.setText("" + cursor.getInt(DB_ITEM));
bName.setText(cursor.getString(NAME));
bSecondLine.setText(cursor.getString(SECOND_LINE));
String hidden = cursor.getString(HIDDEN);
bHidden.setText(hidden);
if ("F".equals(hidden)) {
bSecondLine.setVisibility(View.VISIBLE);
} else {
bSecondLine.setVisibility(View.INVISIBLE);
}
}
}
AListItem.java required no changes.
DBAdapter.java required no changes.
The working application may be found on github: RecyclerViewSqlite
In your current solution, you need to "unhide" the second line in a recycled view. The easiest way to do this is in your switch statement. FWIW, you could store your "hidden" flag in your SQLite table as an integer value. This will make the comparison easier, and probably slightly faster.
Another possible solution is to have two different layouts one for the normal situation (hidden is false) and one for the "hidden" situation (hidden is true). In MySimpleCursorAdapter.getView(), an if statement decides which layout to inflate. You would still encounter the same problem when views are recycled: checking to make sure the recycled view is the correct type before reusing it.
switch (hidden) {
case "F":
viewHolder.showSecondLine();
break;
case "T":
Log.v(TAG,">>>>>Hidden was TRUE<<<<<<<: " + cursor.getString(ViewHolder.NAME));
viewHolder.hideSecondLine();
break;
}
I have a listview that contains some data which I got from the web. Now I can make changes in the list item and once I make changes to the item, I am storing the updated value in the db. When i login in next time to the app, I am downloading the content from net and showing it in the listview with the changes that I have done last time. So my approach here is, I am querying the db for each item in the getview method of the list adapter to check for changes. Is it a good practice to do a db query for each item's getview method of the adapter? If not could you please suggest me some alternative. Thanks.
Never, really, never do that.
If you put your data download code in the getView method of the adapter it will make a network call for each row of the list.
Even worst, it will call it anytime that row appears on the screen, not only one time for row.
You should get all your data first, then use the adapter only to draw it.
You can at anytime call the db to check for changes and, if needed, notify the adapter to redraw the list to show the changes.
Hope this helps.
In Android development, any time you want to show a vertical list of items you will want to use a ListView which is populated using an Adapter to a data source. When we want the data for the list to be sourced directly from a SQLite database query we can use a CursorAdapter.
The CursorAdapter fits in between a Cursor (data source from SQLite query) and the ListView (visual representation) and configures two aspects:
Which layout template to inflate for an item
Which fields of the cursor to bind to views in the template
Creating the View Template
When we want to display a series of items into a list using a custom representation of the items, we need to use our own custom XML layout template for each item. We can simply create an XML layout template in res/layout/item_todo.xml representing a particular cursor row:
<?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="match_parent"
android:orientation="horizontal" >
<TextView
android:id="#+id/tvBody"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Study cursors"
android:textAppearance="?android:attr/textAppearanceLarge" />
<TextView
android:id="#+id/tvPriority"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:text="3"
android:textAppearance="?android:attr/textAppearanceMedium" />
</LinearLayout>
Defining the Adapter
public class ViewAdapter extends BaseAdapter {
LayoutInflater mInflater;
public ViewAdapter() {
mInflater = LayoutInflater.from(context);
}
#Override
public int getCount() {
return favoriteList.size();
}
#Override
public Object getItem(int position) {
return null;
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = mInflater.inflate(R.layout.listitem,null);
}
final TextView nameText = (TextView) convertView.findViewById(R.id.nameText);
nameText.setText("Name : "+favoriteList.get(position).getName());
final TextView ageText = (TextView) convertView.findViewById(R.id.ageText);
ageText.setText("Age : "+favoriteList.get(position).getAge());
final Button edit = (Button) convertView.findViewById(R.id.edit);
edit.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
final Dialog dialog = new Dialog(context);
dialog.setContentView(R.layout.row);
dialog.setTitle("Add Data to Database");
final EditText name = (EditText) dialog.findViewById(R.id.name);
final EditText age = (EditText) dialog.findViewById(R.id.age);
Button Add = (Button) dialog.findViewById(R.id.Add);
Add.setText("Add");
Add.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
if(name.getText().toString() != null && name.getText().toString().length() >0 ){
if(age.getText().toString() != null && age.getText().toString().length() >0 ){
db.updateRow(favoriteList.get(position).getId(), name.getText().toString(), age.getText().toString());
favoriteList = db.getFavList();
listView.setAdapter(new ViewAdapter());
dialog.dismiss();
}else{
Toast.makeText(getApplicationContext(), "Please Enter the Age", Toast.LENGTH_LONG).show();
}
}else{
Toast.makeText(getApplicationContext(), "Please Enter the Name", Toast.LENGTH_LONG).show();
}
}
});
dialog.show();
}
});
final Button delete = (Button) convertView.findViewById(R.id.delete);
delete.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
db.removeFav(favoriteList.get(position).getId());
notifyDataSetChanged();
favoriteList = db.getFavList();
listView.setAdapter(new ViewAdapter());
}
});
return convertView;
}
}
Create database
DatabaseHandler.java
public class DatabaseHandler extends SQLiteOpenHelper {
//Database Version
private static final int DATABASE_VERSION = 1;
//Database Name
private static final String DATABASE_NAME = "Test";
//Table Name
private static final String TABLE_TEST = "TestTable";
//Column Name
private static final String KEY_ID = "id";
private static final String KEY_NAME = "name";
private static final String KEY_AGE = "age";
public DatabaseHandler(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
//Create Table
#Override
public void onCreate(SQLiteDatabase db) {
String CREATE_CONTACTS_TABLE = "CREATE TABLE " + TABLE_TEST + "("
+ KEY_ID + " INTEGER PRIMARY KEY," + KEY_NAME + " TEXT,"
+ KEY_AGE + " TEXT" + ")";
db.execSQL(CREATE_CONTACTS_TABLE);
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("DROP TABLE IF EXISTS " + TABLE_TEST);
onCreate(db);
}
//Insert Value
public void adddata(Context context,String movieId,String songId) {
SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(KEY_NAME, movieId);
values.put(KEY_AGE, songId);
db.insert(TABLE_TEST, null, values);
db.close();
}
//Get Row Count
public int getCount() {
String countQuery = "SELECT * FROM " + TABLE_TEST;
int count = 0;
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor = db.rawQuery(countQuery, null);
if(cursor != null && !cursor.isClosed()){
count = cursor.getCount();
cursor.close();
}
return count;
}
//Delete Query
public void removeFav(int id) {
String countQuery = "DELETE FROM " + TABLE_TEST + " where " + KEY_ID + "= " + id ;
SQLiteDatabase db = this.getReadableDatabase();
db.execSQL(countQuery);
}
//Get FavList
public List<FavoriteList> getFavList(){
String selectQuery = "SELECT * FROM " + TABLE_TEST;
SQLiteDatabase db = this.getWritableDatabase();
Cursor cursor = db.rawQuery(selectQuery, null);
List<FavoriteList> FavList = new ArrayList<FavoriteList>();
if (cursor.moveToFirst()) {
do {
FavoriteList list = new FavoriteList();
list.setId(Integer.parseInt(cursor.getString(0)));
list.setName(cursor.getString(1));
list.setAge(cursor.getString(2));
FavList.add(list);
} while (cursor.moveToNext());
}
return FavList;
}
}
Enojoys.... :)
It is better to use cursor adapter to bind the list view.You can use Loader to get the list updated even if there is a change in the data base.
onLoadFinished (Loader loader, D data) of the Loader call back would be monitor for changes to the data, and report them to you through new calls. You should not monitor the data yourself.
I have MyDBHandler with a getAllDetails method that queries the database using a cursor and returns a list.
What I don't know what to do now is how to output this list in a listview in another fragment. I was told to create two XML layouts and a custom adapter but I don't know how to this exactly!
MyDBHandler class
package com.astuetz.viewpager.extensions.sample;
import android.content.ContentValues;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.Cursor;
import android.content.Context;
import android.content.ContentValues;
import java.util.ArrayList;
import java.util.List;
public class MyDBHandler extends SQLiteOpenHelper {
private static final int DATABASE_VERSION = 1;
private static final String DATABASE_NAME = "detailsDB.db";
public static final String TABLE_DETAILS = "details";
public static final String COLUMN_ID = "_id";
public static final String COLUMN_FIRSTNAME = "firstname";
public static final String COLUMN_SURNAME = "surname";
public static final String COLUMN_PHONE = "phone";
public static final String COLUMN_EMAIL = "email";
public static final String COLUMN_ADDRESS1 = "address1";
public static final String COLUMN_ADDRESS2 = "address2";
public static final String TABLE_KIN_DETAILS = "kindetails";
public static final String COLUMN_KIN_ID = "_id";
public static final String COLUMN_KIN_YOUREMAIL = "youremailkin";
public static final String COLUMN_KIN_FIRSTNAME = "firstnamekin";
public static final String COLUMN_KIN_SURNAME = "surnamekin";
public static final String COLUMN_KIN_PHONE = "phonekin";
public static final String COLUMN_KIN_EMAIL = "emailkin";
public static final String COLUMN_KIN_ADDRESS1 = "address1kin";
public static final String COLUMN_KIN_ADDRESS2 = "address2kin";
// Pass database information along to superclass
public MyDBHandler(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
super(context, DATABASE_NAME, factory, DATABASE_VERSION);
}
#Override
public void onCreate(SQLiteDatabase db) {
String query = " CREATE TABLE " + TABLE_DETAILS + "("
+ COLUMN_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
+ COLUMN_FIRSTNAME + " TEXT, "
+ COLUMN_SURNAME + " TEXT, "
+ COLUMN_PHONE + " TEXT, "
+ COLUMN_EMAIL + " TEXT, "
+ COLUMN_ADDRESS1 + " TEXT, "
+ COLUMN_ADDRESS2 + " TEXT "
+ ");";
String query2 = " CREATE TABLE " + TABLE_KIN_DETAILS + "("
+ COLUMN_KIN_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
+ COLUMN_KIN_YOUREMAIL + " TEXT, "
+ COLUMN_KIN_FIRSTNAME + " TEXT, "
+ COLUMN_KIN_SURNAME + " TEXT, "
+ COLUMN_KIN_PHONE + " TEXT, "
+ COLUMN_KIN_EMAIL + " TEXT, "
+ COLUMN_KIN_ADDRESS1 + " TEXT, "
+ COLUMN_KIN_ADDRESS2 + " TEXT "
+ ");";
db.execSQL(query);
db.execSQL(query2);
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL(" DROP TABLE IF EXISTS " + TABLE_DETAILS);
db.execSQL(" DROP TABLE IF EXISTS " + TABLE_KIN_DETAILS);
onCreate(db);
}
//Add a new row to the database
public void addDetails(Details details) {
ContentValues values = new ContentValues();
values.put(COLUMN_FIRSTNAME, details.getFirstname());
values.put(COLUMN_SURNAME, details.getSurname());
values.put(COLUMN_PHONE, details.getPhone());
values.put(COLUMN_EMAIL, details.getEmail());
values.put(COLUMN_ADDRESS1, details.getAddress1());
values.put(COLUMN_ADDRESS2, details.getAddress2());
SQLiteDatabase db = getWritableDatabase();
db.insert(TABLE_DETAILS, null, values);
db.close();
}
public void addKinDetails(KinDetails kinDetails){
ContentValues values = new ContentValues();
values.put(COLUMN_KIN_YOUREMAIL, kinDetails.getyourEmailkin());
values.put(COLUMN_KIN_FIRSTNAME, kinDetails.getFirstnamekin());
values.put(COLUMN_KIN_SURNAME, kinDetails.getSurnamekin());
values.put(COLUMN_KIN_PHONE, kinDetails.getPhonekin());
values.put(COLUMN_KIN_EMAIL, kinDetails.getEmailkin());
values.put(COLUMN_KIN_ADDRESS1, kinDetails.getAddress1kin());
values.put(COLUMN_KIN_ADDRESS2, kinDetails.getAddress2kin());
SQLiteDatabase db = getWritableDatabase();
db.insert(TABLE_KIN_DETAILS, null, values);
db.close();
}
public List<Details> getAllDetails(){
//create a new list in which we put all persons
List<Details>detailsList = new ArrayList<>();
SQLiteDatabase db = getWritableDatabase();
String query = "SELECT * FROM " + TABLE_DETAILS;
//Cursor points to a location in your results
Cursor c = db.rawQuery(query, null);
//Move to the first row in your results
if (c != null) {
c.moveToFirst();
//Position after the last row means the end of the results
while (!c.isAfterLast()) {
//create new details object
Details details = new Details();
//Here use static declared on top of the class..don't use "" for the table column
details.set_id(c.getColumnIndex(COLUMN_ID));
details.setFirstname(c.getString(c.getColumnIndex(COLUMN_FIRSTNAME)));
details.setSurname(c.getString(c.getColumnIndex(COLUMN_SURNAME)));
details.setPhone(c.getString(c.getColumnIndex(COLUMN_PHONE)));
details.setEmail(c.getString(c.getColumnIndex(COLUMN_EMAIL)));
details.setAddress1(c.getString(c.getColumnIndex(COLUMN_ADDRESS1)));
details.setAddress2(c.getString(c.getColumnIndex(COLUMN_ADDRESS2)));
detailsList.add(details);
c.moveToNext();
}
c.close();
}
db.close();
//return our list of persons
return detailsList;
}
}
You need to first create layout files for your fragment and the listview rows.
For the fragment you can create a new blank fragment as follows :
Note: We are using a blank fragment because its good practise to learn since it gives you more control in complex situations.
In the fragment_details.xml paste the following code : Note change com.companyname to your app package name!
<LinearLayout 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="com.companyname.myapplication.FragmentDetails">
<ListView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/frag_details_listView"
android:layout_weight="1" />
</LinearLayout>
Create a new xml layout file and name it row_details , this will be our custom row for our listview.
And in the file row_details.xml paste the following code :
<?xml version="1.0" encoding="utf-8"?>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text="Large Text"
android:id="#+id/row_details_textview_name"
android:layout_marginTop="10dp"
android:layout_marginLeft="10dp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
android:text="Small Text"
android:id="#+id/row_details_textview_id"
android:layout_marginLeft="10dp" />
</LinearLayout>
What we need now is a custom adapter which will take care of loading the data into our listview.
Create a new Java Class and name it DetailsAdapter, and paste the following code : Note see my comments in the code because it is very important to understand the concept behind the adapters in Android :
public class DetailsAdapter extends ArrayAdapter<Person> {
private Context context;
//Constructor
public DetailsAdapter(Context context, int resource, List<Person> objects) {
super(context, resource, objects);
this.context = context;
}
//The get view is the most crucial part of the adapter, here the listview asks the
//adapter for the row to display
#Override
public View getView(int position, View row, ViewGroup parent) {
//Get an instance of our holder
Holder holder;
//Check if this is the first time we are creating this row for the listview
if (row == null){
//Row was null and thus we need to get components from the row_details.xml
holder = new Holder();
//get the Android's layout inflater service which will read our row_details.xml
LayoutInflater inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
//Fill our row view with the xml layout file
row = inflater.inflate(R.layout.row_details, null);
//Fill our holder with the text view components
holder.textViewName = (TextView)row.findViewById(R.id.row_details_textview_name);
holder.textViewId = (TextView)row.findViewById(R.id.row_details_textview_id);
//This is very imp! attach our holder to the row
row.setTag(holder);
}else{
//row was created before! thus get the holder object from the row tag
holder = (Holder)row.getTag();
}
//At this point we have our row, either created from new or got it from the row tag object
//we can now fill the data
//First get our object from the list which is in the position of the listview
//The position as you can see is passed to the getView method by the listview
Person person = getItem(position);
holder.textViewName.setText(person.getFirstname());
holder.textViewId.setText("ID: " + person.get_id());
//we are done formatting our row..return to listview to show
return row;
}
//A holder will be resposable to hold our components to improve listview performance
//We replicate the components we have in the row_details.xml
private class Holder{
TextView textViewName;
TextView textViewId;
}
}
At this point we are ready to rumble!!
In the FragmentDetails java class we declare a global private List of Details...we get an instance of our listview..we get the data..create a new DetailsAdapter and attach it to the listview..
public class FragmentDetails extends Fragment {
private List<Details>detailsList = new ArrayList<>();
private ListView mListView;
private DetailsAdapter adapter;
public FragmentDetails() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View rootView = inflater.inflate(R.layout.fragment_details, container, false);
//get an instance of our listview
mListView = (ListView)rootView.findViewById(R.id.frag_details_listView);
//Get the data here!!
MyDBHandler dbHandler = new MyDBHandler(getActivity().getApplicationContext());
detailsList = dbHandler.getAllDetails();
//Initiate our adapter
adapter = new DetailsAdapter(getActivity().getApplicationContext(), R.layout.row_details, detailsList);
//set adapter to the listview
if(adapter != null){
mListView.setAdapter(adapter);
}
return rootView;
}
}
NOTE !!
In your MyDbHandler class include another constructor which takes only the context as a parameter like so :
public MyDBHandler(Context context){
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
Your good to go ..run the project
With this procedure you can create any type of listviews in android
Create a fragment that extends ListFragment and implements LoaderManager.LoaderCallbacks<Cursor>. Like below:
public class MyFragment extends ListFragment implements
LoaderManager.LoaderCallbacks<Cursor> {}
Implement the methods onCreateLoader(), onLoadFinished() and onLoaderReset().
In the onActivityCreated() method of your fragment, call getLoaderManager().initLoader() method.
You can remove getAllDetails() method from dbhelper and have it as a query in onCreateLoader() method in the fragment.
For more details, check below links:
https://developer.android.com/training/load-data-background/setup-loader.html
https://developer.android.com/training/load-data-background/handle-results.html
I suggest you use Recycler view, its more efficient.The RecyclerView widget is part of the v7 support library. You need to import the recyclerview library(refer to this link)
Refer to this tutorial for more details and better understanding recyclerview.
To start, within your mainActivity code create recyclerview and a customAdapter as below:
RecyclerView recyclerView = (RecyclerView) view.findViewById(R.id.my_recycler_view);
RecyclerView.LayoutManager mLayoutManager;
dbHelper = new DBHelper(getActivity().getApplicationContext());
list = MyDBHandler.getAllDetails();
mLayoutManager = new LinearLayoutManager(getActivity().getApplicationContext());
recyclerView.setLayoutManager(mLayoutManager);
c = new CustomAdapter(list); //send the list to the adapter
recyclerView.setAdapter(c);
Within your main Layout code you should have this to show the recyclerview:
<android.support.v7.widget.RecyclerView
android:id="#+id/my_recycler_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipToPadding="false"
android:scrollbars="vertical"/>
Now you need to create a custom adapter to show the contents of Details Object. Please note that in the earlier code of the Activity the CustomAdapter is called and passed the list of Details object. We need to use this to show it in the view.
public class CustomAdapter extends RecyclerView.Adapter<CustomAdapter.viewHolder> {
List<Details> records;
public class viewHolder extends RecyclerView.ViewHolder {
public TextView firstname, surname;
public viewHolder(View v) {
super(v);
firstname = (TextView) v.findViewById(R.id.first);
surname = (TextView) v.findViewById(R.id.last);
}
}
public CustomAdapter(List<Details> records) {
this.records = records;
}
#Override
public viewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.listrow, parent, false);
return new viewHolder(v);
}
#Override
public void onBindViewHolder(final viewHolder holder, final int position) {
Details rec = list.get(position);
holder.firstname.setText(rec.getFirstname());
holder.lastname.setText(rec.getSurname);
}
}
Now you need a layout file for the customadapter, create as below:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#android:color/white"
android:orientation="vertical">
<TextView
android:id="#+id/first"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="16dp"
android:textColor="#CC000000"
android:textSize="16sp"
android:text=""/>
<TextView
android:id="#+id/last"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="16dp"
android:textColor="#CC000000"
android:textSize="16sp"
android:text=""/>
</LinearLayout>
I am a beginner and I am studying the android at University.
Currently, I am using DBAdapter at the moment, and I am trying to show the data on layout from database by using ListView(if there are better way instead, advice me).
When I run application at the moment, makeText function will be called, and it will be shown data information.
Instead of showing the notification, I want to show some of values on ListView such as name, and quantity.
How can I get it? which ListView do I have to use it with database?
I want to know the handling database with ListView.
Please advice.
Code attached below:
FridgeDbAdapter.java
public class FridgeDbAdapter
{
public static final String KEY_ROWID = "_id";
public static final String KEY_CATEGORY = "category";
public static final String KEY_NAME = "name";
public static final String KEY_EXPIRED_DATE = "expired_date";
private static final String DATABASE_TABLE = "fridge_table";
private Context ctxt;
private SQLiteDatabase db;
private FridgeDatabaseHelper dbhelper;
public FridgeDbAdapter(Context ctxt)
{
this.ctxt = ctxt;
}
//DB databaseHelper
public class FridgeDatabaseHelper extends SQLiteOpenHelper
{
private static final String DATABASE_NAME = "fridge_db";
private static final int DATABASE_VERSION = 1;
private static final String DATBASE_CREATE =
"create table fridge_table (_id integer primary key autoincrement, "
+ "category text not null, name text not null, expired_date text not null);";
public FridgeDatabaseHelper(Context ctxt)
{
super(ctxt, DATABASE_NAME, null, DATABASE_VERSION);
}
#Override
public void onCreate(SQLiteDatabase db)
{
db.execSQL(DATBASE_CREATE);
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVer, int newVer)
{
Log.w(FridgeDatabaseHelper.class.getName(),
"Upgrading database from version " + oldVer + " to "
+ newVer + ", which will delete the old data.");
db.execSQL("DROP TABLE IF EXISTS fridge_table");
//Method is called during creation of new database
onCreate(db);
}
}
//Open database
public FridgeDbAdapter open() throws SQLException
{
dbhelper = new FridgeDatabaseHelper(ctxt);
db = dbhelper.getWritableDatabase();
return this;
}
//Close database
public void close(){
dbhelper.close();
}
//Create a new item
public long insertItem(String category, String name, String expired_date)
{
ContentValues initialValues = new ContentValues();
initialValues.put(KEY_CATEGORY, category);
initialValues.put(KEY_NAME, name);
initialValues.put(KEY_EXPIRED_DATE, expired_date);
return db.insert(DATABASE_TABLE, null, initialValues);
}
//update a item
public boolean updateItem(long rowId, String category,
String name, String expired_date)
{
ContentValues updateValues = new ContentValues();
updateValues.put(KEY_CATEGORY, category);
updateValues.put(KEY_NAME, name);
updateValues.put(KEY_EXPIRED_DATE, expired_date);
return db.update(DATABASE_TABLE, updateValues, KEY_ROWID + "=" + rowId,
null) > 0;
}
//delete a item
public boolean deleteItem(long rowId){
return db.delete(DATABASE_TABLE, KEY_ROWID + "=" + rowId, null) > 0;
}
//return cursor over the list of all items in the database
public Cursor fetchAllItems(){
return db.query(DATABASE_TABLE, new String[]{KEY_ROWID, KEY_CATEGORY,
KEY_NAME, KEY_EXPIRED_DATE},
null, null, null, null, null);
}
//return a cursor positioned at the defined item
public Cursor fetchItem(long rowId) throws SQLException{
Cursor mCursor = db.query(true, DATABASE_TABLE,
new String[]{KEY_ROWID, KEY_CATEGORY, KEY_NAME,
KEY_EXPIRED_DATE}, KEY_ROWID + "=" + rowId, null, null, null, null, null);
if(mCursor != null){
mCursor.moveToFirst();
}
return mCursor;
}
}
Fridge.java
public class Fridge extends Activity{
//Button goBack;
Button button1;
TextView text;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.fridge);
FridgeDbAdapter db = new FridgeDbAdapter(this);
//Open database
db.open();
//Get all items
Cursor c = db.fetchAllItems();
if(c.moveToFirst())
{
do
{
//Call displayItem method in below
DisplayItem(c);
} while (c.moveToNext());
}
else
{
Toast.makeText(this, "No item found", Toast.LENGTH_SHORT).show();
}
db.close();
}
public void DisplayItem(Cursor c){
Toast.makeText(this, "id: " + c.getString(0) + "\n" +
"category: " + c.getString(1) + "\n" +
"name: " + c.getString(2) + "\n" +
"expired date: " + c.getString(3),
Toast.LENGTH_SHORT).show();
}
}
fridge.xml
<?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="match_parent"
android:orientation="vertical" >
<TextView
android:id="#+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Fridger page" />
<LinearLayout
android:id="#+id/fridge_List_View"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
</LinearLayout>
<Button
android:id="#+id/add_Btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Add item" />
</LinearLayout>
Formula you might wanna consider using it's the Loader API, it's great because it help you handle your cursor and query efficiently.
Loaders make it easy to asynchronously load data in an activity or
fragment.
They are available to every Activity and Fragment.
They provide asynchronous loading of data.
They monitor the source of their data and deliver new results when the content changes.
They automatically reconnect to the last loader's cursor when being recreated after a configuration change. Thus, they don't need to
re-query their data.
Implements LoaderCallbacks in your ListView or ListFragment, then override the methods onCreateLoader, onFinishedLoader, onRestartLoader. Initialize your loader with the LoaderManager, getLoaderManager().initLoader, and enjoy.
The only disadvantage that I've seen it's that is usefull if you have a ContentProvider, but even if you don't you can try some solutions in SO, like Loader without ContentProvider, In general i've learned that ContentProvider makes your life so much easier with the cursors, granted!.
public class ShowNotificationAdapter extends SimpleCursorAdapter{
Cursor dataCursor;
LayoutInflater mInflater;
Context context;
int layoutType;
DatabaseHelper db_helper;
public CustomAdapter(Context context, int layout, Cursor dataCursor, String[] from,
int[] to) {
super(context, layout, dataCursor, from, to);
this.context=context;
this.dataCursor = dataCursor;
mInflater = LayoutInflater.from(context);
db_helper=new DatabaseHelper(context);
db_helper.open();
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
final ViewHolder holder;
if(convertView==null)
{
convertView = mInflater.inflate(R.layout.custom_listitem, null);
holder = new ViewHolder();
holder.name=(TextView)convertView.findViewById(R.id.name);
holder.quantity=(TextView)convertView.findViewById(R.id.quantity);
holder.otherInfo=(TextView)convertView.findViewById(R.id.otherInfo);
}
else
{
holder=(ViewHolder)convertView.getTag();
}
dataCursor.moveToPosition(position);
String nameString=Integer.toString(dataCursor.getString(dataCursor.getColumnIndexOrThrow("name")));//column name of "name"
holder.name.setText(nameString);
String quantityString=dataCursor.getString(dataCursor.getColumnIndexOrThrow("quantity")); //column name of "quantity"
holder.quantity.setText(quantityString);
String otherInfoString=dataCursor.getString(dataCursor.getColumnIndexOrThrow("field_name"));
holder.otherInfo.setText(quantityString);
return convertView;
}
static class ViewHolder
{
TextView name;
TextView quantity;
TextView otherInfo;
}
#Override
public Object getItem(int position) {
return position;
}
}
You want to use a ListActivity.
And you will need to create a cursor and query the data in the fillData method.
Here's a decent tutorial on how to do that:
http://www.vogella.de/articles/AndroidSQLite/article.html
Use ListView and SimpleCursor adapter.
Example code can be found at:
http://thinkandroid.wordpress.com/2010/01/09/simplecursoradapters-and-listviews/
http://www.vogella.de/articles/AndroidListView/article.html
You can use a custom_adapter using SimpleCursorAdapter,for getting your database info. displayed onto the listview.
CustomAdpater.class:
public class CustomAdpater extends SimpleCursorAdapter{
Cursor dataCursor;
LayoutInflater mInflater;
Context context;
int layoutType;
DatabaseHelper db_helper;
public CustomAdapter(Context context, int layout, Cursor dataCursor, String[] from,
int[] to) {
super(context, layout, dataCursor, from, to);
this.context=context;
this.dataCursor = dataCursor;
mInflater = LayoutInflater.from(context);
db_helper=new DatabaseHelper(context);
db_helper.open();
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
final ViewHolder holder;
if(convertView==null)
{
convertView = mInflater.inflate(R.layout.custom_listitem, null);
holder = new ViewHolder();
holder.name=(TextView)convertView.findViewById(R.id.name);
holder.quantity=(TextView)convertView.findViewById(R.id.quantity);
holder.otherInfo=(TextView)convertView.findViewById(R.id.otherInfo);
}
else
{
holder=(ViewHolder)convertView.getTag();
}
dataCursor.moveToPosition(position);
String nameString=Integer.toString(dataCursor.getString(dataCursor.getColumnIndexOrThrow("name")));//column name of "name"
holder.name.setText(nameString);
String quantityString=dataCursor.getString(dataCursor.getColumnIndexOrThrow("quantity")); //column name of "quantity"
holder.quantity.setText(quantityString);
String otherInfoString=dataCursor.getString(dataCursor.getColumnIndexOrThrow("field_name"));
holder.otherInfo.setText(quantityString);
return convertView;
}
static class ViewHolder
{
TextView name;
TextView quantity;
TextView otherInfo;
}
#Override
public Object getItem(int position) {
return position;
}
}
custom_listitem.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent" android:layout_height="fill_parent"
android:orientation="vertical">
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="5dp"
android:id="#+id/name"
/>
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="5dp"
android:id="#+id/quantity"
/>
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="5dp"
android:id="#+id/otherInfo"
/>
</LinearLayout>
MainActivity.class:
...
ListView listview=(ListView)findViewById(R.id.listview);
Cursor cursor=<get data to be passed to custom adapter>;
String[] from={"name","quantity"};//field names of 'name' and 'quantity'
int[] to={R.id.name,R.id.quantity};
CustomAdapter ca=new CustomAdapter(context,R.layout.custom_listitem,cursor,from,to);
listview.setAdapter(ca);
ca.notifyDataSetChanged();
...