Problème de context

Et si possible des conseils sur les bonnes pratiques

L'auteur de ce sujet a trouvé une solution à son problème.
Auteur du sujet

Bonjour,

Il y a quelques jours, j'ai eu une problématique à résoudre (3 services différents à regrouper en 1 widget), et depuis je me suis lancé dans le développement d'un appWidget, en java, pour android.

Voilà ce que je veux :

  • Je pose mon widget sur l'écran
  • Il va dans le class qui update
  • Si j'ai une connexion internet, je récupère les données depuis une API (dans un autre thread)
  • J'applique mes nouvelles données sur mon UI (depuis mon autre thread)

Actuellement, voilà ce qu'il se passe :

  • Je choisi de mettre mon widget sur l'écran.
  • Mon widget lance la class qui hérite d'AppWidgetProvider sur la méthod onUpdate()
  • Dans cette méthod onUpdate(), je vérifie que j'ai une connexion internet
    • Si j'ai une connexion internet, je vais dans une classe qui hérite d'AsyncTask pour récupérer mes données
      • Je récupère mes données depuis internet dans le doInBackground()
      • Si ça à marché, dans le onPostExecute(), j'applique les nouveaux textes sur mon UI.
    • J'actualise mon widget

Le problème est le suivant : comment modifier mon layout (un textView) depuis le thread de la classe qui hérite d'AsyncTask, sachant que je n'ai pas de context ?

Voici mon code :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
/*Manifest*/
<application
    android:allowBackup="true"
    android:icon="@drawable/app_icon"
    android:label="@string/app_name" >
    <receiver
        android:name=".TorrentInfoWidget" >
            <intent-filter>
            <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
        </intent-filter>
        <meta-data
            android:name="android.appwidget.provider"
            android:resource="@xml/widget_definition" />
    </receiver>
</application>
1
2
3
4
5
/* Petite partie du widget_layout */
<TextView 
    android:id="@+id/widget_peers_value"
    /*...*/
    android:text="@string/widget_peers_value" />
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
/* La class qui herite d'AppWidgetProvider */
package ovh.krostar.torrentinfo;

import java.util.ArrayList;

import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.AsyncTask;
import android.util.Log;

public class TorrentInfoWidget extends AppWidgetProvider
{

    @Override
    public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds)
    {
        ConnectivityManager connectionManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo networkInfo = connectionManager.getActiveNetworkInfo();
        if (networkInfo == null || networkInfo.isConnected() == false)
        {
            Log.w("ERROR", "Connexion impossible");
            return ;
        }

        new bgThread().execute(Integer.toString(1), "core.get_session_status", "num_peers");
        Log.i("TorrentInfo", "Widget Updated");
    }

    private class bgThread extends AsyncTask<String, Void, String>
    {
        @Override
        protected String doInBackground(String... p)
        {
            int id = Integer.parseInt(p[0]);
            String method = p[1];
            ArrayList<String> params = new ArrayList<String>();
            int nLoop = 0;
            for (String param : p)
            {
                if (nLoop >= 2)
                    params.add(param);
                nLoop++;
            }
            DelugeRPC delugeInfo = new DelugeRPC();
            String delugeResponse = delugeInfo.sendCommand(id, method, params);
            return (delugeResponse);
        }

        @Override
        protected void onPostExecute(String result)
        {
            if (result != null)
            {
                Log.i("RESULT", result);
                //Ici je change la valeur de ma textview
            }
            else Log.i("RESULT", "NULL");
        }
    }

}

Ma classe delugeRPC retourne une chaine de caractères.

J'avais pensé à getView().findViewById(id.widget_peers_value), mais il me dit que je n'ai pas la fonction getView() par-ce que je n'hérite pas d'un module qui me la propose, et idem avec juste findViewById()

Au début, je voulais faire tout directement dans l'onUpdate()

1
2
3
4
5
6
7
8
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget_layout);

int peersInfos = delugeInfo.getPeersInfos();
views.setTextViewText(R.id.widget_peers_value, Integer.toString(peersInfos));

ComponentName myWidget = new ComponentName(context, TorrentInfoWidget.class);
AppWidgetManager manager = AppWidgetManager.getInstance(context);
manager.updateAppWidget(myWidget, views);

Et ça marchait très bien, sauf que je ne peux pas appeler ma classe qui va chercher la donnée sur internet, par-ce que je ne peux pas faire de requètes sur internet depuis mon thread UI…

Je suppose que je ne fais pas les choses comme il faut, si vous voyez des choses crades qui ne se font pas comme ça, et / ou si vous savez comment faire pour ma textView, je suis preneur :)

Cordialement, Krostar.

Édité par Krostar

+0 -0

Tu peux récupérer ton context avec la méthode onEnabled() de ton Widget. Je pense que ce lien sera approprié à la résolution de ton problème. Notamment, n'oublie pas les permissions dans ton AndroidManifest :

1
2
3
4
<intent-filter>
    <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
    <action android:name="android.appwidget.action.APPWIDGET_ENABLED" />
</intent-filter>

Logiquement tu peux faire ton setTextViewText() et toutes tes modifs dans ton onPostExecute() (et c'est la meilleure manière de procéder selon moi) seulement il faut que tu rajoutes l'autorisation suivante dans ton onUpdate() avant de lancer ton bgThread() :

1
2
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);

Édité par anonyme

+0 -0
Vous devez être connecté pour pouvoir poster un message.
Connexion

Pas encore inscrit ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte