i am new to programming so take it easy on me. So i am reading HOUR only from SQLlite and i am checking if a current hour is the same or not as the last saved hour. My problem is when i call this method and there is no data yet in the Sqlite the app ofcourse crashes. Any idea how to solve this. So when the user launches the app for the first time the app does not crash?
public void CHECK(){
sqliteDbHelper_ = new Sqlite_DBHelper(getActivity());
sqLiteDatabase = sqliteDbHelper_.getWritableDatabase();
String[] columns = {"hour_only","JAKOST"};
cursor = sqLiteDatabase.query("podatki", columns,null,null,null,null,null);
Calendar calander = Calendar.getInstance();
Integer currentHour = calander.get(Calendar.HOUR_OF_DAY);
buttonSaveOnMainPage.setClickable(true);
cursor.moveToLast();
Integer lastInputedHour = cursor.getInt(0);
Log.e(TAG+"zadnja vnesena URA",""+lastInputedHour);
Log.e(TAG+"trenutna URA",""+currentHour);
if (lastInputedHour == currentHour){
buttonSaveOnMainPage.setBackgroundColor(Color.RED);
buttonSaveOnMainPage.setClickable(false);
}
else
buttonSaveOnMainPage.setBackgroundColor(Color.GREEN);
buttonSaveOnMainPage.setClickable(true);
}
You could get the count of the cursor and default to the current hour.
Something like
if (cursor.getCount() < 1) {
// Set default value
} else {
// use value from cursor
}
Here's a link to the documentation
https://developer.android.com/reference/android/database/Cursor.html#getCount%28%29
Why don't you call your method into Try/Catch block? Check this:
try {
CHECK();
} catch (Exception e) {
e.printStackTrace();
}
I hope it will help!
Related
I created a database with a table named flagTable, this table only has two fields, which are id(auto increment) and an integer field. Next, in my program, I have a button that will trigger a thread to start. When the thread is starting, it constantly retrieve data from database, and check for the for the value, if the value is equal to one then it will trigger another new Thread, something like this:
private class statusOfStrummingInAnotherDevice extends Thread {
int value;
public void run() {
try{
while(true){
try{
if(flagCursor == null){
flagCursor = cdb1.getFlagAll();
}
}catch(Exception e){break;}
try{
Log.i("MAIN3ACTIVITY","getting status");
int size = cdb1.getSize(flagCursor);
Log.i("MAIN3ACTIVITY","SIZE is" + String.valueOf(xyz));
for(int i = 0 ; i < size ; i++){
flagCursor.moveToPosition(i);
Log.i("MAIN3ACTIVITY","getting status jkasdfasdf");
value = cdb1.getFlag();
if(value == 1){
Log.i("FLAGCURSOR=====>>>>","Succesful");
releasingNotes = new ReleasingNotes(IntendedChord);
releasingNotes.start();
//break;
}
cdb1.updateFlag(0);
Log.i("FLAGCURSOR=====>>>>",String.valueOf(value));
}
flagCursor = null;
}catch(Exception e){break;}
Log.i("MAIN3ACTIVITY","thread is sleeping");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
break;
}
}
}catch(Exception e){
}
}
}
In the meantime, the data that were retrieved from the database is using this function:
public Cursor getFlagAll(){
return getReadableDatabase().rawQuery(
"SELECT _ID, flag from flagTable", null);
}
And, the data that were updated to the database through this method:
public int updateFlag(int i) {
SQLiteDatabase db = this.getWritableDatabase();
ContentValues contentValues = new ContentValues();
contentValues.put("flag",i);
return db.update("flagTable" , contentValues , "_ID" + "= ?",new String[]{String.valueOf(1)});
}
Now, above codes will give no error, however, the data that were retrieved from the database is always 1, it keeps trigger a new function. In my above codes, I stated if the value is equal to 1, then the current thread will trigger a new thread to start, When its finished, the program will update the current data to 0. So that, the next round of the infinite loop can stop triggering new thread until a the conditon is met. What is problem overhere? did my codes really updated the new value? or I need to referesh the database every time I updated a new value.
Use Listeners to your database.
use SQLiteTransactionListener and do your things in onCommit()
Some guide in details here :
https://developer.android.com/reference/android/database/sqlite/SQLiteTransactionListener.html and
http://www.programcreek.com/java-api-examples/index.php?api=android.database.sqlite.SQLiteTransactionListener
Android Studio keeps complaining ( lightbulb red X ) that 'db' and 'dbh' may not be instantiated in the finally block.
So three things:
If the insert fails, what is the state of dbh and db in the catch block, or the finally block?
More generally, what do I need to account for in the finally and catch blocks
Is lowering the complaint level in Android Studio the proper way to handle this :) ?
Below is the code. Its an Android AsyncTask.
#Override
protected Void doInBackground(Void... voids) {
SweepDatabaseHelper dbh;
SQLiteDatabase db;
try{
Random generator = new Random();
float freqstep = (stopFreq - startFreq)/steps;
dbh = new SweepDatabaseHelper(context);
db = dbh.getWritableDatabase();
// empty the table
db.delete(dbh.TABLE_SWEEPDATA, null, null);
// start writing the data
for(int i=0;i<steps;i++){
ContentValues values = new ContentValues();
SweepData sdata=new SweepData( (long)i, startFreq+(i*freqstep), (float)generator.nextFloat()*10 );
values.put(dbh.COLUMN_ID, (long)i);
values.put(dbh.COLUMN_FREQ, startFreq+(i*freqstep));
values.put(dbh.COLUMN_VSWR, sdata.getVswr());
db.insert(dbh.TABLE_SWEEPDATA, null, values);
publishProgress(new SweepData[]{sdata});
}
dbh.close();
return null;
}catch(Exception e){
// Do nothing at the moment
return null;
}finally{
if(db != null && dbh != null && db.isOpen()){
db.close();
}
}
}
You need to either assign them an initial value at declaration time if they are defined in the method, or define them as instance variables.
The accepted answer to this question has a good explanation.
Basically, instance variables will always have a default value, but that is not the case for local variables, that is why you are seeing the error.
You have two options to choose from to fix this.
The first option is to just initialize them to null:
SweepDatabaseHelper dbh = null;
SQLiteDatabase db = null;
I would recommend the second option of defining them as instance variables in your AsyncTask, and initialize in a constructor:
SweepDatabaseHelper dbh; //make instance variable
SQLiteDatabase db; //make instance variable
//constructor
public MyAsyncTask(Context context){
dbh = new SweepDatabaseHelper(context);
db = dbh.getWritableDatabase();
}
#Override
protected Void doInBackground(Void... voids) {
//SweepDatabaseHelper dbh; //remove
//SQLiteDatabase db; //remove
try{
Random generator = new Random();
float freqstep = (stopFreq - startFreq)/steps;
//dbh = new SweepDatabaseHelper(context); //remove
//db = dbh.getWritableDatabase(); //remove
// empty the table
db.delete(dbh.TABLE_SWEEPDATA, null, null);
// start writing the data
for(int i=0;i<steps;i++){
ContentValues values = new ContentValues();
SweepData sdata=new SweepData( (long)i, startFreq+(i*freqstep), (float)generator.nextFloat()*10 );
values.put(dbh.COLUMN_ID, (long)i);
values.put(dbh.COLUMN_FREQ, startFreq+(i*freqstep));
values.put(dbh.COLUMN_VSWR, sdata.getVswr());
db.insert(dbh.TABLE_SWEEPDATA, null, values);
publishProgress(new SweepData[]{sdata});
}
dbh.close();
return null;
}catch(Exception e){
// Do nothing at the moment
return null;
}finally{
if(db != null && dbh != null && db.isOpen()){
db.close();
}
}
}
You should be able to get Android Studio to stop complaining about this by simply initializing dbh and db to "null" when you define them.
SweepDatabaseHelper dbh = null;
SQLiteDatabase db = null;
try{
...
}catch{
dbh = new SweepDatabaseHelper(context);
db = dbh.getWritableDatabase();
}finally{
...
}
The reason is given in the Java specification:
4.12.5 Initial Values of Variables
...
A local variable (§14.4, §14.14) must be explicitly given a value
before it is used, by either initialization (§14.4) or assignment
(§15.26), in a way that can be verified using the rules for definite
assignment (§16).
http://docs.oracle.com/javase/specs/jls/se7/jls7.pdf
So, for your three questions:
If the insert fails, what is the state of dbh and db in the catch
block, or the finally block?
In your posted code, I would guess it won't compile.
More generally, what do I need to account for in the finally and catch blocks
You will want to put dbh.close() in your finally block so it always runs. Otherwise you may open the database, an exception occurs, and you end up leaving it opened.
You should use the catch block to take any action you'd want to do to if the operation fails, e.g., attempt error recovery, alert the user that there's a problem or ask them to make a decision, send an error report somewhere, etc.
Is lowering the complaint level in Android Studio the proper way to handle this :) ?
In some cases where you know exactly what you're doing, you know why it's complaining, and you know it's going to work, yes. In this case? No.
I have read several posts here on speed issues when looping through a cursor and tried the answers given in these posts such as e.g. do not use getcolumnindex in the loop call this once etc.
However with a database having around 2400 records it takes around 3 to 5 minutes to finish.
The loop is running in an async task method so that it does not hang up the device and the database is handled via a database adapter.
The loop code is as follows :
while (!exportrec.isAfterLast()) {
if ( exportrec.moveToNext() ) {
fulldate = exportnumberformatter(exportrec.getInt(daye))
+"/"+exportnumberformatter(exportrec.getInt(monthe))+"/"
+String.valueOf(exportrec.getInt(yeare));
fulltime = exportnumberformatter(exportrec.getInt(houre))+":"
+exportnumberformatter(exportrec.getInt(mine))+":"
+exportnumberformatter(exportrec.getInt(sece));
noiseid = exportrec.getInt(typee);
exportedinfo += exporttypes[id] +","+exportrec.getString(notee)+","+
fulldate+","+fulltime+" \n" ;
}
}
The exportnumberformatter does the following :
public String exportnumberformatter(int i) {
String result = Integer.toString(i);
if (result.length() >1 ) {
return Integer.toString(i);
}
String zeroprefix = "";
zeroprefix = "0"+result;
return zeroprefix ;
}
The cursor is called as follows before the loop to get the data :
exportrec = MD.GetAllLogs(2, "date_sort");
exportrec.moveToFirst();
The MD is the database adapter and the GetAllLogs Method (this has been played with to try and speed things up and so the date_sort that is used is really ignored here):
public Cursor GetAllLogs(Integer i,String sortfield)
{
String sorted = "";
if (i == 1 ) {
sorted = "DESC";
} else if (i == 2) {
sorted = "ASC";
}
return mDB.query(DB_TABLE, new String[] {COL_ID, COL_TYPE,COL_IMAGE, COL_INFO,COL_IMAGE,COL_HOUR,COL_SEC,COL_MIN,COL_DAY,COL_MON,COL_YEAR,COL_SORT_DATE},
null, null, null, null, COL_ID+" "+sorted);
}
When I created the table in the database it had no indexes so I created these via the upgrade method. However they did not error or appear to fail when I did this but what I do not know is A) does the database/table need rebuilding after an index is created and B) how to tell if they have been created ? the two indexes were based on the ID as the first and a field that holds the year month day hour minute second all in on Long Integer.
I am concerned that the loop appears to be taking this long to read through that many records.
Update:
rtsai2000's and the suggestion from CL answer has improved the speed from minutes to seconds
Your exportedInfo String is growing and growing. Save the results in an array and Stringify later (such as with StringBuilder).
You are not closing your cursor after reading the records.
List<String> exportedInfo = new ArrayList<String>();
Cursor exportrec = GetAllLogs();
try {
while (exportrec.moveToNext()) {
String info = String.format("%s, %s, %02d/%02d/%02d, %02d:%02d:%02d",
exporttypes[id],
exportrec.getString(notee),
exportrec.getInt(daye),
exportrec.getInt(monthe),
exportrec.getInt(yeare),
exportrec.getInt(houre),
exportrec.getInt(mine),
exportrec.getInt(sece));
exportedInfo.add(info);
}
} finally {
exportrec.close();
}
return exportedInfo;
I have a list of events in my app. A button on the side lets the user add the event date and time to his/her calender. I use a calender intent to redirect the user to the android calender which the corresponding date and time. Now after the user adds the event to his calender, I would like to disable the 'add event' button which corresponds to the events he/she had already added(so the user avoid adding the same event again). How can I do this? I have gone through the new calender API for android 4.0 but I wasnt able to achieve what I wanted.
Basically what I want is to avoid repeated entries for the same event in the users calender.
Any help would be appreciated.
You should test, if an instance for this event exists. See the documentation of the Android's CalendarContract.Instances class.
Especially the second query method should be helpful in this case.
This examples is some code, I posted on my blog post about the CalendarContract provider - slightly altered for your needs:
long begin = // starting time in milliseconds
long end = // ending time in milliseconds
String[] proj =
new String[]{
Instances._ID,
Instances.BEGIN,
Instances.END,
Instances.EVENT_ID};
Cursor cursor =
Instances.query(getContentResolver(), proj, begin, end, "\"Your event title\"");
if (cursor.getCount() > 0) {
// deal with conflict
}
Be aware: The time is always in UTC millis since the epoch. So you might have to adjust given the user's timezone.
And the last parameter should contain the title of the event you have added to the calendar. Keep the quotes - otherwise Android looks for "your" or "event" or "title"!
And do not forget to include the necessary permissions.
Instances.query is not recommended to be run on the UI thread, but can be done efficiently by ensuring start and end time duration is minimized.
The search string will search all values, not just title, so adding a loop to check for that an exact field value is necessary.
public boolean eventExistsOnCalendar(String eventTitle, long startTimeMs, long endTimeMs) {
if (eventTitle == null || "".equals(eventTitle)) {
return false;
}
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_CALENDAR) != PackageManager.PERMISSION_GRANTED) {
return false;
}
// If no end time, use start + 1 hour or = 1 day. Query is slow if searching a huge time range
if (endTimeMs <= 0) {
endTimeMs = startTimeMs + 1000 * 60 * 60; // + 1 hour
}
final ContentResolver resolver = mContext.getContentResolver();
final String[] duplicateProjection = {CalendarContract.Events.TITLE}; // Can change to whatever unique param you are searching for
Cursor cursor =
CalendarContract.Instances.query(
resolver,
duplicateProjection,
startTimeMs,
endTimeMs,
'"' + eventTitle + '"');
if (cursor == null) {
return false;
}
if (cursor.getCount() == 0) {
cursor.close();
return false;
}
while (cursor.moveToNext()) {
String title = cursor.getString(0);
if (eventTitle.equals(title)) {
cursor.close();
return true;
}
}
cursor.close();
return false;
}
I have used following way to check it ...what i am passing event_id to check whether is it in calendar or not....
public boolean isEventInCal(Context context, String cal_meeting_id) {
Cursor cursor = context.getContentResolver().query(
Uri.parse("content://com.android.calendar/events"),
new String[] { "_id" }, " _id = ? ",
new String[] { cal_meeting_id }, null);
if (cursor.moveToFirst()) {
//Yes Event Exist...
return true;
}
return false;
}
Please check this, this might help:
private static boolean isEventInCalendar(Context context, String titleText, long dtStart, long dtEnd) {
final String[] projection = new String[]{CalendarContract.Instances.BEGIN, CalendarContract.Instances.END, CalendarContract.Instances.TITLE};
Cursor cursor = CalendarContract.Instances.query(context.getContentResolver(), projection, dtStart, dtEnd);
return cursor != null && cursor.moveToFirst() && cursor.getString(cursor.getColumnIndex(CalendarContract.Instances.TITLE)).equalsIgnoreCase(titleText);
}
I have written a simple code for Database updatation, but it is sometime updating and sometimes not... i have written LOG for conformation but the log is giving correct output. Here is what i am trying :=
public void updateDownloadedAssetNumberOfStartingBytesEncrypted(int id, int startingBytesEncrypted)
{
SQLiteDatabase database = null;
int numOfRowsUpdated = 0;
try
{
database = getWritableDatabase();
ContentValues values = new ContentValues();
values.put("StartingBytesEncrypted", startingBytesEncrypted);
if(database.isOpen())
{
Log.v("updating in db","doc id - "+id + " encrypted bytes - "+startingBytesEncrypted);
numOfRowsUpdated = database.update("_assets", values, "Id = "+id, null);
}
else
{
Log.v("Database","the database is not open thus starting encrypted bytes were not updated");
}
Log.v("muber of rows updated - ",""+numOfRowsUpdated);
}
catch(Exception ex)
{
}
finally
{
if(database != null)
{
database.close();
}
}
}
What is the problem?? Any help would be Appreciable.
Ya i got ur code...
Finally i resolved the issue.... actually it is beacuse of threading....
the thread creating the row was executed later and that updating the row was executed first
i have resolved it.Have fun :)
This happened due to connection of database is not open. Pls keep ex.printstacktrace(); in catch statement.