我有更新appwidget的问题。这是一个简单的小部件,它使用服务来更新小部件并从db(sqlite)获取引用并在主屏幕上显示它。
在日志中我看到引号已插入db。它们由方法
返回List<Quote> contacts = quoteSeeker.getAllQuotes();
然后显示在日志中:
Log.w(LOG, "From Intent" + String.valueOf(allWidgetIds.length));
Log.w(LOG, "Direct" + String.valueOf(allWidgetIds2.length));
之后出现了这些警告和错误。可能是什么问题?
来自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)
代码: 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:
<?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扩展了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;
}
}
服务:
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);
}
}
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);
}
}
答案 0 :(得分:0)
关注UpdateWidgetService
stopSelf();
super.onStart(intent, startId);
在第二行......你正在调用一个方法本身(递归)......通过调用stopSelf
结束你的服务......
这就是问题......你正在调用你在上一行中销毁过的类的方法......
希望这会有所帮助...
如果您认为这回答了您的问题,请将其标记为“已接受”。这将提高您和我的声誉分数。