web-dev-qa-db-fra.com

Widgets cliquables en android

La documentation du développeur semble avoir échoué ici. Je peux créer un widget statique sans réfléchir, je peux même créer un widget comme le widget d'horloge analogique qui se mettra à jour, cependant, je ne peux pas pour la vie de moi comprendre comment créer un widget qui réagit lorsqu'un utilisateur clique sur il. Voici le meilleur exemple de code que la documentation du développeur donne à ce qu'une activité de widget doit contenir (le seul autre indice étant les démonstrations d'API, qui ne créent qu'un widget statique):

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);
        }
    }
}

à partir de: La Android

Ainsi, il semble que l'intention en attente soit appelée lorsque le widget est cliqué, qui est basé sur une intention (je ne sais pas trop quelle est la différence entre une intention et une intention en attente), et l'intention est pour la classe ExampleActivity . J'ai donc fait de mon exemple de classe d'activité une activité simple qui, une fois créée, créerait un objet mediaplayer et le démarrerait (il ne libérerait jamais l'objet, donc il finirait par planter, voici son code:

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

Cependant, lorsque j'ai ajouté le widget à l'écran d'accueil et que j'ai cliqué dessus, rien n'a joué, en fait, rien n'a joué lorsque j'ai réglé le minuteur de mise à jour à quelques centaines de millisecondes (dans le fichier xml du fournisseur appwidget). De plus, j'ai fixé des points d'arrêt et découvert que non seulement il n'atteignait jamais l'activité, mais aucun point d'arrêt que je fixais ne serait jamais déclenché. (Je n'ai toujours pas compris pourquoi), cependant, logcat semblait indiquer que le fichier de classe d'activité était en cours d'exécution.

Alors, puis-je faire quoi que ce soit pour obtenir un appwidget pour répondre à un clic? Comme la méthode onClickPendingIntent () est la plus proche que j'ai trouvée d'un type de méthode onClick.

Merci beaucoup.

61
Leif Andersen

Tout d'abord, ajoutez une variable statique avec une constante.

public static String YOUR_AWESOME_ACTION = "YourAwesomeAction";

Vous devez ensuite ajouter l'action à l'intention avant d'ajouter l'intention à l'intention en attente:

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

(Où widget.class est la classe de votre AppWidgetProvider, votre classe actuelle)

Vous devez ensuite créer un PendingIntent avec getBroadcast

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

Définissez onClickPendingIntent pour la vue cliquable dans votre widget

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

Ensuite, remplacez la méthode onReceive dans la même classe:

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

Ensuite, répondez à vos pressions de bouton en interrogeant l'intention renvoyée pour votre action dans la méthode onReceive:

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

Et ça devrait le faire!

126
strange quark

Laissez la méthode onUpdate telle qu'elle était et copiez-collez la logique dans pdateAppWidget.

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);
    }
}

PS. PendingIntent est juste une "boîte" pour une intention, qui permet à d'autres applications d'avoir accès et d'exécuter cette intention dans votre application.

1
Mike