Lancement de l'activité à partir du widget
J'essaie de faire quelque chose qui devrait vraiment être assez facile, mais ça me rend fou. J'essaie de lancer une activité lorsqu'un widget de l'écran d'accueil est pressé, comme une activité de configuration pour le widget. Je pense que j'ai suivi mot pour mot le tutoriel sur le site Web des Développeurs Android, et même quelques tutoriels non officiels, mais je dois manquer quelque chose d'important car cela ne fonctionne pas.
Voici le 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);
}
}
}
Lors de l'ajout du widget à L'écran D'accueil, Logcat montre les deux lignes de débogage, mais pas le Toast. (Des idées pourquoi pas?) Cependant, plus vexant est que lorsque je clique ensuite sur le bouton avec le PendingIntent associé, rien ne se passe du tout. Je sais que L'activité" WidgetTest " peut s'exécuter car si je configure une intention à partir de l'activité principale, elle se lance bien.
Au cas où cela importerait, voici le fichier manifeste Android:
<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" />
Existe-t-il un moyen de tester où se trouve la faute? I. e. est le défaut que le bouton N'est pas lié correctement au PendingIntent, ou que le PendingIntent ou L'intention ne trouve pas WidgetTest.classe, etc?
Merci beaucoup pour votre aide!
Steve
10 réponses
J'avais le même problème. J'ai découvert que le correctif consiste à appeler une mise à jour via le gestionnaire appwidget. voici un exemple de la façon de le faire dans onEnabled. Il semble que cela doit être fait à la fois dans onEnabled et onUpdated afin que lorsque le périphérique est sous tension, votre intention de clic soit également initialisée - dans onUpdated, les paramètres fournissent déjà la référence au gestionnaire, heureusement.
@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);
}
Ramener cette Façon d'entre les morts, mais j'ai eu un problème similaire et je pense que je l'ai finalement résolu... comme vous, j'ai eu un PendingIntent que j'ai attaché à la RemoteView. Parfois, cela fonctionnerait, et parfois cela échouerait. Il a été me rend fou.
Ce que j'ai trouvé à partir d'une info-bulle sur le PendingIntent.getActivty() était:
Notez que l'activité sera démarrée en dehors du contexte d'une activité existante, vous devez donc utiliser Intention.Flag_activity_new_task drapeau de lancement dans L'intention.
Donc, j'ai ajouté:
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Aucun exemple de code que j'ai vu jusqu'à présent ne le fait, mais il a résolu mon problème; L'activité des paramètres est maintenant lancée de manière fiable.
Le code complet qui fonctionne bien...
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);
Cela a fonctionné pour moi, basé sur info ici, l'exemple de widget word, et le tutoriel ici
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);
Le problème avec le Toast qui ne s'affiche pas est facile, vous n'appelez pas show (), une erreur que je fais toujours aussi... do
Toast.makeText(context, "Hello from onUpdate", Toast.LENGTH_SHORT).show();
Au Lieu de
Toast.makeText(context, "Hello from onUpdate", Toast.LENGTH_SHORT);
Steve,
Avez-vous trouvé le problème? J'utilise un widget et cela fonctionne très bien pour moi sans astuce onEnabled. Je suis intéressé pourquoi il ne fait pas pour vous.
Ma conjecture: dans votre code d'origine, veuillez essayer
PendingIntent pendingIntent = PendingIntent.getActivity(context, 1, intent, 0);
Au Lieu de
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
Lors de l'ajout du widget écran d'accueil, Logcat montre les deux lignes de débogage, mais pas le Toast. (Des idées pourquoi pas?)
N'essayez pas de lancer Toasts
à partir d'un BroadcastReceiver
.
Existe-t-il un moyen de tester où la faute est?
Regardez LogCat, via adb logcat
, DDMS ou la perspective DDMS dans Eclipse. Vous pouvez trouver des avertissements sur le fait de ne pas trouver une activité correspondant au Intent
donné.
Je ne vois aucun problème évident. Vous voudrez peut-être prendre un regardez un de mes exemples de livres et voyez si cela fonctionne pour vous, et si cela vous donne une idée de ce qui peut être en cours.
Vous devez définir votre activité de configuration dans res / xml / volume_changer_info.XML. Ajoutez cette balise et donnez un chemin complet à l'activité de configuration.
Android:configurer = ""
Par exemple
<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"/>
Je voulais juste noter ceci ici quelque part car j'ai été (assez bêtement) en train de me battre toute la nuit. Fondamentalement, j'ai fait tout le code d'intention correctement mais rien ne serait lancé.
Le problème était que j'ai accidentellement eu un appel comme celui-ci
super.onUpdate(context, appWidgetManager, appWidgetIds);
À la fin de ma fonction onUpdate () remplacée.
Assurez-vous que vous n'avez pas Cet appel à super car il effacera toutes les intentions en attente que vous avez configurées!
Je sais que ce fil est ancien, mais... D'autres réponses décrivent votre problème de pain grillé brûlé. Quant à la raison pour laquelle votre activité pop-up ne se lance pas au toucher, vous devrez peut-être activer l'action "update" pour lancer et appeler votre méthode onUpdate (). Pour cela, je pense que vous devez ajouter L'action" APPWIDGET_UPDATE " comme ceci:
<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>
Ajoutez également les actions APPWIDGET_ENABLED et APPWIDGET_DISABLED si vous avez l'intention de remplacer ces méthodes aussi.
Il semble être une API très inhabituelle qui vous oblige à déclarer les méthodes remplacées que vous voulez appeler. La façon habituelle d'obtenir votre version personnalisée d'un parent est de simplement les remplacer/les implémenter. Peut-être y a-t-il une bonne raison pour ce modèle étrange, mais ce n'est pas un modèle Java que j'ai vu auparavant. Je pense donc qu'il est susceptible de trébucher beaucoup d'auteurs de widgets d'applications. Comme si les widgets de l'application n'étaient pas assez confus sans ce mécanisme.
Un point supplémentaire: L'activité appelée à partir du Widget doit être déclarée dans le fichier manifeste. Aucune exception n'est lancée, On dirait que rien ne se passe...