I’ve got problem updating my appwidget. It’s simple widget which use service to update widget and get quote from db (sqlite) and show it on homescreen.
On log I see that quotes were inserted to db. And they are returned by method
List<Quote> contacts = quoteSeeker.getAllQuotes();
Then showing up in log:
Log.w(LOG, "From Intent" + String.valueOf(allWidgetIds.length));
Log.w(LOG, "Direct" + String.valueOf(allWidgetIds2.length));
And after that warrnings and errors comes. What can be the issue?
Here come the log from LOGCAT:
08-15 10:56:18.295: I/service jarek(3061): Called
08-15 10:56:18.335: I/JARO TEST(3061): Called
08-15 10:56:18.335: D/Insert:(3061): Inserting ..
08-15 10:56:19.280: D/Reading:(3061): Reading all contacts..
08-15 10:56:19.335: D/Name:(3061): Id: 1 ,Name: Ravi ,Phone: 9100000000
08-15 10:56:19.335: D/Name:(3061): Id: 2 ,Name: Srinivas ,Phone: 9199999999
08-15 10:56:19.335: D/Name:(3061): Id: 3 ,Name: Tommy ,Phone: 9522222222
08-15 10:56:19.340: D/Name:(3061): Id: 4 ,Name: Karthik ,Phone: 9533333333
08-15 10:56:19.340: D/Name:(3061): Id: 5 ,Name: Darek ,Phone: DAREKDAREK
08-15 10:56:19.340: D/Name:(3061): Id: 6 ,Name: Ravi ,Phone: 9100000000
08-15 10:56:19.340: D/Name:(3061): Id: 7 ,Name: Srinivas ,Phone: 9199999999
08-15 10:56:19.345: D/Name:(3061): Id: 8 ,Name: Tommy ,Phone: 9522222222
08-15 10:56:19.345: D/Name:(3061): Id: 9 ,Name: Karthik ,Phone: 9533333333
08-15 10:56:19.345: D/Name:(3061): Id: 10 ,Name: Darek ,Phone: DAREKDAREK
08-15 10:56:19.345: D/Name:(3061): Id: 11 ,Name: Ravi ,Phone: 9100000000
08-15 10:56:19.350: D/Name:(3061): Id: 12 ,Name: Srinivas ,Phone: 9199999999
08-15 10:56:19.355: D/Name:(3061): Id: 13 ,Name: Tommy ,Phone: 9522222222
08-15 10:56:19.355: D/Name:(3061): Id: 14 ,Name: Karthik ,Phone: 9533333333
08-15 10:56:19.355: D/Name:(3061): Id: 15 ,Name: Darek ,Phone: DAREKDAREK
08-15 10:56:19.360: D/Name:(3061): Id: 16 ,Name: Ravi ,Phone: 9100000000
08-15 10:56:19.365: D/Name:(3061): Id: 17 ,Name: Srinivas ,Phone: 9199999999
08-15 10:56:19.365: D/Name:(3061): Id: 18 ,Name: Tommy ,Phone: 9522222222
08-15 10:56:19.365: D/Name:(3061): Id: 19 ,Name: Karthik ,Phone: 9533333333
08-15 10:56:19.370: D/Name:(3061): Id: 20 ,Name: Darek ,Phone: DAREKDAREK
08-15 10:56:19.375: W/JARO TEST(3061): From Intent1
08-15 10:56:19.380: W/JARO TEST(3061): Direct1
08-15 10:56:19.545: D/AndroidRuntime(3061): Shutting down VM
08-15 10:56:19.545: W/dalvikvm(3061): threadid=1: thread exiting with uncaught exception (group=0x4001d7f0)
08-15 10:56:19.580: E/AndroidRuntime(3061): FATAL EXCEPTION: main
08-15 10:56:19.580: E/AndroidRuntime(3061): java.lang.RuntimeException: Unable to start service beautiful.quotes.UpdateWidgetService@4643d410 with Intent { cmp=beautiful.quotes/.UpdateWidgetService (has extras) }: java.lang.IllegalStateException: attempt to re-open an already-closed object: android.database.sqlite.SQLiteQuery (mSql = SELECT * FROM quotes)
08-15 10:56:19.580: E/AndroidRuntime(3061): at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:3070)
08-15 10:56:19.580: E/AndroidRuntime(3061): at android.app.ActivityThread.access$3600(ActivityThread.java:125)
08-15 10:56:19.580: E/AndroidRuntime(3061): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2096)
08-15 10:56:19.580: E/AndroidRuntime(3061): at android.os.Handler.dispatchMessage(Handler.java:99)
08-15 10:56:19.580: E/AndroidRuntime(3061): at android.os.Looper.loop(Looper.java:123)
08-15 10:56:19.580: E/AndroidRuntime(3061): at android.app.ActivityThread.main(ActivityThread.java:4641)
08-15 10:56:19.580: E/AndroidRuntime(3061): at java.lang.reflect.Method.invokeNative(Native Method)
08-15 10:56:19.580: E/AndroidRuntime(3061): at java.lang.reflect.Method.invoke(Method.java:521)
08-15 10:56:19.580: E/AndroidRuntime(3061): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:880)
08-15 10:56:19.580: E/AndroidRuntime(3061): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:638)
08-15 10:56:19.580: E/AndroidRuntime(3061): at dalvik.system.NativeStart.main(Native Method)
08-15 10:56:19.580: E/AndroidRuntime(3061): Caused by: java.lang.IllegalStateException: attempt to re-open an already-closed object: android.database.sqlite.SQLiteQuery (mSql = SELECT * FROM quotes)
08-15 10:56:19.580: E/AndroidRuntime(3061): at android.database.sqlite.SQLiteClosable.acquireReference(SQLiteClosable.java:34)
08-15 10:56:19.580: E/AndroidRuntime(3061): at android.database.sqlite.SQLiteQuery.fillWindow(SQLiteQuery.java:67)
08-15 10:56:19.580: E/AndroidRuntime(3061): at android.database.sqlite.SQLiteCursor.fillWindow(SQLiteCursor.java:285)
08-15 10:56:19.580: E/AndroidRuntime(3061): at android.database.sqlite.SQLiteCursor.getCount(SQLiteCursor.java:266)
08-15 10:56:19.580: E/AndroidRuntime(3061): at beautiful.quotes.DBHandler.getQuotesCount(DBHandler.java:114)
08-15 10:56:19.580: E/AndroidRuntime(3061): at beautiful.quotes.DBHandler.getRandomQuote(DBHandler.java:139)
08-15 10:56:19.580: E/AndroidRuntime(3061): at beautiful.quotes.UpdateWidgetService.onStart(UpdateWidgetService.java:62)
And the code:
Android manifest.xml
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" android:debuggable="true">
<receiver android:name="BeautifulQuotesWidget">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data android:name="android.appwidget.provider"
android:resource="@xml/beatiful_quotes" />
</receiver>
<service android:name=".UpdateWidgetService"></service>
</application>
Xml for widget:
<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:minWidth="146dip"
android:minHeight="72dip"
android:updatePeriodMillis="180000"
android:initialLayout="@layout/activity_beautiful_quotes"
/>
DBHelper:
public class DBHandler extends SQLiteOpenHelper {
// All Static variables
// Database Version
private static final int DATABASE_VERSION = 1;
// Database Name
private static final String DATABASE_NAME = "QuotesManager";
// Contacts table name
private static final String TABLE_QUOTES = "quotes";
// Contacts Table Columns names
private static final String KEY_ID = "id";
private static final String KEY_AUTHOR = "author";
private static final String KEY_DESCR = "description";
private static final String LOG = "BAZA TEST";
public DBHandler(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
// TODO Auto-generated constructor stub
}
// Creating Tables
@Override
public void onCreate(SQLiteDatabase db) {
String CREATE_QUOTES_TABLE = "CREATE TABLE " + TABLE_QUOTES + "("
+ KEY_ID + " INTEGER PRIMARY KEY," + KEY_AUTHOR + " TEXT,"
+ KEY_DESCR + " TEXT" + ")";
db.execSQL(CREATE_QUOTES_TABLE);
}
// Upgrading database
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// Drop older table if existed
db.execSQL("DROP TABLE IF EXISTS " + TABLE_QUOTES);
// Create tables again
onCreate(db);
}
// Adding new quote
public void addQuote(Quote quote) {
SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(KEY_AUTHOR, quote.getAuthor()); // Author
values.put(KEY_DESCR, quote.getDescription()); // Description
// Inserting Row
db.insert(TABLE_QUOTES, null, values);
db.close(); // Closing database connection
}
// Getting single quote
public Quote getQuote(int id) {
SQLiteDatabase db = this.getReadableDatabase();
Log.i(LOG, "Baza danych");
Cursor cursor = db.query(TABLE_QUOTES, new String[] { KEY_ID,
KEY_AUTHOR, KEY_DESCR }, KEY_ID + "=?",
new String[] { String.valueOf(id) }, null, null, null, null);
if (cursor != null)
cursor.moveToFirst();
Quote quote = new Quote(Integer.parseInt(cursor.getString(0)),
cursor.getString(1), cursor.getString(2));
// return quote
return quote;
}
// Getting All quotes
public List<Quote> getAllQuotes() {
List<Quote> quotesList = new ArrayList<Quote>();
// Select All Query
String selectQuery = "SELECT * FROM " + TABLE_QUOTES;
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor = db.rawQuery(selectQuery, null);
// looping through all rows and adding to list
if (cursor.moveToFirst()) {
do {
Quote quote = new Quote();
quote.setID(Integer.parseInt(cursor.getString(0)));
quote.setAuthor(cursor.getString(1));
quote.setDescription(cursor.getString(2));
// Adding contact to list
quotesList.add(quote);
} while (cursor.moveToNext());
}
// return contact list
cursor.close();
return quotesList;
}
// Getting quotes count
public int getQuotesCount() {
String countQuery = "SELECT * FROM " + TABLE_QUOTES;
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor = db.rawQuery(countQuery, null);
cursor.close();
// return count
return cursor.getCount();
}
// Updating single quote
public int updateQuote(Quote quote) {
SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(KEY_AUTHOR, quote.getAuthor());
values.put(KEY_DESCR, quote.getDescription());
// updating row
return db.update(TABLE_QUOTES, values, KEY_ID + " = ?",
new String[] { String.valueOf(quote.getID()) });
}
// Deleting single quote
public void deleteQuote(Quote quote) {
SQLiteDatabase db = this.getWritableDatabase();
db.delete(TABLE_QUOTES, KEY_ID + " = ?",
new String[] { String.valueOf(quote.getID()) });
db.close();
}
//Get random quote
public Quote getRandomQuote(){
SQLiteDatabase db = this.getReadableDatabase();
int counts = getQuotesCount();
Random rn = new Random();
int id = rn.nextInt(counts);
Cursor cursor = db.query(TABLE_QUOTES, new String[] { KEY_ID,
KEY_AUTHOR, KEY_DESCR }, KEY_ID + "=?",
new String[] { String.valueOf(id) }, null, null, null, null);
if (cursor != null)
cursor.moveToFirst();
Quote quote = new Quote(Integer.parseInt(cursor.getString(0)),
cursor.getString(1), cursor.getString(2));
// return quote
return quote;
}
}
And service:
public class UpdateWidgetService extends Service {
private static final String LOG = "JARO TEST";
DBHandler quoteSeeker;
@Override
public void onStart(Intent intent, int startId) {
Log.i(LOG, "Called");
// Create some random data
quoteSeeker = new DBHandler(this);
// Inserting Contacts
Log.d("Insert: ", "Inserting ..");
quoteSeeker.addQuote(new Quote("Ravi", "9100000000"));
quoteSeeker.addQuote(new Quote("Srinivas", "9199999999"));
quoteSeeker.addQuote(new Quote("Tommy", "9522222222"));
quoteSeeker.close();
quoteSeeker.addQuote(new Quote("Karthik", "9533333333"));
quoteSeeker.addQuote(new Quote("Darek", "DAREKDAREK"));
// Reading all contacts
Log.d("Reading: ", "Reading all contacts..");
List<Quote> contacts = quoteSeeker.getAllQuotes();
for (Quote cn : contacts) {
String log = "Id: "+cn.getID()+" ,Name: " + cn.getAuthor() + " ,Phone: " + cn.getDescription();
// Writing Contacts to log
Log.d("Name: ", log);
}
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(this
.getApplicationContext());
int[] allWidgetIds = intent.getIntArrayExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS);
ComponentName thisWidget = new ComponentName(getApplicationContext(),
BeautifulQuotesWidget.class);
int[] allWidgetIds2 = appWidgetManager.getAppWidgetIds(thisWidget);
Log.w(LOG, "From Intent" + String.valueOf(allWidgetIds.length));
Log.w(LOG, "Direct" + String.valueOf(allWidgetIds2.length));
for (int widgetId : allWidgetIds) {
// Create some random data
int number = (new Random().nextInt(100));
quoteSeeker = new DBHandler(this);
Quote q1 = quoteSeeker.getRandomQuote();
RemoteViews remoteViews = new RemoteViews(this
.getApplicationContext().getPackageName(),
R.layout.activity_beautiful_quotes);
Log.w("WidgetExample", String.valueOf(number));
// Set the text
remoteViews.setTextViewText(R.id.author_name,
"Random: " + String.valueOf(q1.getAuthor()));
remoteViews.setTextViewText(R.id.quote_descr,
"Descr: " + String.valueOf(q1.getDescription()));
// Register an onClickListener
Intent clickIntent = new Intent(this.getApplicationContext(),
BeautifulQuotesWidget.class);
clickIntent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
clickIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS,
allWidgetIds);
PendingIntent pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 0, clickIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
remoteViews.setOnClickPendingIntent(R.id.quote_descr, pendingIntent);
appWidgetManager.updateAppWidget(widgetId, remoteViews);
}
stopSelf();
super.onStart(intent, startId);
}
}
And the AppWidgetProvider
public class BeautifulQuotesWidget extends AppWidgetProvider{
private static final String LOG = "service jarek";
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
// To prevent any ANR timeouts, we perform the update in a service
// Get all ids
ComponentName thisWidget = new ComponentName(context, BeautifulQuotesWidget.class);
int[] allWidgetIds = appWidgetManager.getAppWidgetIds(thisWidget);
// Build the intent to call the service
Intent intent = new Intent(context.getApplicationContext(),
UpdateWidgetService.class);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, allWidgetIds);
Log.i(LOG, "Called");
//context.startService(new Intent(context, UpdateService.class));
// Update the widgets via the service
context.startService(intent);
}
}
Focus on these two lines of your
UpdateWidgetServiceIn second line…you are calling a method itself (Recursion)…AFTER ENDING YOUR SERVICE by calling
stopSelf…That is the problem…you are calling the method of a class that your have destroyed in the previous line…
hope this helps…
If you decide that this answers your question, please mark it as “accepted”. This will raise both your and my reputation score.