web-dev-qa-db-fra.com

Comment mettre à jour l'interface utilisateur dans un BroadcastReceiver

J'ai créé une application dans laquelle j'ai enregistré un récepteur de diffusion dans ma classe principale (Main Activity) et chaque fois que je reçois quelque chose dans ma BroadcastReceiver, je souhaite mettre à jour l'interface utilisateur, par exemple. Je souhaite afficher un message d’alerte ou définir une vue textuelle de ma MainActivity. Je reçois toutes les valeurs dans mon récepteur mais je ne peux pas les définir. Quelqu'un peut-il m'aider pour mettre à jour mon interface utilisateur dans la variable BroadcastReceiver?.

Ma classe BroadcastReceiver est la classe interne de MainActivity comme ceci: -

public class MainActivity extends Activity {

   ..........

public static class NissanTabBroadcast extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            SharedPreferences shrd = context.getSharedPreferences("NissanGallery", context.MODE_WORLD_READABLE);
            type = shrd.getString("type", "null");
            badges = shrd.getString("badge_count", "null");

            //badge_tips_text.setText(badges);
            /*Editor edit =  shrd.edit();
            edit.remove("type");*/

            Toast.makeText(context, "" + type + "\n" + badge_tips_text.getText().toString(), Toast.LENGTH_LONG).show();
        }
    }
}

Toute aide sera appréciable

Merci

22
Salman Khan

Je vous suggère d'utiliser un gestionnaire.

  1. Initialiser un gestionnaire dans l'activité, exemple: handler = new Handler()
  2. Fournissez le gestionnaire à BroadcastReceiver dans le constructeur, comme je l'ai fait pour NissanTabBroadcast ci-dessus
  3. Utilisez la méthode post() de votre instance de gestionnaire dans la méthode onReceive() pour soumettre le fichier Runnable qui met à jour l'interface utilisateur.

C’est la solution la plus propre que je puisse imaginer.

public class MainActivity extends Activity {

    private MyReceiver receiver;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        receiver = new MyReceiver(new Handler()); // Create the receiver
        registerReceiver(receiver, new IntentFilter("some.action")); // Register receiver

        sendBroadcast(new Intent("some.action")); // Send an example Intent
    }

    public static class MyReceiver extends BroadcastReceiver {

        private final Handler handler; // Handler used to execute code on the UI thread

        public MyReceiver(Handler handler) {
            this.handler = handler;
        }

        @Override
        public void onReceive(final Context context, Intent intent) {
            // Post the UI updating code to our Handler
            handler.post(new Runnable() {
                @Override
                public void run() {
                    Toast.makeText(context, "Toast from broadcast receiver", Toast.LENGTH_SHORT).show();
                }
            });
        }
    }
}
31
allprog

Mon cas était de mettre à jour le champ de texte dans l'un des fragments hébergés par MainActivity.La solution la plus simple que j'ai trouvée était la suivante: -

Dans ma classe MainActivity, j'ai récupéré l'instance active de MainActivtiy. C'est ma MAinActivity.

private static MainActivity mainActivityRunningInstance;
    public static MainActivity  getInstace(){
        return mainActivityRunningInstance;
    }
  @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mainActivityRunningInstance =this;
----------
}

Maintenant, dans la méthode onRecieve de Broadcast reciever, récupérez cette instance et appelez la méthode update

 @Override
    public void onReceive(Context context, Intent intent) {
        if (intent.getAction().matches(Intents.PROVIDER_CHANGED_ACTION)) {
                String textValue="the text field value";
// the null check is for, if the activity is not running or in paused state, in my case the update was required onlyif the main activity is active or paused
            if(MainActivity.getInstace()!=null)
                MainActivity.getInstace().updateUI(textValue);
}

Maintenant pour la partie où nous devons exécuter la mise à jour dans UIThread, la méthode updateUI de MainActivity appellera la méthode de mise à jour des fragments.

  public void updateUI(final String str) {
        MainActivity.this.runOnUiThread(new Runnable() {
            public void run() {
     //use findFragmentById for fragments defined in XML ((SimpleFragment)getSupportFragmentManager().findFragmentByTag(fragmentTag)).updateUI(str);
            }
        });
    }

et la dernière étape met à jour le champ de texte du fragment

public void updateUI(String str){
        tv_content.setText(str);
    }

et Bingo, c'est fait. J'ai référé this link pour résoudre mon problème. J'espère que ça aidera les autres.

8
Nicks

Utilisez runOnUiThread:

 MainActivity.this.runOnUiThread(new Runnable() {

        @Override
        public void run() {
            // show alert

        }
    });
6
Nermeen

Comment réutiliser BroadcastReceiver dans n'importe quelle activité?

 enter image description here
Considérez les situations

  • Vous voulez utiliser la même BroadcastReceiver dans différentes activités
  • Vous avez écrit BroadcastReceiver dans un fichier séparé et souhaitez accéder aux méthodes Activity, aux éléments de l'interface utilisateur, etc. 

Dans ces cas, l'utilisation d'une interface est une excellente approche. J'expliquerai l'avantage et un cas d'utilisation plus en détail. Mais d'abord, voyez comment ça se passe.

1) Créer une interface 

