【问题标题】:How to update the UI of Activity from BroadCastReceiver如何从 BroadCastReceiver 更新 Activity 的 UI
【发布时间】:2014-08-09 06:27:15
【问题描述】:

我正在学习Android 概念ActivityBroadCastReceiver。我想从BroadtCastReceiver 更新Activity 的内容,两者都在不同的java 类中。

有点像

MyActivity.javaMyBroadtCastReceiver.java

这可能在 Android 中做到这一点吗?

【问题讨论】:

  • 让您的BroadcastReceiver 成为您的Activity 的内部类。
  • @Squonk 不,我不想有一个内部类。我有类似 MyActivity.java 和 MyBroadtCastReceiver.java 的东西。有没有办法做到这一点?
  • OK 一些要点/问题... 1. 你为什么不想要一个内部类? 2.你打算如何注册接收器? 3.如果接收者没有被Activity注册,你怎么知道Activity在接收广播时是否真的存在? 4. 通常,答案是 - 不,您不能以任何可靠的方式从Activity 之外执行此操作,Activity 可能存在也可能不存在,即使它存在也将处于不确定状态(运行、暂停、停止等等)。将接收器作为内部类是唯一有保证的方法。

标签: android android-activity broadcastreceiver


【解决方案1】:

BroadcastReceiver 可以以多种方式使用,但是当涉及到像更新Activity 的 UI 组件这样特定的事情时,在它自己的 Java 类文件中声明/定义 BroadcastReceiver 几乎没有优势.

推理 - BroadcastReceiver 必须先有一些 Activity 的“知识”以及更新 UI 需要做什么。实际上,BroadcastReceiverActivity 本身绑定在一起,将其声明/定义为内部类是有意义的。

另一个重要方面是Activity 需要处于“运行”(即可见)状态,以保证 UI 组件的操作。在这种情况下,在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(...) 方法应该尽可能简单。它调用的任何方法也应该尽可能轻量级......进入,做你的事情,离开然后等待下一次广播。如果更新 UI 需要一些时间(例如,可能通过重新查询数据库以获取大量数据来更新 ListView),请考虑调用异步执行的代码(例如 AsyncTask)。李>

【讨论】:

  • +1 感谢有帮助。在这里我们可以使用LocalBroadCastManager 来完成相同的任务吗?
  • 在activity被销毁时是否会导致任何泄漏,因为Broadcast Receiver是activity中的一个内部类。
  • 重要的是还要提到您不应该从BroadcastReceiver 启动长时间运行的后台线程。请参阅 Effects 进程状态 下的此处:developer.android.com/guide/components/broadcasts.html
  • 快速说明:registerReceived 对我不起作用。我用过:LocalBroadcastManager.getInstance(this).registerReceiver(mReceiver, new IntentFilter(Constants.BROADCAST_ACTION));
【解决方案2】:

是的,这是可能的。这就是我所做的。 我类从(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);

【讨论】:

    【解决方案3】:

    在您的活动中注册一个新的 BroadcastReceiver 对象,其意图过滤器与您的 MyBroadtCastReceiver 相同。由于 BroadcastReceiver 和 MyBroadtCastReceiver 具有相同的意图过滤器,因此它们的 onReceive() 都将被调用。您想在 Activity 中进行的任何更新都可以在 BroadcastReceiver 的 onReceive 中完成。

    【讨论】:

      【解决方案4】:
      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          
          }
      }  
      
      }
      

      【讨论】:

        【解决方案5】:

        Squonk-s 回答仅在活动当前处于活动状态时才有效。 如果您不想在其他 Activity 中声明/定义您的 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 秒,但您自己决定。

        【讨论】:

          【解决方案6】:

          试试这样可能对你有帮助。

          在要更新ui的activity的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"));
          

          在您要更新 ui 的位置定义此操作,

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

          【讨论】:

          • 还要检查,要更新ui的活动是否在顶部
          • 是否需要处理activity是否存在?
          • 是的,因为如果活动没有运行,那么您将无法访问其资源
          • 来自getRunningTasks() 的文档:注意:此方法仅用于调试和呈现任务管理用户界面。这绝不应该用于应用程序中的核心逻辑,例如根据此处找到的信息来决定不同的行为。此类用途不受支持,将来可能会中断。例如,如果多个应用程序可以同时主动运行,则出于控制流目的对此处数据的含义所做的假设将是不正确的。
          • @Williams :重新阅读我对您的问题的第一条评论,并在onResume() 中注册接收器,并在您的ActivityonPause() 方法中取消注册。这样,当调用接收者的 onReceive(...) 方法时,您可以保证您的 Activity 处于“运行”状态。为 BroadcastReceiver 提供一个单独的 Java 类,它必须做一些像更新特定 UI 元素一样明确的事情,这没有任何优势。
          猜你喜欢
          • 1970-01-01
          • 2018-02-10
          • 1970-01-01
          • 1970-01-01
          • 2013-01-16
          • 2017-04-30
          • 1970-01-01
          • 1970-01-01
          • 2021-07-27
          相关资源
          最近更新 更多