安卓中的可点击小部件

65

开发文档在这里似乎对我失灵了。 我可以轻松创建静态小部件,甚至可以创建像模拟时钟小部件这样的自更新小部件,但是我死活想不出如何创建响应用户单击的小部件。以下是开发文档提供的有关小部件活动应包含什么的最佳代码示例(唯一的其他提示是API演示,它仅创建静态小部件):

public class ExampleAppWidgetProvider extends AppWidgetProvider {
    public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
        final int N = appWidgetIds.length;

        // Perform this loop procedure for each App Widget that belongs to this provider
        for (int i=0; i<N; i++) {
            int appWidgetId = appWidgetIds[i];

            // Create an Intent to launch ExampleActivity
            Intent intent = new Intent(context, ExampleActivity.class);
            PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);

            // Get the layout for the App Widget and attach an on-click listener to the button
            RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.appwidget_provider_layout);
            views.setOnClickPendingIntent(R.id.button, pendingIntent);

            // Tell the AppWidgetManager to perform an update on the current App Widget
            appWidgetManager.updateAppWidget(appWidgetId, views);
        }
    }
}

来自:Android开发者文档小部件页

所以,看起来当小部件被点击时会调用挂起意图(pending intent),这是基于一个意图(intent)(我不太确定意图和挂起意图的区别),而该意图是为ExampleActivity类创建的。所以我创建了一个简单的活动类作为示例,在创建时会创建一个媒体播放器对象并启动它(它不会释放该对象,因此最终会崩溃,以下是它的代码:

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    MediaPlayer mp = MediaPlayer.create(getApplicationContext(), R.raw.sound);
    mp.start();
}

然而,当我把小部件添加到主屏幕并点击它时,什么也没有播放,甚至当我将更新定时器设置为几百毫秒时(在appwidget提供程序xml文件中),仍然没有任何声音。此外,我设置了断点并发现不仅从未到达活动,而且我设置的任何断点都不会被触发。(我仍然没有弄清楚为什么),但是logcat似乎表明正在运行活动类文件。

那么,有什么可以使appwidget响应点击的方法吗?因为onClickPendingIntent()方法是我找到的最接近onClick类型的方法。


嗨Leif,你是用Brain515的方法解决了这个问题吗?我有一个类似的问题,但是Brain的解决方案对我不起作用,你能帮我吗? - Stack User 5674
2个回答

130

首先,添加一个带有常量的静态变量。

public static String YOUR_AWESOME_ACTION = "YourAwesomeAction";

在将意图添加到待定意图之前,您需要将操作添加到意图中:

Intent intent = new Intent(context, widget.class);
intent.setAction(YOUR_AWESOME_ACTION);

(其中 widget.class 是您的 AppWidgetProvider 的类,即您当前的类)

然后,您需要使用 getBroadcast 创建一个 PendingIntent。

PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, 0);

为小部件中可点击视图设置onClickPendingIntent。

remoteView.setOnClickPendingIntent(R.id.widgetFrameLayout, pendingIntent);

接下来,在同一类中重写onReceive方法:

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

然后在onReceive方法内通过查询返回给你的操作意图来响应你的按钮按下:

if (intent.getAction().equals(YOUR_AWESOME_ACTION)) {
   //do some really cool stuff here
}

这样应该就可以了!


1
这行代码(Intent intent = new Intent(context, ExampleActivity.class);)应该放在哪里?widget.class 包含什么?我猜 ExampleActivity 是我们想要启动的内容。 - JustCurious
1
编辑了对一个方法的回复,增加了一些额外的步骤以使其正常工作。getBroadcast 对于 PendingIntent 被广播是很重要的,而不是从示例中使用 getActivity。 - Guykun
1
.getActivity用于打开一个活动,例如当您单击小部件中的对象时。 - erdomester
1
使用LocalBroadcastManager代替通用广播。 - Vikram Bodicherla
1
据我所知,无法在LocalBroadcastManager中使用PendingIntent。 - vault
显示剩余5条评论

2

onUpdate方法保持不变,并将逻辑复制粘贴到updateAppWidget中。

static void updateAppWidget(Context context, AppWidgetManager appWidgetManager,
                            int appWidgetId) {

    // Create an Intent to launch ExampleActivity when clicked
    Intent intent = new Intent(context, ExampleActivity.class);
    PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
    // Construct the RemoteViews object
    RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.appwidget_provider_layout);
    // Widgets allow click handlers to only launch pending intents
    views.setOnClickPendingIntent(R.id.button, pendingIntent);
    // Instruct the widget manager to update the widget
    appWidgetManager.updateAppWidget(appWidgetId, views);
}

@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
    // There may be multiple widgets active, so update all of them
    for (int appWidgetId : appWidgetIds) {
        updateAppWidget(context, appWidgetManager, appWidgetId);
    }
}

顺便提一下,PendingIntent 就相当于 Intent 的“盒子”,它允许 其他应用程序 访问并在你的应用程序中运行该 Intent。


你为什么要在每次小部件更新时这样做?肯定只需要做一次就可以了吧? - Richard Barraclough

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接