【问题标题】:Accessing Layout Items from inside Widget AppWidgetProvider从 Widget AppWidgetProvider 内部访问布局项
【发布时间】:2010-07-20 11:24:06
【问题描述】:

我开始疯狂地试图弄清楚这一点。看起来应该很容易,我开始怀疑这是否可能。

我想要做的是创建一个主屏幕小部件,它只包含一个 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 设为本地和静态私有变量。使用日志我可以看到当应用程序的多个实例在屏幕上时,它们都指的是 RemoteViews 的一个实例。非常适合我正在尝试做的事情

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

我可以在 onUpdate 方法中使用这个来做到这一点。

remoteViews.setImageViewResource(R.id.buttonOne, R.drawable.button_pressed_ringer);

尽管创建了小部件,但这对我没有任何好处。 出于某种原因,即使它在同一个类中,在 onReceive 方法中也会使该行不起作用。

事实上,该行用于抛出一个空指针,直到我将变量更改为静态。现在它通过了 null 测试,引用了与开始时相同的 layoutId,读取了该行,但它什么也不做。

就好像代码根本不存在,只是不停地乱跑。

所以......

有没有办法在创建小部件后从小部件中修改布局元素!? 我想根据环境执行此操作,而不是通过配置活动启动。

我一直在看各种问题,这似乎是一个真正没有解决的问题,例如link textlink text

哦,对于任何找到这个并想要一个好的小部件入门教程的人,这很容易理解(虽然有点旧,但它会让你对小部件感到满意).pdf link text

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

谢谢

【问题讨论】:

    标签: android android-widget


    【解决方案1】:

    您可以使用仅修改 ImageButton 的其他布局重绘屏幕。这听起来像是一个骇人听闻的解决方案,但它对我有用。

    // 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 :)

    【讨论】:

      【解决方案2】:

      @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(); 之后在上面的代码中。 这真的是一个很棒的方法,对我很有帮助,干杯......

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多