【问题标题】:Widget not updating Views and showing no errors as well小部件不更新视图并且也没有显示错误
【发布时间】:2013-06-26 09:29:19
【问题描述】:

我正在开发一个小部件,它运行时没有任何错误,但我的小部件的 ImageView 没有更新,也没有给出任何错误。因此让我对自己做错了什么感到困惑。这是代码:-

BroadcastReceiver _broadcastReceiver;
GetDrawableResources getDrawableResources = new GetDrawableResources();
private final SimpleDateFormat _sdfWatchTime = new SimpleDateFormat("HH:mm");

@Override
public void onEnabled(final Context context) {
    super.onEnabled(context);
    // TODO Auto-generated method stub
    System.out.println("Entering onstart");
    _broadcastReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context ctx, Intent intent) {
            System.out.println("Registering BroadCast");
            if (intent.getAction().compareTo(Intent.ACTION_TIME_TICK) == 0) {

                System.out.println(_sdfWatchTime.format(new Date()));
                Bundle extras = intent.getExtras();
                if (extras != null) {
                    AppWidgetManager awm = AppWidgetManager
                            .getInstance(context);
                    ComponentName thisWidget = new ComponentName(
                            context.getPackageName(),
                            MainActivity.class.getName());
                    int[] appWidgetIds = awm.getAppWidgetIds(thisWidget);
                    onUpdate(context, awm, appWidgetIds);
                }

            }
        }
    };
    context.getApplicationContext().registerReceiver(_broadcastReceiver,
            new IntentFilter(Intent.ACTION_TIME_TICK));

}

@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
        int[] appWidgetIds) {
    // TODO Auto-generated method stub
    super.onUpdate(context, appWidgetManager, appWidgetIds);
    for (int awID : appWidgetIds) {
        updateAppWidget(context, appWidgetManager, awID);
    }

}

private void updateAppWidget(Context context,
        AppWidgetManager appWidgetManager, int awID2) {
    // TODO Auto-generated method stub
    // class to get drawable images that will be used to denote hours and
    // minutes

    int time[] = new int[new GetTime().getTime(context
            .getApplicationContext()).length];
    // class to get each digit of time separately eg 10:10, separating 1 0 1
    // 0 working correctly
    time = new GetTime().getTime(context.getApplicationContext());
    // changing views

    System.out.println("awID for " + awID2);
    RemoteViews views = new RemoteViews(context
            .getPackageName(), R.layout.activity_main);

    views.setImageViewResource(R.id.ivHour0,
            getDrawableResources.setTimeDrawable(time[0]));
    views.setImageViewResource(R.id.ivHour1,
            getDrawableResources.setTimeDrawable(time[1]));
    views.setImageViewResource(R.id.ivMinute0,
            getDrawableResources.setTimeDrawable(time[2]));
    views.setImageViewResource(R.id.ivMinute1,
            getDrawableResources.setTimeDrawable(time[3]));


    System.out.println("updating the views");

    appWidgetManager.updateAppWidget(awID2, views);

}

我的 LogCat 中的输出

06-28 19:46:00.076: I/System.out(680): Registering BroadCast
06-28 19:46:00.086: I/System.out(680): 19:46
06-28 19:46:00.096: I/System.out(680): awID for 14
06-28 19:46:00.096: I/System.out(680): updating the views
06-28 19:47:00.086: I/System.out(680): Registering BroadCast
06-28 19:47:00.086: I/System.out(680): 19:47
06-28 19:47:00.096: I/System.out(680): awID for 14
06-28 19:47:00.096: I/System.out(680): updating the views

因此,appWidgetID 是正确的,并且函数正在按应有的方式执行,但视图没有更新。它们和以前一样。

