I want to create a clock widget with a second watch hand. And yes, I already read that widgets aren't designed to be refreshed that fast.
The widget should become an egg timer which is only animated when the user actively starts it so it is probably not that bad for battery life and performance at all because I only use this high refresh rate when the user actively uses it...
Currently I start a service which posts a delayed runnable every 1000 milliseconds.
Handler mTimeRecordLongTouchedHandler = new Handler();
Runnable mTimeRecordLongTouched = new Runnable() {
public void run() {
remoteViews.setTextViewText(R.id.tv_widget_watch, _fmtTime.print(new DateTime()));
Bitmap bmpSource = _bmpSource.copy(Bitmap.Config.ARGB_8888, true);
Canvas canvas = new Canvas(bmpSource);
DateTime dtNow = new DateTime();
int iSeconds = dtNow.getSecondOfMinute();
float radius = _bmpSource.getWidth() / 2;
float mX = _bmpSource.getWidth() / 2;
float mY = _bmpSource.getWidth() / 2;
float pX = mX + radius * FloatMath.cos(iSeconds * 6);
float pY = mY + radius * FloatMath.sin(iSeconds * 6);
canvas.drawLine(mX, mY, pX, pY, paint3);
remoteViews.setImageViewBitmap(R.id.iv_tower, bmpSource);
manager.updateAppWidget(thiswidget, remoteViews);
iCounter++;
// if (bmpLast != null) {
// bmpLast.recycle();
// }
// bmpLast = bmpSource;
mTimeRecordLongTouchedHandler.postDelayed(mTimeRecordLongTouched, 1000);
}
};
After a few seconds I get: “android.os.TransactionTooLargeException”. For this exception I don’t have a stack trace but I guess it is because I don’t recycle my newly created bitmap. The exception after this is: “system server dead?” and here I have a stacktrace:
03-07 11:26:28.374: E/AndroidRuntime(13422): FATAL EXCEPTION: main
03-07 11:26:28.374: E/AndroidRuntime(13422): java.lang.RuntimeException: system server dead?
03-07 11:26:28.374: E/AndroidRuntime(13422): at android.appwidget.AppWidgetManager.updateAppWidget(AppWidgetManager.java:554)
03-07 11:26:28.374: E/AndroidRuntime(13422): at com.mxp.time.service.WidgetService$1.run(WidgetService.java:90)
03-07 11:26:28.374: E/AndroidRuntime(13422): at android.os.Handler.handleCallback(Handler.java:730)
03-07 11:26:28.374: E/AndroidRuntime(13422): at android.os.Handler.dispatchMessage(Handler.java:92)
03-07 11:26:28.374: E/AndroidRuntime(13422): at android.os.Looper.loop(Looper.java:137)
03-07 11:26:28.374: E/AndroidRuntime(13422): at android.app.ActivityThread.main(ActivityThread.java:5493)
03-07 11:26:28.374: E/AndroidRuntime(13422): at java.lang.reflect.Method.invokeNative(Native Method)
03-07 11:26:28.374: E/AndroidRuntime(13422): at java.lang.reflect.Method.invoke(Method.java:525)
03-07 11:26:28.374: E/AndroidRuntime(13422): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1209)
03-07 11:26:28.374: E/AndroidRuntime(13422): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1025)
03-07 11:26:28.374: E/AndroidRuntime(13422): at dalvik.system.NativeStart.main(Native Method)
03-07 11:26:28.374: E/AndroidRuntime(13422): Caused by: android.os.TransactionTooLargeException
03-07 11:26:28.374: E/AndroidRuntime(13422): at android.os.BinderProxy.transact(Native Method)
03-07 11:26:28.374: E/AndroidRuntime(13422): at com.android.internal.appwidget.IAppWidgetService$Stub$Proxy.updateAppWidgetProvider(IAppWidgetService.java:736)
03-07 11:26:28.374: E/AndroidRuntime(13422): at android.appwidget.AppWidgetManager.updateAppWidget(AppWidgetManager.java:551)
03-07 11:26:28.374: E/AndroidRuntime(13422): ... 10 more
I thought that I can solve this easily with just recycling my bitmap
if (bmpLast != null) {
bmpLast.recycle();
}
bmpLast = bmpSource;
but this just leads me to the next problem:
03-07 11:28:22.964: E/AndroidRuntime(14559): FATAL EXCEPTION: main
03-07 11:28:22.964: E/AndroidRuntime(14559): java.lang.IllegalStateException: Can't parcel a recycled bitmap
03-07 11:28:22.964: E/AndroidRuntime(14559): at android.graphics.Bitmap.checkRecycled(Bitmap.java:273)
03-07 11:28:22.964: E/AndroidRuntime(14559): at android.graphics.Bitmap.writeToParcel(Bitmap.java:1332)
03-07 11:28:22.964: E/AndroidRuntime(14559): at android.widget.RemoteViews$BitmapCache.writeBitmapsToParcel(RemoteViews.java:988)
03-07 11:28:22.964: E/AndroidRuntime(14559): at android.widget.RemoteViews.writeToParcel(RemoteViews.java:2573)
03-07 11:28:22.964: E/AndroidRuntime(14559): at com.android.internal.appwidget.IAppWidgetService$Stub$Proxy.updateAppWidgetProvider(IAppWidgetService.java:730)
03-07 11:28:22.964: E/AndroidRuntime(14559): at android.appwidget.AppWidgetManager.updateAppWidget(AppWidgetManager.java:551)
03-07 11:28:22.964: E/AndroidRuntime(14559): at com.mxp.time.service.WidgetService$1.run(WidgetService.java:90)
03-07 11:28:22.964: E/AndroidRuntime(14559): at android.os.Handler.handleCallback(Handler.java:730)
03-07 11:28:22.964: E/AndroidRuntime(14559): at android.os.Handler.dispatchMessage(Handler.java:92)
03-07 11:28:22.964: E/AndroidRuntime(14559): at android.os.Looper.loop(Looper.java:137)
03-07 11:28:22.964: E/AndroidRuntime(14559): at android.app.ActivityThread.main(ActivityThread.java:5493)
03-07 11:28:22.964: E/AndroidRuntime(14559): at java.lang.reflect.Method.invokeNative(Native Method)
03-07 11:28:22.964: E/AndroidRuntime(14559): at java.lang.reflect.Method.invoke(Method.java:525)
03-07 11:28:22.964: E/AndroidRuntime(14559): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1209)
03-07 11:28:22.964: E/AndroidRuntime(14559): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1025)
03-07 11:28:22.964: E/AndroidRuntime(14559): at dalvik.system.NativeStart.main(Native Method)
I already cache my last bitmap and only recycle it when the new one is forwarded to the widget. Why do I get this exception?
Who wants to parcel my last Bitmap? Keeps the widget a reference to all Bitmaps I pass in???
Cheers, Stefan