public interface MyBroadcastListener{

    public void doSomething(String value);

}

2) Initialiser le récepteur dans votre BroadcastReceiver 

public class MyReceiver extends BroadcastReceiver {

    private MyBroadcastListener listener;

    public MyReceiver(MyBroadcastListener listener){
        this.listener = listener;
    }

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

        listener.doSomething("Some Result");

    }
}

3) Implémentez l'interface dans votre activité et remplacez la méthode

 public MainActivity extends AppCompatActivity implements MyBroadcastListener{

      // Your Activity code 

      public void updateUI(String msg) {
           TextView textView = (TextView) findViewById(R.id.textView);
           textView .setText(msg);
      }

      @Override
      public void doSomething(String result){
           updateUI(result);        // Calling method from Interface
      }

 }

Avantage et cas d'utilisation?

L'utilisation de l'interface rend BroadcastReceiver indépendant de tout Activity. Disons à l'avenir que vous souhaitez utiliser cette BroadCastReceiver avec une autre activité qui prend le résultat de BroadcastReceiver et lancez DetailActivity avec le résultat. C'est un complètement tâche différente mais vous utiliserez la même BroadcastReceiver sans même changer le code dans la BroadcastReceiver.

Comment faire ça?
Simple! Implémentez l'interface dans les variables Activity et Override. C'est tout!

public ListActivity extends AppCompatActivity implements MyBroadcastListener{

      // Your Activity code goes here

     public void startDetailActivity(String title) {
         Intent i = new Intent(ListActivity,this, DetailActivity.class);
         i.putExtra("Title", title);
         startActivity(i);
     }

      @Override
      public void doSomething(String result){
           startDetailActivity(String title);    // Calling method from Interface
      }

}

 enter image description here

1
Rohit Singh

J'utilise une approche complètement différente pour cela.Passer l'instance de gestionnaire pour émettre le destinataire en le mettant dans l'intention.Than récepteur a utilisé ce gestionnaire pour envoyer un message à votre classe d'activité qui met à jour l'interface utilisateur de votre méthode onHandleMessage de votre gestionnaire personnalisé classe.