【问题讨论】:

    标签: android android-widget broadcastreceiver android-view android-appwidget


    【解决方案1】:

    您的方法有一个有效的基础,但是您正在 onEnabled 方法中创建和注册您的 broadcastReceiver,而该方法又属于 WidgetProvider 类。

    当 WidgetProvider 的方法 (onEnabled, onUpdate) 执行完毕后,WidgetProvider 类将被系统销毁,您的 broadcastReceiver 也将被销毁。如您所见,这里没有错误,但也没有收到。

    为了做你想做的事,你需要一个更“稳定”的应用程序组件来保存你的广播接收器,这样的组件就是一个服务。即使您的应用程序停止,服务也会继续运行,因此它是此类作业的好组件。

    所以为了回答你的问题,我建议你创建一个服务来创建和注册你的广播接收器,然后你从你的 widgetprovider 类的 onEnabled 方法启动服务,当用户从他的小部件中删除你的小部件时你可以停止服务主屏幕。

    从我的建议开始的一个好地方是here...

    编辑 Here 是来自 google 的 App Widgets 文档(大约在中间):

    注意:由于 AppWidgetProvider 是 BroadcastReceiver 的扩展,因此无法保证您的进程在回调方法返回后继续运行(有关广播生命周期的信息,请参阅 BroadcastReceiver)。如果您的 App Widget 设置过程可能需要几秒钟(可能在执行 Web 请求时)并且您需要继续您的过程,请考虑在 onUpdate() 方法中启动服务。在服务中,您可以对 App Widget 执行自己的更新,而不必担心 AppWidgetProvider 由于应用程序无响应 (ANR) 错误而关闭。有关运行服务的 App Widget 示例,请参阅维基词典示例的 AppWidgetProvider。

    我在我的 appwidget 中遇到过类似的问题,结果是我的 appwidgetprovider 的生命周期引起的,所以我基于此回答了你。但是,在您的观察中,您是对的,您的小部件至少应该在第一次更新时更新自身,所以更多地研究它我发现您正在使用自定义 getDrawableResources 类来获取您的资源(您可以用它编辑您的问题吗?代码?)并且您正在使用 getDrawableResources.setTimeDrawable(time[0]));为了得到drawable,也许你应该把它改成getDrawableResources.getTimeDrawable(time[0]))?

    编辑 2

    这是说明我的建议的代码。首先是我们注册 BatteryReceiver 的服务。

    class FullWidgetBatteryChangedReceiver extends BroadcastReceiver {
    //----- BroadcastReceiver Overrides -----
    @Override
    public void onReceive(Context cx, Intent intent) {
        Log.d("BatteryChangedReceiver", "onReceive");
    
        Commands.FullWidgetUpdate(cx, -1, 0); //<-- Update all widgets
    }
    //----- BroadcastReceiver Overrides END -----
    }
    
    public class myWidgetService extends Service {
    
    //----- Private Members -----
    private FullWidgetBatteryChangedReceiver    bcRCV;
    //----- Private Members END -----
    
    
    
    //----- Private Code -----    
    private void RegisterBatteryChangedReceiver() {
        Log.d(TAG, "RegisterBatteryChangedReceiver");
    
        if (bcRCV == null) {
            Log.d(TAG, "BatteryChangedReceiver needs Registration and I am doing it...");
    
            bcRCV = new FullWidgetBatteryChangedReceiver();
            IntentFilter actions = new IntentFilter();
            actions.addAction(Intent.ACTION_BATTERY_CHANGED);
            registerReceiver(bcRCV, actions);
        } else {
            Log.d(TAG, "BatteryChangedReceiver does not needs Registration");
        }
    }
    
    private void UnRegisterBatteryChangedReceiver() {
        Log.d(TAG, "UnRegisterBatteryChangedReceiver");
    
        if (bcRCV != null) {
            Log.d(TAG, "Assuming that BatteryChangedReceiver is registered and I am unregister it...");
    
            unregisterReceiver(bcRCV);
            bcRCV = null;
        } else {
            Log.d(TAG, "Assuming that BatteryChangedReceiver is NOT registered");
        }
    }    
    //----- Private Code END -----
    
    
    
    //----- Service Overrides -----
    @Override
    public void onCreate() {
        super.onCreate();
    }
    
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        RegisterBatteryChangedReceiver();
    
        return Service.START_STICKY; //<-- This is important!!!
    }   
    
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
    
    @Override
    public void onDestroy() {       
        UnRegisterBatteryChangedReceiver();
    
        super.onDestroy();
    }   
    //----- Service Overrides END -----
    
    }
    

    然后这里是完成服务操作的 myWidgetProvider:

    public class myWidgetProvider extends AppWidgetProvider {
    
    
    //----- AppWidgetProvider Overrides -----
    @Override
    public void onEnabled(Context context) {
        super.onEnabled(context);
    }
    
    @Override
    public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
        super.onUpdate(context, appWidgetManager, appWidgetIds);
    
        // If no specific widgets requested, collect list of all
        if (appWidgetIds == null) {
            appWidgetIds = appWidgetManager.getAppWidgetIds(new ComponentName(context, FullWidgetProvider.class));
        }
    
        // Εδώ κάνουμε update to Widget για κάθε id ξεχωριστά
        for (int widgetId : appWidgetIds) {
            Commands.FullWidgetUpdate(context, widgetId, 0); //<-- Update το widgetId
        }
    
        context.startService(new Intent(context, myWidgetService.class));
    }
    
    @Override
    public void onDeleted(Context context, int[] appWidgetIds) {        
        super.onDeleted(context, appWidgetIds);
    }
    
    @Override
    public void onDisabled(Context context) {
        super.onDisabled(context);
    
        context.stopService(new Intent(context, FullWidgetService.class));
    
        int[] appWidgetIds = AppWidgetManager.getInstance(context).getAppWidgetIds(new ComponentName(context, FullWidgetProvider.class));
    
        if (appWidgetIds.length != 0) {
            AppWidgetHost host = new AppWidgetHost(context, 0);
    
            for (int widgetId : appWidgetIds) {
                host.deleteAppWidgetId(widgetId);
            }   
        }
    }
    //----- AppWidgetProvider Overrides END -----       
    }
    

    希望这会有所帮助...

    【讨论】:

    • 我不知道这些WidgetProvider类和broadcastReceiver在执行后被销毁了。我正在阅读有关该服务的信息,如果它解决了我的问题,请将答案标记为正确。谢谢
    • 我想清除一些东西。你说在执行onEnabled之后,onUpdate和broadcastReciever被销毁但是每分钟我的broadcastReciever然后onUpdate然后最后updateAppWidget被调用。因此,如果每分钟调用一次 updateAppWidget,则必须更新视图,因为更新是在此方法中完成的。我说错了吗?
    • getDrawableResources 是我制作的一个自定义类,它没有扩展或实现任何东西。这是一个简单的类。它根据 time[0] 发送返回图像的 id。例如,如果时间 [0] 为 8,则在 getDrawableResources 中运行的代码为案例 8:时间 = R.drawable.time_8;休息;
    • @RohanKandwal 是这样的,但看看我的第二次编辑,我在其中添加了一些代码来说明这种方法。谢谢。
    • @RohanKandwal Commands 是我创建的一个自定义静态类,目的是让事情井井有条。您可以将此行替换为您的 updatewidget 函数。对于给您带来的不便,我深表歉意,但我的代码仅用于说明目的,而不是完整的工作代码。顺便说一句,我很高兴你解决了你的问题。谢谢。
    猜你喜欢
    • 1970-01-01
    • 2021-03-09
    • 2019-02-16
    • 2014-09-24
    • 1970-01-01
    • 1970-01-01
    • 2021-07-28
    • 2011-10-04
    • 2022-08-15
    相关资源
    最近更新 更多