我在将从SQLite数据库表中检索到的dataTime输出解析为Date格式时遇到了一些问题。
对于背景:我正在尝试使用AChartEngine将此表中的得分和日期时间显示在图表中。
主要问题是我一直收到有关数据集和渲染器错误的错误。 of series / null。我很确定这是因为日期没有被添加到系列中,因为解析时出错。我需要帮助试图找出问题,因为从在线阅读和查看有关Sqlite使用的模式的帖子我有正确的但我得到这个错误:
java.text.ParseException: Unparseable date: "5 Aug 2015 18:48" (at offset 1)
但是我的调试显示我从查询中转换的字符串是:
08-05 21:14:20.628 13955-13955/com.example.jamesliasides.myapplication D/dateTime db string:﹕ 2015-08-05 17:48:23
我在我的代码中用来解析字符串的模式是:
String pattern = "yyyy-MM-dd HH:mm:ss";
非常感谢任何帮助!
我的DatabaseHelper类:
public class DatabaseHelper extends SQLiteOpenHelper {
//SCORES Columns
public static final String SCORE_COLUMN_ID = "_ID";
public static final String SCORE_COLUMN_USER_ID = "user_ID";
public static final String SCORE_COLUMN_ACTIVITY_ID = "activity_ID";
public static final String SCORE_COLUMN_SCORE = "score";
public static final String SCORE_COLUMN_TIMESTAMP = "created_at";
//SCORES create command
private static final String CREATE_TABLE_SCORES = "CREATE TABLE "
+ SCORES_TABLE_NAME + "(" + SCORE_COLUMN_ID + " INTEGER PRIMARY KEY AUTOINCREMENT," + SCORE_COLUMN_ACTIVITY_ID
+ " INTEGER," + SCORE_COLUMN_USER_ID + " INTEGER," + SCORE_COLUMN_SCORE + " INTEGER,"
+ SCORE_COLUMN_TIMESTAMP + " DATETIME default current_timestamp" + ")";
public DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
this.context = context;
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(CREATE_TABLE_ACTIVITIES);
db.execSQL(CREATE_TABLE_USERS);
db.execSQL(CREATE_TABLE_SCORES);
Activity a1 = new Activity(1, "deadlift", "Standard dealift exercise is...");//do not include ID as the table autoincrements ids for
Activity a2 = new Activity(2, "squat", "Standard squat exercise is...");
ContentValues r1 = new ContentValues();
r1.put(ACTIVITIES_COLUMN_NAME, a1.getName());
r1.put(ACTIVITIES_COLUMN_DESCRIPTION, a1.getDescription());
r1.put(ACTIVITIES_COLUMN_ID, a1.getId());
// insert row
long activity_id1 = db.insert(ACTIVITIES_TABLE_NAME, null, r1);
Log.d("Insert Act DeadLift:", String.valueOf(activity_id1));
ContentValues r2 = new ContentValues();
r2.put(ACTIVITIES_COLUMN_NAME, a2.getName());
r2.put(ACTIVITIES_COLUMN_DESCRIPTION, a2.getDescription());
r2.put(ACTIVITIES_COLUMN_ID, a2.getId());
// insert row
long activity_id2 = db.insert(ACTIVITIES_TABLE_NAME, null, r2);
Log.d("Insert Act Squat:", String.valueOf(activity_id2));
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// on upgrade drop older tables
db.execSQL("DROP TABLE IF EXISTS " + SCORES_TABLE_NAME);
db.execSQL("DROP TABLE IF EXISTS " + ACTIVITIES_TABLE_NAME);
db.execSQL("DROP TABLE IF EXISTS " + USERS_TABLE_NAME);
onCreate(db);
}
/**
* Inserts a user into its relation,reuturns -1 if fail, or the row id if successful.
*
* @param user
* @return
*/
public long insertUser(User user) {
SQLiteDatabase db = this.getWritableDatabase();
Log.v("EditText", user.getName());
Log.v("EditText", user.getEmail());
Log.v("EditText", user.getPassword());
ContentValues values = new ContentValues();
values.put(USERS_COLUMN_NAME, user.getName());
values.put(USERS_COLUMN_EMAIL, user.getEmail());
values.put(USERS_COLUMN_PASSWORD, user.getPassword());
values.put(USERS_COLUMN_AGE, user.getAge());
values.put(USERS_COLUMN_WEIGHT, user.getWeight());
values.put(USERS_COLUMN_HEIGHT, user.getHeight());
//insert row
long user_id = db.insert(USERS_TABLE_NAME, null, values);
return user_id;
}
/**
* Insert a score into the scores table. Note the user ID is not input as the autoincrement
* feature of the table will automatically apply one to it.
* @param score
* @return
*/
public long insertScore(Scores score){
SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues();
// values.put(SCORE_COLUMN_ID, score.getId());
values.put(SCORE_COLUMN_SCORE, score.getScore());
//values.put(SCORE_COLUMN_TIMESTAMP, score.getTimestamp()); DONT WANT to insert anything into this as its automated!
values.put(SCORE_COLUMN_ACTIVITY_ID, score.getActivityID());
values.put(SCORE_COLUMN_USER_ID, score.getUserID());
//insert row
long score_id = db.insert(SCORES_TABLE_NAME, null, values);
return score_id;
}
/**
* return a single entity from table by specifying its unique email address
*
* @param email
* @return user
*/
public User getUser(String email, String password) {
SQLiteDatabase db = this.getReadableDatabase();
// String selectQuery = "SELECT * FROM " + USERS_TABLE_NAME + " WHERE " + USERS_COLUMN_EMAIL_ID + " = " + "?" + " AND " + USERS_COLUMN_PASSWORD + " = " + "?" ;
// Log.e(LOG, selectQuery);
//Cursor c = db.rawQuery(selectQuery, new String[]{email, password});
String whereClause = "email =? AND password =?";
String[] whereArgs = new String[]{email, password};
Cursor c = db.query(USERS_TABLE_NAME, null, whereClause, whereArgs, null, null, null);
User u = new User();
if (c != null) {
Log.i("cursor count: ", Integer.toString(c.getCount()));
if (c.moveToFirst()) {
Log.i("password parameter: ", password);
do {
u.setName(c.getString(c.getColumnIndex(USERS_COLUMN_NAME)));
u.setEmail(c.getString(c.getColumnIndex(USERS_COLUMN_EMAIL)));
u.setPassword(c.getString(c.getColumnIndex(USERS_COLUMN_PASSWORD)));
u.setAge(c.getInt(c.getColumnIndex(USERS_COLUMN_AGE)));
u.setWeight(c.getInt(c.getColumnIndex(USERS_COLUMN_WEIGHT)));
u.setHeight(c.getInt(c.getColumnIndex(USERS_COLUMN_HEIGHT)));
u.setId(c.getLong(c.getColumnIndex(USERS_COLUMN_ID)));
Log.d("user", u.toString());
} while (c.moveToNext());
}
c.close();
}
return u;
}
public XYMultipleSeriesDataset getTableScores(long userID, long activityID) throws ParseException {
SQLiteDatabase db = this.getReadableDatabase();//error
//SQLite query to get all Scores where ID and activity correspond to input params.
String selectQuery = "SELECT " + SCORE_COLUMN_SCORE + ", " + SCORE_COLUMN_TIMESTAMP + ", " + SCORE_COLUMN_ID + " FROM " + SCORES_TABLE_NAME +
" WHERE " + SCORE_COLUMN_USER_ID + " = '" + userID + "'" + " AND " + SCORE_COLUMN_ACTIVITY_ID
+ " = '" + activityID + "'"; //String.valueOf(userID)
Log.e(LOG, selectQuery);
Cursor c = db.rawQuery(selectQuery, null);
//dataset to add series to.
XYMultipleSeriesDataset dataset = new XYMultipleSeriesDataset();
//TimeSeries series = new TimeSeries("Line1");
TimeSeries series2 = new TimeSeries("activity score");
Log.d("cursor count", String.valueOf(c.getCount()));
//mCurrentSeries.clear();
if (c.moveToFirst()) {
do {
double value;
int valueColumn = c.getColumnIndex("score");
value = c.getDouble(valueColumn);
// String time;
// int timeColumn = c.getColumnIndex("created_at");
// time = String.valueOf(c.getDouble(timeColumn));
String pattern = "yyyy-MM-dd HH:mm:ss";
String dateTime = c.getString(c.getColumnIndexOrThrow(SCORE_COLUMN_TIMESTAMP));
Log.d("dateTime db string:", dateTime);
DateFormat iso8601Format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date = null;
try {
date = iso8601Format.parse(dateTime);
} catch (ParseException e) {
Log.e(LOG_TAG, "Parsing ISO8601 datetime failed", e);
}
long when = date.getTime();
int flags = 0;
flags |= android.text.format.DateUtils.FORMAT_SHOW_TIME;
flags |= android.text.format.DateUtils.FORMAT_SHOW_DATE;
flags |= android.text.format.DateUtils.FORMAT_ABBREV_MONTH;
flags |= android.text.format.DateUtils.FORMAT_SHOW_YEAR;
String finalDateTime = android.text.format.DateUtils.formatDateTime(context,
when + TimeZone.getDefault().getOffset(when), flags);
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(pattern);
//make the date object again from the string value of the DateTime record in the DB.
date = simpleDateFormat.parse(finalDateTime);
// series2.add(date, value);
series2.add(date, value);
Log.i("values of time/score:", value + " + " + date);
} while (c.moveToNext());
}
c.close();
// dataset.addSeries(series);
dataset.addSeries(series2);
return dataset;
}
public Cursor getUserScore(long userID, long activityID){
String selectQuery = "SELECT * FROM " + SCORES_TABLE_NAME + " WHERE " + SCORE_COLUMN_USER_ID
+ " = " + userID + " AND " + SCORE_COLUMN_ACTIVITY_ID + " = " + activityID
+ " ORDER BY " + SCORE_COLUMN_TIMESTAMP + " ASC";
Log.e(LOG, selectQuery);
SQLiteDatabase db = this.getReadableDatabase();
Cursor c = db.rawQuery(selectQuery, null);
return c;
}
这是我的viewGraphFragment类,其中使用viewGraph()方法调用Database方法:
public class viewGraphFragment extends Fragment {
private DatabaseHelper mDbHelper;
private Spinner spinnerActivity;
private LinearLayout chart_layout;
private long userID;
public static viewGraphFragment newInstance(int someInt) {
viewGraphFragment myFragment = new viewGraphFragment();
Bundle args = new Bundle();
args.putInt("someInt", someInt);
myFragment.setArguments(args);
return myFragment;
}
//set up the onClick listeners for the viewGraph button. Find user ID (sharedPrefs) and activity ID (choice from the spinner). Use these in a DB query. Put results in the AchartEngine XYseries.
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_view_graph, container, false);
mDbHelper = new DatabaseHelper(getActivity());
Button backbutton = (Button) view.findViewById(R.id.btnBackToHome);
backbutton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent;
intent = new Intent(getActivity(), HomeActivity.class);
startActivity(intent);
}
});
Button button = (Button) view.findViewById(R.id.btnViewGraph);
button.setOnClickListener(new View.OnClickListener() {
/**
* method called on click of the viewGraph button.
* This button will call a DB method take the choice in the spinner as the Activity and the
* User ID to get all relevent Scores to display in a Graph.
*/
@Override
public void onClick(View v) {
//choose which activity scores to use.
//get them from the database.
//find out how to store them in a graph and a table.
//display it nicely.
String activityType = spinnerActivity.getSelectedItem().toString();
//turn activityType to Activity ID.
//long activityID = mDbHelper.findActivityID(activityType);
long activityID = getActivityId(activityType);
//getDemoDataset should return a dataset to be used for the Graph.
XYMultipleSeriesDataset dataset = null;
try {
dataset = mDbHelper.getTableScores(userID, activityID);//error activity type should be activityID not name
//if dataset is null we need an exception to handle this!!
} catch (ParseException e) {
e.printStackTrace();
}
//is the query actually returning anything from the DB or is it not displaying it properly.
// Now we create the renderer
XYSeriesRenderer renderer = new XYSeriesRenderer();
renderer.setLineWidth(2);
renderer.setColor(Color.RED);
// Include low and max value
renderer.setDisplayBoundingPoints(true);
// we add point markers
renderer.setPointStyle(PointStyle.CIRCLE);
renderer.setPointStrokeWidth(3);
renderer.setDisplayChartValues(true);
renderer.setFillPoints(true);
XYMultipleSeriesRenderer mRenderer = new XYMultipleSeriesRenderer();
mRenderer.setChartTitle("Activity Scores: " + activityType);
mRenderer.setXTitle("Time Days/Hours");
mRenderer.setYTitle("Score in KG");
// We want to avoid black border
mRenderer.setMarginsColor(Color.argb(0x00, 0xff, 0x00, 0x00)); // transparent margins
// Disable Pan on two axis
mRenderer.setPanEnabled(false, false);
mRenderer.setYAxisMax(200);
mRenderer.setYAxisMin(0);
mRenderer.setShowGrid(true); // we show the grid
mRenderer.addSeriesRenderer(renderer);
chart_layout = (LinearLayout) getActivity().findViewById(R.id.chart_layout);
//needs a context a dataset and a renderer.
GraphicalView chartView = ChartFactory.getLineChartView(getActivity(), dataset, mRenderer);//match sets in renderer and series!
chart_layout.addView(chartView);
}
});
return view;
}
//set up the spinners once activity is created.
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
SharedPreferences sharedpreferences = this.getActivity().getSharedPreferences(MainActivity.MyPREFERENCES, Context.MODE_PRIVATE);
userID = sharedpreferences.getLong(MainActivity.UserId, 0);
//set up spinner
spinnerActivity = (Spinner) this.getActivity().findViewById(R.id.spinnerActivity);
ArrayAdapter<CharSequence> staticAdapter = ArrayAdapter
.createFromResource(getActivity(), R.array.activity_type_array,
android.R.layout.simple_spinner_item);
staticAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinnerActivity.setAdapter(staticAdapter);
}
public static long getActivityId(String activity){
long id;
switch (activity) {
case "deadlift":
id = 1;
break;
case "squat":
id = 2;
break;
case "bench press":
id = 3;
break;
case "shoulder press":
id = 4;
break;
case "bicep curl":
id = 5;
break;
case "skullcrusher":
id = 6;
break;
case "chin up":
id = 7;
break;
case "pull up":
id = 8;
break;
default:
id = -1;
break;
}
return id;
}
}
Heres很长一段时间我的完整Logcat:
08-05 21:14:20.628 13955-13955/com.example.jamesliasides.myapplication E/DatabaseHelper﹕ SELECT score, created_at, _ID FROM scores WHERE user_ID = '1' AND activity_ID = '1'
08-05 21:14:20.628 13955-13955/com.example.jamesliasides.myapplication D/cursor count﹕ 2
08-05 21:14:20.628 13955-13955/com.example.jamesliasides.myapplication D/dateTime db string:﹕ 2015-08-05 17:48:23
08-05 21:14:20.638 13955-13955/com.example.jamesliasides.myapplication W/System.err﹕ java.text.ParseException: Unparseable date: "5 Aug 2015 18:48" (at offset 1)
08-05 21:14:20.638 13955-13955/com.example.jamesliasides.myapplication W/System.err﹕ at java.text.DateFormat.parse(DateFormat.java:571)
08-05 21:14:20.638 13955-13955/com.example.jamesliasides.myapplication W/System.err﹕ at com.example.jamesliasides.myapplication.DatabaseHelper.getTableScores(DatabaseHelper.java:607)
08-05 21:14:20.638 13955-13955/com.example.jamesliasides.myapplication W/System.err﹕ at com.example.jamesliasides.myapplication.viewGraphFragment$2.onClick(viewGraphFragment.java:80)
08-05 21:14:20.638 13955-13955/com.example.jamesliasides.myapplication W/System.err﹕ at android.view.View.performClick(View.java:4785)
08-05 21:14:20.638 13955-13955/com.example.jamesliasides.myapplication W/System.err﹕ at android.view.View$PerformClick.run(View.java:19858)
08-05 21:14:20.638 13955-13955/com.example.jamesliasides.myapplication W/System.err﹕ at android.os.Handler.handleCallback(Handler.java:739)
08-05 21:14:20.638 13955-13955/com.example.jamesliasides.myapplication W/System.err﹕ at android.os.Handler.dispatchMessage(Handler.java:95)
08-05 21:14:20.638 13955-13955/com.example.jamesliasides.myapplication W/System.err﹕ at android.os.Looper.loop(Looper.java:155)
08-05 21:14:20.638 13955-13955/com.example.jamesliasides.myapplication W/System.err﹕ at android.app.ActivityThread.main(ActivityThread.java:5696)
08-05 21:14:20.638 13955-13955/com.example.jamesliasides.myapplication W/System.err﹕ at java.lang.reflect.Method.invoke(Native Method)
08-05 21:14:20.638 13955-13955/com.example.jamesliasides.myapplication W/System.err﹕ at java.lang.reflect.Method.invoke(Method.java:372)
08-05 21:14:20.638 13955-13955/com.example.jamesliasides.myapplication W/System.err﹕ at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1028)
08-05 21:14:20.638 13955-13955/com.example.jamesliasides.myapplication W/System.err﹕ at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:823)
08-05 21:14:20.648 13955-13955/com.example.jamesliasides.myapplication E/AndroidRuntime﹕ FATAL EXCEPTION: main
Process: com.example.jamesliasides.myapplication, PID: 13955
java.lang.IllegalArgumentException: Dataset and renderer should be not null and should have the same number of series
at org.achartengine.ChartFactory.checkParameters(ChartFactory.java:660)
at org.achartengine.ChartFactory.getLineChartView(ChartFactory.java:68)
at com.example.jamesliasides.myapplication.viewGraphFragment$2.onClick(viewGraphFragment.java:118)
at android.view.View.performClick(View.java:4785)
at android.view.View$PerformClick.run(View.java:19858)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:155)
at android.app.ActivityThread.main(ActivityThread.java:5696)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1028)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:823)
答案 0 :(得分:0)
问题似乎在这里:
String finalDateTime = android.text.format.DateUtils.formatDateTime(context,
when + TimeZone.getDefault().getOffset(when), flags);
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(pattern);
//make the date object again from the string value of the DateTime record in the DB.
date = simpleDateFormat.parse(finalDateTime);
而不是try-catch中数据库的结果。
您正在使用ormat模式:
String pattern = "yyyy-MM-dd HH:mm:ss";
但是你的finalDateTime
字符串是根据这个标志从formatDateTime构建的:
int flags = 0;
flags |= android.text.format.DateUtils.FORMAT_SHOW_TIME;
flags |= android.text.format.DateUtils.FORMAT_SHOW_DATE;
flags |= android.text.format.DateUtils.FORMAT_ABBREV_MONTH;
flags |= android.text.format.DateUtils.FORMAT_SHOW_YEAR;
显然会产生字符串"5 Aug 2015 18:48"