create handler class like

   public class MyHandler extends Handler{

onHandlerMessage(Message msg){//do whatever you want here after broadcast get fired}
}

maintenant, utilisez Myhandler handler=new MyHandler(); créer cet objet de gestionnaire sur la portée de niveau global en activité.

Maintenant, mettez ce gestionnaire dans votre intention par putExtra et envoyez ensuite cette intention via sendBraodcast(intent).

dans la classe de récepteur de diffusion, obtenez cet objet de gestionnaire par getExtras et utilisez-le comme ci-dessousin onReceive() 

 handler.sendEmptyMessage();
1
kaushal trivedi

L'utilisation de getters et de setters peut facilement résoudre ce problème.

déclarez simplement une classe comme suit.

public class DetailsGetters {
    private View view;
    public View getview() {
        return view;
    }

    public void setview(View view) {
        this.view = view;
    }
}

Dans votre activité principale ou dans votre activité de fragment, créez une instance de la classe DetailsGetters. 

DetailsGetters newdetailsinstance=new DetailsGetters();

Avant de reprendre la vue callnewdetailsinstance.setview(view);

Sur le récepteur de diffusion, obtenez la vue sous le nom newdetailsinstance.getview(view);

La suite peut être utilisée pour obtenir une vue du fragment et mettre à jour Ui en utilisant setText et ainsi de suite.

Pour mettre à jour l'interface utilisateur de l'activité principale, passez Textview, changez la classe DeailsGetters et créez des accesseurs et des passeurs pour Textview. J'espère que cela aide pour quelqu'un.

1
Elaiya

J'ai utilisé Intention pour informer Broadcast Receiver de l'instance de gestionnaire du fil d'activité principal et ai utilisé Message pour transmettre un message à l'activité principale.

J'ai utilisé un tel mécanisme pour vérifier si Broadcast Receiver est déjà enregistré ou non. Parfois, cela est nécessaire lorsque vous enregistrez votre récepteur de radiodiffusion de manière dynamique et que vous ne voulez pas le faire deux fois, ou que vous présentez à l'utilisateur si le récepteur de diffusion est en cours d'exécution.

Activité principale:

public class Example extends Activity {

private BroadCastReceiver_example br_exemple;

final Messenger mMessenger = new Messenger(new IncomingHandler());

private boolean running = false;

static class IncomingHandler extends Handler {
    @Override
    public void handleMessage(Message msg) {
        running = false;    
        switch (msg.what) {
        case BroadCastReceiver_example.ALIVE:
    running = true;
            ....
            break;
        default:

            super.handleMessage(msg);
        }

    }
    }

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

    IntentFilter filter = new IntentFilter();
        filter.addAction("pl.example.CHECK_RECEIVER");

        br_exemple = new BroadCastReceiver_example();
        getApplicationContext().registerReceiver(br_exemple , filter); //register the Receiver
    }

// call it whenever you want to check if Broadcast Receiver is running.

private void check_broadcastRunning() {    
        /**
        * checkBroadcastHandler - the handler will start runnable which will check if Broadcast Receiver is running
        */
        Handler checkBroadcastHandler = null;

        /**
        * checkBroadcastRunnable - the runnable which will check if Broadcast Receiver is running
        */
        Runnable checkBroadcastRunnable = null;

        Intent checkBroadCastState = new Intent();
        checkBroadCastState .setAction("pl.example.CHECK_RECEIVER");
        checkBroadCastState .putExtra("mainView", mMessenger);
        this.sendBroadcast(checkBroadCastState );
        Log.d(TAG,"check if broadcast is running");

        checkBroadcastHandler = new Handler();
        checkBroadcastRunnable = new Runnable(){    

            public void run(){
                if (running == true) {
                    Log.d(TAG,"broadcast is running");
                }
                else {
                    Log.d(TAG,"broadcast is not running");
                }
            }
        };
        checkBroadcastHandler.postDelayed(checkBroadcastRunnable,100);
        return;
    }

.............
}

Récepteur de diffusion:

public class BroadCastReceiver_example extends BroadcastReceiver {


public static final int ALIVE = 1;
@Override
public void onReceive(Context context, Intent intent) {
    // TODO Auto-generated method stub
    Bundle extras = intent.getExtras();
    String action = intent.getAction();
    if (action.equals("pl.example.CHECK_RECEIVER")) {
        Log.d(TAG, "Received broadcast live checker");
        Messenger mainAppMessanger = (Messenger) extras.get("mainView");
        try {
            mainAppMessanger.send(Message.obtain(null, ALIVE));
        } catch (RemoteException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    .........

}

}
1
jarek

Dans mon cas, je souhaite mettre à jour le texte dans mon activité avec les SMS entrants. Ce que j'ai fait a été ajouté avec les informations requises à l'aide de putextra, puis a démarré l'activité depuis le récepteur de radiodiffusion: 

Intent intentone = new Intent(context.getApplicationContext(), enroll.class);
intentone.putExtra("pinbody",message);
intentone.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intentone);    

Et puis, du côté du destinataire, c’est-à-dire que lors de l’inscription, j’ai extrait cette information à l’aide de ce qui suit et a mis à jour mon textview:

Bundle extras = getIntent().getExtras();
String message = extras.getString("pinbody");

Je ne sais pas si cela aide, mais cela vous mènera à ce que vous voulez. 

À votre santé ! 

1
Srinivas Kumar

Vous devez définir Broadcast receiver comme classe interne, de cette manière, il aura accès à tous les champs pour mettre à jour l'interface utilisateur.

Voir cette application Plaid par Nick Butcher Plaid- Nick Butcher (Github)

0
Uzair

J'ai utilisé Handler & sa méthode post (). Au lieu de runOnUiThread (). Pas besoin de convertir le contexte en activité. C'est une alternative à runOnUiThread ()

Handler handler = new Handler();
Runnable runnable = new Runnable() {
    private long startTime = System.currentTimeMillis();
    public void run() {
        while (gameState == GameState.Playing) {  
            try {
                Thread.sleep(1000);
            }    
            catch (InterruptedException e) {
                e.printStackTrace();
            }
            handler.post(new Runnable(){
                public void run() {
                   tvTime.setText("" + ((System.currentTimeMillis() - this.startTime) / 1000));
            }
        });
        }
    }
};
new Thread(runnable).start();
0
Pavan Pyati