从Widget AppWidgetProvider内部访问布局项

时间:2010-07-20 11:24:06

标签: android android-widget

我开始疯狂地试图解决这个问题。看起来应该很容易,我开始怀疑它是否可能。

我要做的是创建一个只包含ImageButton的主屏幕小部件。 按下时,想法是更改某些设置(如wi-fi切换),然后更改按钮图像。

我在main.xml

中声明了ImageButton

<ImageButton android:id="@+id/buttonOne"
        android:src="@drawable/button_normal_ringer"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center" />

我的AppWidgetProvider类,名为ButtonWidget

***请注意,RemoteViews类是本地存储的变量。这让我可以访问RViews布局元素......或者我认为。

@Override
    public void onUpdate(Context context, AppWidgetManager appWidgetManager,
            int[] appWidgetIds) {

    remoteViews = new RemoteViews(context.getPackageName(),
            R.layout.main);

    Intent active = new Intent(context, ButtonWidget.class);
    active.setAction(VIBRATE_UPDATE);
    active.putExtra("msg","TESTING");
    PendingIntent actionPendingIntent = PendingIntent.getBroadcast(context,
            0, active, 0);
    remoteViews.setOnClickPendingIntent(R.id.buttonOne,
            actionPendingIntent);

    appWidgetManager.updateAppWidget(appWidgetIds, remoteViews);


}

@Override
public void onReceive(Context context, Intent intent) {

    // v1.5 fix that doesn't call onDelete Action
    final String action = intent.getAction();
    Log.d("onReceive",action);
    if (AppWidgetManager.ACTION_APPWIDGET_DELETED.equals(action)) {
        final int appWidgetId = intent.getExtras().getInt(
                AppWidgetManager.EXTRA_APPWIDGET_ID,
                AppWidgetManager.INVALID_APPWIDGET_ID);
        if (appWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID) {
            this.onDeleted(context, new int[] { appWidgetId });
        }
    } else {
        // check, if our Action was called
        if (intent.getAction().equals(VIBRATE_UPDATE)) {
            String msg = "null";
            try {
                msg = intent.getStringExtra("msg");
            } catch (NullPointerException e) {
                Log.e("Error", "msg = null");
            }
            Log.d("onReceive",msg);
            if(remoteViews != null){

                Log.d("onReceive",""+remoteViews.getLayoutId());
                remoteViews.setImageViewResource(R.id.buttonOne, R.drawable.button_pressed_ringer);

                Log.d("onReceive", "tried to switch");
            }
            else{
                Log.d("F!", "--naughty language used here!!!--");
            }
        }
        super.onReceive(context, intent);
    }
}

所以,我一直在测试这个并且onReceive方法效果很好,我能够发送通知和各种各样的东西(从代码中删除以方便阅读)

我不能做的一件事就是改变视图元素的任何属性。

为了尝试解决这个问题,我将RemoteViews作为本地和静态私有变量。使用log我可以看到当应用程序的多个实例在屏幕上时,它们都引用了一个RemoteViews实例。完美的我正在尝试做什么

问题在于尝试更改ImageButton的图像。

我可以使用此方法在onUpdate方法中执行此操作。

remoteViews.setImageViewResource(R.id.buttonOne, R.drawable.button_pressed_ringer);
一旦创建了小部件,这对我没有任何好处。 出于某种原因,即使它在同一个类中,在onReceive方法中也会使该行无效。

该行用于抛出Null指针,直到我将变量更改为static。现在它通过了null测试,引用了与在开始时相同的layoutId,读取了行,但它什么也没做。

就像代码甚至不存在一样,只是一直在喋喋不休。

SO ......

创建窗口小部件后,有没有办法在窗口小部件中修改布局元素? 我想基于环境而不是配置活动启动来执行此操作。

我一直在研究各种问题,这似乎是一个尚未解决的问题,例如link textlink text

哦,对于任何发现这个并希望获得小工具的良好入门教程的人来说,这很容易理解(虽然有点旧,但它让你对小部件感到满意).pdf link text

希望有人可以在这里提供帮助。我有点觉得这是非法的,并且有不同的方法可以解决这个问题。我很乐意被告知另一种方法!!!!

由于

2 个答案:

答案 0 :(得分:2)

您可以使用仅修改了ImageButton的其他布局重绘屏幕。这听起来像一个hackish解决方案,但它适用于我。

// Your appWidgetProvider class should track which layout it's currently on
private static int layoutId;

// onReceive should be something like this
@Override
public void onReceive(Context context, Intent intent) {
    Bundle bundle = intent.getExtras();

    if (bundle != null) {
        int newLayoutId = bundle.getInt("layout_id");
        // Change the current layout id to the layout id contained in the bundle
        layoutId = newLayoutId;
        initViews(context);
    } else {
        initViews(context);
    }
}

// Initialize the view according to the chosen layout
private void initViews(Context context) {
    RemoteViews views = null;

    // Set the initial layout   
    if (layoutId == 0) {
        Intent layoutIntent = new Intent("android.appwidget.action.APPWIDGET_UPDATE");
        Bundle layoutBundle = new Bundle();

        // I put in the layoutId of the next layout. Note that the layoutId is not
        // from R. I just made up some easy to remember number for my layoutId
        layoutBundle.putInt("layout_id", 1);

        PendingIntent lPendingIntent = PendingIntent.getBroadcast(context, 0,
                layoutIntent, PendingIntent.FLAG_ONE_SHOT);

        // Set the layout to the first layout
        views = new RemoteViews(context.getPackageName(), R.layout.layout_zero);

        // I used buttons to trigger a layout change
        views.setOnClickPendingIntent(R.id.btnNext, lPendingIntent);
    } // Else if there's some trigger to change the layout...
    else if (layoutId == 1) {
        Intent layoutIntent = new Intent("android.appwidget.action.APPWIDGET_UPDATE");
        Bundle layoutBundle = new Bundle();

        // Since I only have two layouts, I put here the id of the previous layout
        layoutBundle.putInt("layout_id", 0);

        PendingIntent lPendingIntent = PendingIntent.getBroadcast(context, 0,
                layoutIntent, PendingIntent.FLAG_ONE_SHOT);

        // Set the layout to the second layout
        // This layout should be almost the same as the first layout except for the
        // part that you want to change
        views = new RemoteViews(context.getPackageName(), R.layout.layout_one);
        views.setOnClickPendingIntent(R.id.btnPrev, lPendingIntent);
    }
}

如您所见,我使用了两种不同的布局,用户可以通过按钮点击切换。您可以根据需要使用不同的触发器来更改布局。可以找到类似的解决方案link text。请原谅我把代码放在onReceive而不是onUpdate:)

答案 1 :(得分:0)

@Avendael您的代码完美无缺。您唯一需要做的就是添加更新小部件。像这样的事情

public static void buildUpdate(Context context) {
RemoteViews updateViews;                    
//Have your own condition here
if (1==1){
    layoutId = R.layout.main;
} else {
    layoutId = R.layout.main1;
}
updateViews = new RemoteViews(context.getPackageName(),
    layoutId);
//actually do things here
//then finally, return our remoteView
AppWidgetManager.getInstance(context).updateAppWidget(
    new ComponentName(context, ButtonWidget.class), updateViews);

}

在分配新的远程视图以更新窗口小部件布局后,调用此方法buildUpdate(context)。例如,我们可以在views.setOnClickPendingIntent();之后放置它。在上面的代码中。 这真的是一个很好的方法,对我来说真的很有帮助...