Как обновить пользовательский интерфейс Activity из BroadCastReceiver

Я учусь Android концепции Activity а также BroadCastReceiver, Я хочу обновить содержание Activity от BroadtCastReceiver оба находятся в разных классах Java.

Это что-то вроде

MyActivity.java а также MyBroadtCastReceiver.java

Возможно ли это сделать в Android?

6 ответов

Решение

BroadcastReceiver можно использовать по-разному, но когда дело доходит до чего-то такого особенного, как обновление компонентов пользовательского интерфейса Activity, есть небольшое преимущество для объявления / определения BroadcastReceiver в своем собственном файле класса Java.

Рассуждение - BroadcastReceiver должен иметь некоторые предварительные "знания" о Activity и что требуется сделать для обновления пользовательского интерфейса. В действительности BroadcastReceiver привязан к Activity сам по себе, и имеет смысл объявить / определить его как внутренний класс.

Другим важным аспектом является Activity должен быть в "работающем" (то есть видимом) состоянии, чтобы гарантировать манипулирование компонентами пользовательского интерфейса. В этом случае регистрация получателя в onResume() и отмена регистрации в onPause() поможет предотвратить проблемы.

Используя общий шаблон, я бы сделал что-то вроде следующего...

class MyActivity extends Activity {

    boolean mIsReceiverRegistered = false;
    MyBroadcastReceiver mReceiver = null;

    // onCreate(...) here

    @Override
    protected void onResume() {

        // Other onResume() code here

        if (!mIsReceiverRegistered) {
            if (mReceiver == null)
                mReceiver = new MyBroadcastReceiver();
            registerReceiver(mReceiver, new IntentFilter("YourIntentAction"));
            mIsReceiverRegistered = true;
        }
    }

    @Override    
    protected void onPause() {
        if (mIsReceiverRegistered) {
            unregisterReceiver(mReceiver);
            mReceiver = null;
            mIsReceiverRegistered = false;
        }

        // Other onPause() code here

    }

    private void updateUI(Intent intent) {
        // Do what you need to do
    }

    private class MyBroadcastReceiver extends BroadcastReceiver {

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

РЕДАКТИРОВАТЬ: пару дополнительных заметок...

  1. Жизненный цикл BroadcastReceiver между входом и выходом onReceive(...), Как только он вернулся из onReceive(...) экземпляр остается в состоянии покоя в ожидании следующей трансляции.
  2. Прямое отношение к пункту 1 - BroadcastReceiver не предназначен для "тяжелой работы". В основном onReceive(...) Метод должен быть максимально простым. Любые методы, которые он вызывает, также должны быть как можно более легкими: входите, делайте свое дело, выходите, затем ждите следующей трансляции. Если обновление пользовательского интерфейса займет некоторое время (возможно, обновление ListView например, повторно запросив базу данных для большого объема данных), рассмотрите возможность вызова кода, который выполняется асинхронно (AsyncTask например).

Да, это возможно. Вот что я делаю. Класс я отправляю трансляцию из (BackgroundActivity.java):

public static final String BROADCAST_BUFFER_SEND_CODE = "com.example.SEND_CODE";

onCreate(){
   bufferIntentSendCode = new Intent(BROADCAST_BUFFER_SEND_CODE);
}

private void sendBufferingBroadcastSendCode() {
   bufferIntentSendCode.putExtra("buffering", "1");
   sendBroadcast(bufferIntentSendCode);
}

Класс, который получит трансляцию (SendCode.java):

onResume(){
        registerReceiver(broadcastBufferReceiver, new IntentFilter(BackgroundActivity.BROADCAST_BUFFER_SEND_CODE));
}

// set up broadcast receiver
private BroadcastReceiver broadcastBufferReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent bufferIntent) {
        SendCode.this.LoadMessages(alarmNumber);
    }
};

Я отменяю регистрацию в onPause

this.unregisterReceiver(broadcastBufferReceiver);
You can do like this:

public class MyActivity extends Activity{

// used to listen for intents which are sent after a task was
// successfully processed
private BroadcastReceiver mUpdateReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        new UpdateUiTask().execute();
    }
};

@Override
public void onResume() {        
    registerReceiver(mUpdateReceiver, new IntentFilter(
            YOUR_INTENT_ACTION));
    super.onResume();
}

@Override
public void onPause() {     
    unregisterReceiver(mUpdateReceiver);
    super.onPause();
}


// used to update the UI
private class UpdateUiTask extends AsyncTask<Void, Void, String> {

    @Override
    protected void onPreExecute() {

    }

    @Override
    protected String doInBackground(Void... voids) {
        Context context = getApplicationContext();
        String result = "test";
        // Put the data obtained after background task. 
        return result;
    }

    @Override
    protected void onPostExecute(String result) {
        // TODO: UI update          
    }
}  

}

Зарегистрируйте новый объект BroadcastReceiver в своей деятельности с теми же фильтрами намерений, что и ваш MyBroadtCastReceiver. Поскольку BroadcastReceiver и MyBroadtCastReceiver имеют одинаковые фильтры намерений, будут вызваны оба их onReceive(). Любое обновление, которое вы хотите сделать в Activity, можно сделать в onReceive вашего BroadcastReceiver.

Ответ Squonk-s работает, только если активность активна в данный момент. Если вы не хотите объявлять / определять свой BroadcastReceiver (BR) в другом действии, или если вы хотите внести некоторые изменения, даже если приложение не является передним планом, то ваше решение будет выглядеть примерно так.

Сначала вы объявляете BR и сохраняете или переопределяете данные, необходимые для отображения в Acitvity.

public class MyBR extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        // override the data. Eg: save to SharedPref
    }
}

Затем в Activity, вы показываете данные

TextView tv = findViewById(R.id.tv);
tv.setText(/*get the data Eg: from SharedPref*/);

И вы должны использовать таймер, чтобы обновить телевизор:

    Timer timer = new Timer();
    timer.schedule(new TimerTask() {
        @Override
        public void run() {
            runOnUiThread(new Runnable() {
                @Override
                 public void run() {
                    TextView tv = findViewById(R.id.tv);
                    tv.setText(/*get the data Eg: from SharedPref*/);
                }
            });
        }
    }, REFRESH_RATE, REFRESH_RATE);

REFRESH_RATE может быть что-то около 1 секунды, но вы решаете.

Попробуй вот так это может тебе помочь.

Определите этот метод в методе oncreate действия, в котором вы хотите обновить интерфейс,

    BroadcastReceiver mMessageReceiver = new BroadcastReceiver() {
                @Override
                public void onReceive(Context context, Intent intent) {
                    //your code to update ui
                }
            };
   LocalBroadcastManager.getInstance(this).registerReceiver(mMessageReceiver, new IntentFilter("giveyourappname"));

Определите это действие там, где вы хотите обновить интерфейс,

try{
        ActivityManager am = (ActivityManager) this .getSystemService(ACTIVITY_SERVICE);
        List<RunningTaskInfo> taskInfo = am.getRunningTasks(1);
        ComponentName componentInfo = taskInfo.get(0).topActivity;
        Log.d("Activity", "Current Activity ::" + taskInfo.get(0).topActivity.getClassName());
        Log.d("Package", "Package Name :  "+ componentInfo.getPackageName());

        if(componentInfo.getPackageName().equals("your application package name")){
             Intent intent = new Intent("giveyourappname");
                //add data you wnat to pass in intent
                LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
        }
    }catch(Throwable e){
        e.printStackTrace();
    }
Другие вопросы по тегам