从小部件启动活动
Posted
技术标签:
【中文标题】从小部件启动活动【英文标题】:Launching activity from widget 【发布时间】:2010-12-28 13:51:51 【问题描述】:我正在尝试做一些应该很容易的事情,但这让我发疯了。我正在尝试在按下主屏幕小部件时启动活动,例如小部件的配置活动。我想我已经逐字阅读了 android Developers 网站上的教程,甚至还有一些非官方的教程,但我一定错过了一些重要的东西,因为它不起作用。
代码如下:
public class VolumeChangerWidget extends AppWidgetProvider
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds)
final int N = appWidgetIds.length;
for (int i=0; i < N; i++)
int appWidgetId = appWidgetIds[i];
Log.d("Steve", "Running for appWidgetId " + appWidgetId);
Toast.makeText(context, "Hello from onUpdate", Toast.LENGTH_SHORT);
Log.d("Steve", "After the toast line");
Intent intent = new Intent(context, WidgetTest.class);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget);
views.setOnClickPendingIntent(R.id.button, pendingIntent);
appWidgetManager.updateAppWidget(appWidgetId, views);
将小部件添加到主屏幕时,Logcat 会显示两个调试行,但不是 Toast。 (有什么想法为什么不呢?)然而,更令人烦恼的是,当我然后单击具有关联的 PendingIntent 的按钮时,什么也没有发生。我知道“WidgetTest”活动可以运行,因为如果我在主活动中设置一个 Intent,它可以正常启动。
如果重要的话,这里是 Android Manifest 文件:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.steve"
android:versionCode="1"
android:versionName="1.0">
<application android:icon="@drawable/icon" android:label="@string/app_name">
<activity android:name=".Volume_Change_Program"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".WidgetTest"
android:label="@string/hello">
<intent_filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent_filter>
</activity>
<receiver android:name=".VolumeChangerWidget" >
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data android:name="android.appwidget.provider"
android:resource="@xml/volume_changer_info" />
</receiver>
</application>
<uses-sdk android:minSdkVersion="3" />
有没有办法测试故障在哪里? IE。是按钮未正确链接到 PendingIntent,还是 PendingIntent 或 Intent 未找到 WidgetTest.class 等故障?
非常感谢您的帮助!
史蒂夫
【问题讨论】:
【参考方案1】:让这种方式起死回生,但我遇到了类似的问题,我想我终于解决了它......和你一样,我有一个附加到 RemoteView 的 PendingIntent。有时它会起作用,有时它会失败。这让我发疯了。
我从 PendingIntent.getActivty() 的工具提示中发现:
请注意,活动将在现有活动的上下文之外启动,因此您必须在 Intent 中使用 Intent.FLAG_ACTIVITY_NEW_TASK 启动标志。
所以,我补充说:
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
到目前为止,我没有看到任何示例代码可以做到这一点,但它解决了我的问题;现在可以可靠地启动设置活动。
运行良好的完整代码...
Intent intent = new Intent(context, Settings.class);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appId); // Identifies the particular widget...
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
// Make the pending intent unique...
intent.setData(Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME)));
PendingIntent pendIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.wwwidget);
views.setOnClickPendingIntent(R.id.widget, pendIntent);
appWidgetManager.updateAppWidget(appId,views);
【讨论】:
对我来说,是setData(...)
行使它起作用。在此之前,我无法收到任何额外的东西。我知道,难以置信。【参考方案2】:
我遇到了同样的问题。我发现解决方法是通过 appwidget 管理器调用更新。这是一个如何在 onEnabled 中执行此操作的示例。看来它需要在 onEnabled 和 onUpdated 中完成,这样当设备启动时,您的点击意图也会被初始化——幸运的是,在 onUpdated 中,参数已经提供了对管理器的引用。
@Override
public void onEnabled(Context context)
//Log.v("toggle_widget","Enabled is being called");
AppWidgetManager mgr = AppWidgetManager.getInstance(context);
//retrieve a ref to the manager so we can pass a view update
Intent i = new Intent();
i.setClassName("yourdoman.yourpackage", "yourdomain.yourpackage.yourclass");
PendingIntent myPI = PendingIntent.getService(context, 0, i, 0);
//intent to start service
// Get the layout for the App Widget
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.togglelayout);
//attach the click listener for the service start command intent
views.setOnClickPendingIntent(R.id.toggleButton, myPI);
//define the componenet for self
ComponentName comp = new ComponentName(context.getPackageName(), ToggleWidget.class.getName());
//tell the manager to update all instances of the toggle widget with the click listener
mgr.updateAppWidget(comp, views);
【讨论】:
很遗憾,我还没有弄清楚如何做到这一点。它一定是晦涩难懂的,就像你一样,我阅读了我能找到的所有教程,但从未找到有用的东西。我刚刚搁置了这个项目并开始做其他事情,直到我知道如何更好地使用 Android。 嘿史蒂夫。我想我已经找到了解决方案。我正在开发 2.0.1。关键是将这个确切的代码移动到 onUpdated 中,然后调用另外一件事 - 对 AppWidgetManager 的引用通过参数进入 onUpdated。 ComponentName comp = new ComponentName(context.getPackageName(), ToggleWidget.class.getName()); appWidgetManager.updateAppWidget(comp, views);这个版本告诉它像这样更新小部件的所有实例。现在唯一的问题是让 onEnabled 调用 onUpdate 一次,以便在用户将小部件添加到主页时初始化。 +1 谢谢。通过添加 mgr.updateAppWidget,我终于能够让我的小部件执行相同的操作。 感谢您的建议!一旦我完成了我正在做的另一个项目,我会试一试。 (您的代码看起来与我尝试过的其他事情非常相似,但我正在使用 v1.5 进行编码,因为这是我手机上的版本。我希望这不是 v1.5 无法正常工作的问题,按照有关此版本中 AppWidgets 所需的各种解决方法的一些报告...) onEnabled() 在这里完全无关紧要。它甚至没有被调用!【参考方案3】:这对我有用,基于此处的信息、单词小部件示例和 the tutorial here
Intent intent = new Intent(Intent.ACTION_MAIN, null);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
// first param is app package name, second is package.class of the main activity
ComponentName cn = new ComponentName("com....","com...MainActivity");
intent.setComponent(cn);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent myPI = PendingIntent.getActivity(context, 0, intent, 0);
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget_word);
views.setOnClickPendingIntent(R.id.widget, myPI);
AppWidgetManager mgr = AppWidgetManager.getInstance(context);
mgr.updateAppWidget(comp, views);
【讨论】:
【参考方案4】:Toast 不显示的问题很简单,你不调用 show(),我也经常犯这个错误... 做
Toast.makeText(context, "Hello from onUpdate", Toast.LENGTH_SHORT).show();
而不是
Toast.makeText(context, "Hello from onUpdate", Toast.LENGTH_SHORT);
【讨论】:
大声笑,谢谢。这就是我希望需要的那种简单修复:P 这确实是解决吐司问题的方法。现在只要我能弄清楚为什么活动没有启动......【参考方案5】:将小部件添加到 主屏幕,Logcat 显示两个 调试行,虽然不是 Toast。 (有什么想法为什么不呢?)
不要尝试从BroadcastReceiver
启动Toasts
。
有没有办法测试故障在哪里 是吗?
通过adb logcat
、DDMS 或 Eclipse 中的 DDMS 透视图查看 LogCat。您可能会发现有关未找到与给定 Intent
匹配的活动的警告。
我没有发现任何明显的问题。您可能想看看one of my book examples,看看它是否适合您,以及它是否能让您对可能发生的事情有所了解。
【讨论】:
LogCat 在添加按钮时这样说: DEBUG/Steve(772): Running for appWidgetId 33 DEBUG/Steve(772): 在 toast 行之后 DEBUG/Launcher(622): dumping extras content= Bundle[appWidgetId=33] WARN/InputManagerService(571):窗口已经聚焦,忽略焦点增益:com.android.internal.view.IInputMethodClient$Stub$Proxy@4388abe0 但是当按下按钮时什么都没有。感谢您提供示例程序,我会仔细查看,看看是否能找到一些迹象表明我哪里出错了。 嗯...感觉就像它没有注册您的点击。您确定 R.id.button 在您的小部件布局中吗? 我认为是。我在 xml 文件中有一个带有“@+id/button”行的 【参考方案6】:您必须在 res/xml/volume_changer_info.xml 中定义您的配置活动。添加此标记并提供配置活动的完全限定路径。
android:configure = ""
例如
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:minWidth="200dip"
android:minHeight="100dip"
android:updatePeriodMillis="60000"
android:initialLayout="@layout/widget_loading"
android:configure = "org.raza.ConfigureWidgetActivity"/>
【讨论】:
嗨,当我们提到“配置活动”时,我想我们在谈论不同的事情。我的意思是添加小部件后可以随时启动的东西,而不是添加小部件时会启动的东西。此问题已在不久前解决,但感谢您的帮助!【参考方案7】:我知道这条线很古老,但是... 其他答案描述了您烧焦的吐司问题。至于为什么您的弹出活动没有在触摸时启动,您可能需要启用“更新”操作才能启动并调用您的 onUpdate() 方法。为此,我认为您需要像这样添加“APPWIDGET_UPDATE”操作:
<activity android:name=".WidgetTest" android:label="@string/hello">
<intent_filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent_filter>
</activity>
如果您也打算覆盖这些方法,请同样添加 APPWIDGET_ENABLED 和 APPWIDGET_DISABLED 操作。
这似乎是一个非常不寻常的 API,它要求您声明要调用的覆盖方法。获取自定义版本的父级的常用方法是简单地覆盖/实现它们。也许这种奇怪的模式有充分的理由,但它不是我以前见过的 Java 模式。因此,我认为它可能会绊倒大量的应用程序小部件作者。好像没有这种机制,应用小部件还不够混乱。
【讨论】:
【参考方案8】:另外一点:从Widget调用的Activity需要在Manifest文件中声明。没有抛出异常,只是看起来什么都没有发生......
【讨论】:
【参考方案9】:我只是想在这里的某个地方注意这一点,因为我一直(非常愚蠢地)整晚都在与这个作斗争。基本上我正确地完成了所有意图代码,但什么都不会启动。
问题是我不小心接到了这样的电话
super.onUpdate(context, appWidgetManager, appWidgetIds);
在我重写的 onUpdate() 函数的末尾。
确保您不要对 super 进行此调用,因为它会清除您已设置的所有待处理意图!
【讨论】:
这很奇怪,至少in recent Android versions AppWidgetProvider.onUpdate() does nothing。 是的,它也让我感到困惑,但删除那条线对我来说是什么:)以上是关于从小部件启动活动的主要内容,如果未能解决你的问题,请参考以下文章
onActivityResult 从未从小部件启动的活动中调用
如果活动在后台运行,则无需通过启动器即可从小部件恢复现有活动