Redraw Widget every second

淺唱寂寞╮ 提交于 2019-12-13 07:03:33

问题


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


回答1:


you should recycle bitmap like this

if (bmpLast != null) {
        bmpLast.recycle();
        bmpLast=null;//you must do it
    }

Other then this there is another issue you should use alarmmanager to update widget ,it will cumsume less battery compared to Runnable() ;




回答2:


Part of your problem is probably that you hang on to your RemoteViews object and keep adding 'actions' to it. RemoteViews doesn't do any smart de-duplication of actions, it just appends them to a list, so you're effectively retaining references to every Bitmap you push into it.



来源:https://stackoverflow.com/questions/22248249/redraw-widget-every-second

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!