Datetime Does Not Show Up
Solution 1:
Ok, since you uploaded your project I think I got it working the way you want. It is working nonetheless.
There were several errors - mostly with logic. I tried to comment as much as I could so you can understand what/why I was doing everything.
One thing I did not comment was that the AndroidManifest
needed permission:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
You can download the project here, or just look at the snippets:
MainActivity
I added a ListView
so you can see all the primes. Also changed how/where we get the data from the DB, and how we save to DB.
publicclassMainActivityextendsActionBarActivity {
privatestaticfinalStringTAG= MainActivity.class.getSimpleName();
privateintmax=500;
private TextView primeText;
privateint previousPrimeNumber;
private List<Prime> primes;
private PrimeAdapter adapter;
private MyDBHandler dbManager;
@OverrideprotectedvoidonCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
primeText = (TextView) findViewById(R.id.primeText);
//get the object from previous session. Remember these are sorted by date
dbManager = newMyDBHandler(this);
primes = dbManager.getPrimeObjects();
//get the first prime. (AKA the last one added)if (primes.size() != 0) {
previousPrimeNumber = primes.get(0).get_primeno(); //get the first item
primeText.setText(String.valueOf(previousPrimeNumber));
} else {
previousPrimeNumber = 2;
}
//create list view and adapter to display the dataListViewlistView= (ListView) findViewById(R.id.listView);
adapter = newPrimeAdapter(this, primes);
listView.setAdapter(adapter);
findViewById(R.id.primeButton).setOnClickListener(newView.OnClickListener() {
@OverridepublicvoidonClick(View v) {
intprimeNumber= -1;
//increment previousPrimeNumber by one so we wont keep using previousPrimeNumberfor (inti= previousPrimeNumber + 1; i <= max; i++) {
if (isPrimeNumber(i)) {
primeNumber = i;
primeText.setText(String.valueOf(i));
previousPrimeNumber = i + 1;
break;
}
}
if (primeNumber != -1) {
Primeprime=newPrime(primeNumber);
dbManager.addPrime(prime);
/* Yes, it saved to our database. But there is no reason for us to read from
* it too when we have the prime object right here. So just add it to the
* adapter and be done *///The adapter is looking at the list primes. So add it to the top and notify
primes.add(0, prime);
adapter.notifyDataSetChanged();
} else {
Log.e(TAG, "Oops, there was an error. Invalid prime number");
}
}
});
}
publicbooleanisPrimeNumber(int number) {
for (inti=2; i <= number / 2; i++) {
if (number % i == 0) {
returnfalse;
}
}
returntrue;
}
/**
* If this is too confusing you can ignore it for now.
* However, I recommend understanding the android UIs before diving in to database storage.
* Take a look at this link:
* http://www.vogella.com/tutorials/AndroidListView/article.html
*/privateclassPrimeAdapterextendsArrayAdapter<Prime> {
publicPrimeAdapter(Context context, List<Prime> primes) {
// I am just using androids views. (android.R.id...)super(context, android.R.layout.simple_list_item_2, primes);
}
@Overridepublic View getView(int position, View view, ViewGroup parent) {
/* This method will automagically get called for every item in the list.
* This is an ARRAY adapter. So it has a list of the data we passed in on
* the constructor. So by calling "this" we are accessing it like it were a list
* which it really is. */finalPrimeprime=this.getItem(position);
if (view == null) {
view = LayoutInflater.from(MainActivity.this)
.inflate(android.R.layout.simple_list_item_2, null);
}
/* if you look at simple_list_item_2, you will see two textViews. text1 and text2.
* Normally you would create this view yourself, but like i said, that is not the
* reason I am here */// Notice I am referencing android.R.id. and not R.id. That is cause I am lazy and// didn't create my own views.TextViewtv1= (TextView) view.findViewById(android.R.id.text1);
TextViewtv2= (TextView) view.findViewById(android.R.id.text2);
tv1.setText(String.valueOf(prime.get_primeno()));
tv2.setText(prime.getDateTimeFormatted());
//now return the view so the listView knows to show itreturn view;
}
}
MyDBHandler:
Changed the queries and added two methods that will convert Prime
to a ContentValues
object and from Cursor
to a prime.
publicclassMyDBHandlerextendsSQLiteOpenHelper {
privatestaticfinalintDATABASE_VERSION=1;
privatestaticfinalStringDATABASE_NAME="prime.db";
publicstaticfinalStringTABLE_PRIME="prime";
publicstaticfinalStringCOLUMN_ID="_id";
publicstaticfinalStringCOLUMN_PRIMENO="primeno";
publicstaticfinalStringCOLUMN_DATETIME="datetime";
publicMyDBHandler(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
@OverridepublicvoidonCreate(SQLiteDatabase db) {
Stringquery="CREATE TABLE " + TABLE_PRIME + "(" +
/* This must be in same order everywhere! */
COLUMN_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " + // ID will be index 0
COLUMN_PRIMENO + " INTEGER, " + // Prime will be index 1
COLUMN_DATETIME + " LONG);"; // Date will be index 2
db.execSQL(query);
/* Something else to note: I changed the column types. You had text for these,
* which is fine. But the object that you are storing in each of these is not
* a string. So for consistency store the object as its original class type:
* PrimeNo == integer
* Datetime == long (milliseconds)
* This also makes it so sorting is much easier */
}
@OverridepublicvoidonUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("DROP TABLE IF EXISTS " + TABLE_PRIME);
onCreate(db);
}
/**
* You want to save the entire Prime object at once. Not bits and pieces.
*
* @param prime
*/publicvoidaddPrime(Prime prime) {
ContentValuesvalues= writePrime(prime);
SQLiteDatabasedb= getWritableDatabase();
db.insert(TABLE_PRIME, null, values);
/* DON'T FORGET TO CLOSE YOUR DATABASE! */
db.close();
}
/**
* Again, you want to receive the entire prime object at once. Not bits.
*
* @return List of previous prime objects
*/public List<Prime> getPrimeObjects() {
final List<Prime> primes = newArrayList<Prime>();
finalSQLiteDatabasedb= getWritableDatabase();
/* Normally i would use this line of code:
final Cursor c = db.rawQuery("SELECT * FROM " + TABLE_PRIME, null);
but, you want to be sure you will get them order by DATE so you know
the first prime in the list is the last added. so I switched the query to this:
*/finalCursorc= db.query(TABLE_PRIME,
newString[]{COLUMN_ID, COLUMN_PRIMENO, COLUMN_DATETIME},
null, null, null, null, //much null. So wow.
COLUMN_DATETIME + " DESC"); //order in descending./* After queried the first item will be our starting point */
c.moveToFirst();
while (c.moveToNext()) {
Primep= buildPrime(c);
//check not nullif (p != null)
primes.add(p); //add to list
}
/* DON'T FORGET TO CLOSE YOUR DATABASE AND CURSOR! */
c.close();
db.close();
return primes;
}
/**
* Convert the Cursor object back in to a prime number
*
* @param cursor Cursor
* @return Prime
*/private Prime buildPrime(Cursor cursor) {
finalPrimeprime=newPrime();
prime.set_id(cursor.getInt(0)); // id index as stated above
prime.set_primeno(cursor.getInt(1)); // prime index as stated above
prime.setDateTime(cursor.getLong(2)); // date index as stated abovereturn prime;
}
/**
* Convert the prime object in to ContentValues to write to DB
*
* @param prime prime
* @return ContentValues
*/private ContentValues writePrime(Prime prime) {
ContentValuesvalues=newContentValues();
values.put(COLUMN_PRIMENO, prime.get_primeno()); //must insert first
values.put(COLUMN_DATETIME, prime.getDateTime()); //must insert secondreturn values;
}
}
Prime:
I just changed the value types. Prime
's purpose is to store a prime integer. So why not make that field a integer?
publicclassPrime {
privatestatic final String format = "yyyy-MM-dd HH:mm:ss";
privatestatic final SimpleDateFormat formatter = new SimpleDateFormat(format, Locale.ENGLISH);
privateint _id;
privateint _primeno;
privatelong dateTime = 0; //this is in milliseconds. Makes it easier to managepublicPrime() { }
publicPrime(int primeNumber) {
//create a new prime object with a prime already known. set the date while we are at itthis._primeno = primeNumber;
this.dateTime = System.currentTimeMillis();
}
publicvoidset_id(int _id) {
this._id = _id;
}
publicvoidset_primeno(int _primeno) {
this._primeno = _primeno;
}
publicintget_id() {
return _id;
}
publicintget_primeno() {
return _primeno;
}
publiclonggetDateTime() {
return dateTime;
}
public String getDateTimeFormatted() {
if (dateTime == 0) {
dateTime = System.currentTimeMillis();
}
Date date = new Date(dateTime);
return formatter.format(date);
}
publicvoidsetDateTime(long dateTime) {
this.dateTime = dateTime;
}
}
Solution 2:
This seems to work.
In your values create db.xml
<?xml version="1.0" encoding="utf-8"?><resources><stringname="prime_table_name">prime</string><stringname="prime_table_column_id">_id</string><stringname="prime_table_column_prime_no">prime_no</string><stringname="prime_table_column_datetime">date_time</string><string-arrayname="prime_table_all_columns"><item>@string/prime_table_column_id</item><item>@string/prime_table_column_prime_no</item><item>@string/prime_table_column_datetime</item></string-array><stringname="createTableOfPrimes">CREATE TABLE prime ( _id INTEGER PRIMARY KEY AUTOINCREMENT, prime_no TEXT, date_time DATETIME DEFAULT CURRENT_TIMESTAMP );</string><stringname="dropTableOfPrimes">DROP TABLE IF EXISTS prime</string><stringname="insertIntoTableOfPrimes">INSERT INTO prime (prime_no, date_time) VALUES(?,?)</string></resources>
Prime class
package si.kseneman.utilities;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Locale;
publicclassPrime {
privatestaticfinalStringformat="yyyy-MM-dd HH:mm:ss";
privatestaticfinalSimpleDateFormatformatter=newSimpleDateFormat(format, Locale.ENGLISH);
privateint id;
private String primeNo;
private Calendar dateTime;
publicPrime(String primeNo) {
this.id = -1;
this.primeNo = primeNo;
this.dateTime = Calendar.getInstance();
}
publicintgetId() {
return id;
}
publicvoidsetId(int id) {
this.id = id;
}
public String getPrimeNo() {
return primeNo;
}
publicvoidsetPrimeNo(String primeNo) {
this.primeNo = primeNo;
}
public String getDateTime() {
return formatter.format(dateTime.getTime());
}
publicvoidsetDateTime(Calendar calendar) {
this.dateTime = (Calendar) calendar.clone();
}
publicvoidsetDateTime(String dateTimeString) {
try {
dateTime.setTime(formatter.parse(dateTimeString));
} catch (ParseException e) {
dateTime.setTimeInMillis(0);
}
}
publicvoidsetDateTimeToNow() {
this.dateTime = Calendar.getInstance();
}
}
Prie SQL Lite Helper
package si.kseneman.utilities;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;
import java.lang.ref.WeakReference;
import si.kseneman.mobile.R;
publicclassPrimeDBSQLLiteHelperextendsSQLiteOpenHelper {
publicstaticfinalintDATABASE_VERSION=1;
publicstaticfinalStringDATABASE_NAME="Prime.db";
privatestaticfinalStringTAG= PrimeDBSQLLiteHelper.class.getSimpleName();
private WeakReference<Context> mContext;
publicPrimeDBSQLLiteHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
mContext = newWeakReference<Context>(context);
}
@OverridepublicvoidonCreate(SQLiteDatabase sqLiteDatabase) {
sqLiteDatabase.execSQL(getString(R.string.createTableOfPrimes));
Log.i(TAG, "DataBase created");
}
@OverridepublicvoidonUpgrade(SQLiteDatabase sqLiteDatabase, int oldVersion, int newVersion) {
sqLiteDatabase.execSQL(getString(R.string.dropTableOfPrimes));
this.onCreate(sqLiteDatabase);
}
private String getString(int resID) {
return mContext.get() != null ? mContext.get().getString(resID) : null;
}
}
Prime SingleTon database
package si.kseneman.utilities;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteStatement;
import android.os.Environment;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import android.database.sqlite.SQLiteDatabase;
import android.util.Log;
import si.kseneman.mobile.R;
publicclassPrimeDataSource {
privatestaticfinalStringTAG= PrimeDataSource.class.getSimpleName();
privatestaticbyte numberOfInstances;
private SQLiteDatabase database;
private PrimeDBSQLLiteHelper primeDBSQLLiteHelper;
privatestatic PrimeDataSource instance;
privatestaticfinalObjectLOCK=newObject();
private Context context;
protectedPrimeDataSource(Context context) {
this.context = context.getApplicationContext();
}
publicstaticsynchronized PrimeDataSource getInstance(Context context) {
if (instance == null) {
instance = newPrimeDataSource(context);
}
numberOfInstances++;
return instance;
}
publicstaticsynchronizedvoiddecrementNumberOfInstances() {
if (--numberOfInstances <= 0) {
instance.close();
}
numberOfInstances = numberOfInstances < 0 ? 0 : numberOfInstances; //Sanity?
}
publicstaticsynchronizedvoidforceClose() {
numberOfInstances = 0;
instance.close();
}
privatevoidclose() {
if (isDatabaseOpenOpen()) {
primeDBSQLLiteHelper.close();
}
primeDBSQLLiteHelper = null;
instance = null;
database = null;
}
publicsynchronizedvoidopen() {
if (database == null || !database.isOpen()) {
primeDBSQLLiteHelper = newPrimeDBSQLLiteHelper(context);
database = primeDBSQLLiteHelper.getWritableDatabase();
}
}
publicbooleanisDatabaseOpenOpen() {
return database != null && database.isOpen();
}
publicsynchronizedvoiddeleteAllPrimesFromDb() {
try {
database.delete(getString(R.string.prime_table_name), null, null);
} catch (Exception e) {
// Was it really created?
createTableOfPrimes();
}
}
publicsynchronizedvoidcreateTableOfPrimes() {
database.execSQL(getString(R.string.createTableOfPrimes));
}
publicsynchronizedvoiddropTableOfJobs() {
database.execSQL(getString(R.string.dropTableOfPrimes));
}
publicsynchronizedvoiddropDataBase() {
database.execSQL("DROP DATABASE IF EXISTS " + PrimeDBSQLLiteHelper.DATABASE_NAME);
}
public String getDatabasePath() {
return (Environment.getDataDirectory() + File.separator + PrimeDBSQLLiteHelper.DATABASE_NAME);
}
publicsynchronizedvoidinsertListOfPrimes(List<Prime> data) {
synchronized (LOCK) {
database.beginTransaction();
SQLiteStatementstmt= database.compileStatement(getString(R.string.insertIntoTableOfPrimes));
for (Prime p : data) {
stmt.bindString(1, p.getPrimeNo());
stmt.bindString(2, p.getDateTime());
stmt.executeInsert();
stmt.clearBindings();
}
database.setTransactionSuccessful();
database.endTransaction();
Log.i(TAG, "Insertion success");
}
}
private Prime cursorToPrime(Cursor cursor) {
// ID = 0 ; primeNo = 1; dateTime = 2;Primep=newPrime(cursor.getString(1));
p.setId(cursor.getInt(0));
p.setDateTime(cursor.getString(2));
return p;
}
public List<Prime> getListOfPrimes() {
synchronized (LOCK) {
List<Prime> listOfPrimes = newArrayList<Prime>();
Cursorcursor= database.query(getString(R.string.prime_table_name), getStringArray(R.array.prime_table_all_columns), null, null, null, null, null);
cursor.moveToFirst();
while (!cursor.isAfterLast()) {
listOfPrimes.add(cursorToPrime(cursor));
cursor.moveToNext();
}
return listOfPrimes;
}
}
publicvoidinsertPrime(Prime prime) {
synchronized (LOCK) {
database.beginTransaction();
SQLiteStatementstmt= database.compileStatement(getString(R.string.insertIntoTableOfPrimes));
stmt.bindString(1, prime.getPrimeNo());
stmt.bindString(2, prime.getDateTime());
stmt.executeInsert();
stmt.clearBindings();
database.setTransactionSuccessful();
database.endTransaction();
}
}
privateintgetCountFromCursor(Cursor cursor) {
intresult= cursor.moveToFirst() ? cursor.getCount() : 0;
cursor.close();
return result;
}
publicintgetPrimeCount() {
synchronized (LOCK) {
Cursorcursor= database.query(getString(R.string.prime_table_name), newString[]{getString(R.string.prime_table_column_id)}, null, null, null, null, null);
return getCountFromCursor(cursor);
}
}
private String getString(int resID) {
return context.getString(resID);
}
private String[] getStringArray(int resID) {
return context.getResources().getStringArray(resID);
}
private String[] getStringArrayFromResources(int... integers) {
String[] result = newString[integers.length];
for (inti=0; i < integers.length; ++i) {
result[i] = getString(integers[i]);
}
return result;
}
}
In Activity
private PrimeDataSource dataSource;
@Override
protectedvoidonCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
dataSource = PrimeDataSource.getInstance(getApplicationContext());
dataSource.open();
List<Prime> demoListOfPrimes = new ArrayList<Prime>(5);
demoListOfPrimes.add(new Prime("1"));
demoListOfPrimes.add(new Prime("3"));
demoListOfPrimes.add(new Prime("5"));
demoListOfPrimes.add(new Prime("7"));
demoListOfPrimes.add(new Prime("11"));
dataSource.insertListOfPrimes(demoListOfPrimes);
demoListOfPrimes = dataSource.getListOfPrimes();
if(demoListOfPrimes.size() == 0){
Log.i("", "Empty list");
}
for (Prime p : demoListOfPrimes) {
Log.i("Prime: ", p.getPrimeNo() + " ; " + p.getDateTime());
}
}
@Override
protectedvoidonDestroy() {
super.onDestroy();
dataSource = null;
PrimeDataSource.decrementNumberOfInstances();
}
LogCat output:
04-0722:45:18.5901005-1005/si.kseneman.mobileI/PrimeDataSource﹕Insertionsuccess04-0722:45:18.5901005-1005/si.kseneman.mobileI/Prime:﹕1;2015-04-07 22:45:1804-0722:45:18.5901005-1005/si.kseneman.mobileI/Prime:﹕3;2015-04-07 22:45:1804-0722:45:18.5901005-1005/si.kseneman.mobileI/Prime:﹕5;2015-04-07 22:45:1804-0722:45:18.5901005-1005/si.kseneman.mobileI/Prime:﹕7;2015-04-07 22:45:1804-0722:45:18.5901005-1005/si.kseneman.mobileI/Prime:﹕11;2015-04-07 22:45:18
P.S. you may need to uninstall your app or drop your table for this to work
Here is a zip of a simple project that displays the numbers in a listview activity: LINK
Post a Comment for "Datetime Does Not Show Up"