可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I'm trying to do something which really ought to be quite easy, but it's driving me crazy. I'm trying to launch an activity when a home screen widget is pressed, such as a configuration activity for the widget. I think I've followed word for word the tutorial on the Android Developers website, and even a few unofficial tutorials as well, but I must be missing something important as it doesn't work.
Here is the code:
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);
}
}
}
When adding the widget to the homescreen, Logcat shows the two debugging lines, though not the Toast. (Any ideas why not?) However, more vexing is that when I then click on the button with the PendingIntent associated with it, nothing happens at all. I know the "WidgetTest" activity can run because if I set up an Intent from within the main activity, it launches fine.
In case it matters, here is the Android Manifest file:
<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" />
Is there a way to test where the fault is? I.e. is the fault that the button isn't linked properly to the PendingIntent, or that the PendingIntent or Intent isn't finding WidgetTest.class, etc?
Thanks very much for your help!
Steve
回答1:
I was having the same issue. I discovered that the fix is to call an update through the appwidget manager. here is an example of how to do that in onEnabled. It appears it needs to be done in both onEnabled and onUpdated so that when device is powering on your click intent is also intialized - in onUpdated the params already provide the reference to the manager, luckily.
@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);
}
回答2:
Bringing this way back from the dead, but I had a similar problem and I think I finally solved it... like you, I had a PendingIntent that I attached to the RemoteView. Sometimes it would work, and sometimes it would fail. It was driving me crazy.
What I found from a tooltip on the PendingIntent.getActivty() was:
Note that the activity will be started outside of the context of an existing activity, so you must use the Intent.FLAG_ACTIVITY_NEW_TASK launch flag in the Intent.
so, I added:
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
No example code I've seen so far does this, but it solved my problem; the Settings activity is now launched reliably.
The full code that's working well...
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);
回答3:
This worked for me, based on info here, the word widget sample, and 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:
The problem with the Toast not showing is easy, you don't call show(), a mistake I always do too...
do
Toast.makeText(context, "Hello from onUpdate", Toast.LENGTH_SHORT).show();
instead of
Toast.makeText(context, "Hello from onUpdate", Toast.LENGTH_SHORT);
回答5:
Steve,
Have you found the problem? I use widget and it works fine for me without onEnabled trick. I'm interested why it doesn't for you.
My guess: in your original code please try
PendingIntent pendingIntent = PendingIntent.getActivity(context, 1, intent, 0);
instead of
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
回答6:
When adding the widget to the
homescreen, Logcat shows the two
debugging lines, though not the Toast.
(Any ideas why not?)
Don't try launching Toasts
from a BroadcastReceiver
.
Is there a way to test where the fault
is?
Look at LogCat, via adb logcat
, DDMS, or the DDMS perspective in Eclipse. You may find warnings about not finding an activity to match the given Intent
.
I do not see any obvious problem. You may want to take a peek at one of my book examples and see if that works for you, and if it gives you any idea of what may be afoot.
回答7:
you must define your configuration activity in res/xml/volume_changer_info.xml. Add this tag and give a fully qualified path to the configuration activity.
android:configure = ""
e.g.
<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"/>
回答8:
I know this thread is ancient, but...
Other answers describe your burnt Toast problem. As to why your pop-up activity doesn't launch on touch, you may need to enable the "update" action in order to launch and call your onUpdate() method. For that I think you need to add the "APPWIDGET_UPDATE" action like this:
<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>
Likewise add the APPWIDGET_ENABLED and APPWIDGET_DISABLED actions if you intend to override those methods too.
It seems to be a very unusual API that requires you to declare the overridden methods that you want called. The usual way to get your custom version of a parent is to simply override/implement them. Maybe there's a good reason for this strange pattern, but it is not a Java pattern that I've seen before. I therefore think it is likely to trip up a great deal of app widget authors. As if app widgets were not confusing enough without this mechanism.
回答9:
One additional point: The Activity that is called from the Widget needs to be declared in the Manifest file. No exception is thrown, just looks like nothing happens...
回答10:
I just wanted to note this here somewhere as I have been (quite stupidly) battling this all night. Basically I did all the intent code correctly but nothing would be launched.
The problem was that I accidentally had a call like this
super.onUpdate(context, appWidgetManager, appWidgetIds);
at the end of my Overridden onUpdate() function.
Make sure you DO NOT have this call to super as it will clear out all pending intents you've set up!