28

我创建了一个应用程序,在其中我在我的主类()中注册了一个广播接收器Main Activity,每当我在我的主类中收到一些东西时,我BroadcastReceiver都想更新 UI,例如,我想显示一个警报框或设置我的MainActivity. 我收到接收器中的所有值但无法设置它们,有人可以帮助我,以便我可以在BroadcastReceiver.

我的 BroadcastReceiver 类是 MainActivity 的内部类,如下所示:-

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

任何帮助都将是可观的

谢谢

4

12 回答 12

33

我建议你使用处理程序。

  1. 在Activity中初始化一个Handler,例如:handler = new Handler()
  2. 在构造函数中为 BroadcastReceiver 提供处理程序,就像我为上面的 NissanTabBroadcast 所做的那样
  3. 在方法中使用post()你的 Handler 实例的onReceive()方法来提交更新 UI 的 Runnable

这是我能想象到的最干净的解决方案。

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();
                }
            });
        }
    }
}
于 2013-02-01T14:53:49.347 回答
14

如何在任何 Activity 中重用 BroadcastReceiver?

在此处输入图像描述
考虑以下情况,

  • 您想BroadcastReceiver在不同的活动中使用相同的
  • 你已经写BroadcastReceiver在一个单独的文件中,并且想要访问Activity方法、UI 元素等。

在这些情况下,使用接口是一个好主意。我将更详细地解释优势和用例。但首先,让我们看看它是如何完成的。

1) 创建接口

public interface MyBroadcastListener{

    public void doSomething(String value);

}

2) 在您的 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)在你的Activity中实现接口并覆盖方法

 public MainActivity extends AppCompatActivity implements MyBroadcastListener{

      private BroadcastReceiver receiver;

      @Override
      public void onCreate(Bundle sis){

           // Related code 

           receiver = new MyReceiver(this);   // This is how you initialise receiver

          // Register receiver etc
      }


      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
      }

 }

优势和用例?

使用接口方法使 BroadcastReceiver 独立于任何 Activity。假设将来您想将此 BroadCastReceiver 与另一个活动一起使用,该活动从 BroadcastReceiver 获取结果并启动一个 DetailActivity。

请注意,这是一项完全 不同的任务,但您可以使用相同的 BroadcastReceiver,甚至无需更改 BroadcastReceiver 内的任何代码。

怎么做?
简单的!实现接口中的Activity并重写方法。就是这样!

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
      }

}

在此处输入图像描述

于 2019-01-25T11:12:48.560 回答
9

我的案例是更新 MainActivity 托管的片段之一中的文本字段。我找到的最简单的解决方案是:-

在我的 MainActivity 类中检索到 MainActivtiy 的运行实例。这是我的 MAinActivity

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

现在在广播接收者的 onRecieve 方法中,获取该实例并调用更新方法

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

现在对于我们需要在 UIThread 中运行更新的部分,MainActivity 的 updateUI 方法将调用片段更新方法。

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

最后一步是更新片段的文本字段

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

和宾果游戏,它完成了。我参考了这个链接来解决我的问题。希望对其他人有所帮助。

于 2015-08-14T02:22:47.953 回答
6

使用runOnUiThread

 MainActivity.this.runOnUiThread(new Runnable() {

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

        }
    });
于 2013-02-01T09:43:13.097 回答
1

我为此使用了完全不同的方法。通过将处理程序的实例放入意图中,将其传递给广播接收器。比在广播接收器中使用该处理程序向您的活动类发送消息,该活动类在您的自定义处理程序的 onHandleMessage 方法中更新 UI班级。

create handler class like

   public class MyHandler extends Handler{

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

现在使用Myhandler handler=new MyHandler();在活动的全局级别范围内创建此处理程序对象。

现在将此处理程序放入您的意图中putExtra,然后通过发送此意图sendBraodcast(intent)

onReceive()在广播接收器类中,通过 getExtras 获取此处理程序对象并在方法中使用它,如下所示

 handler.sendEmptyMessage();
于 2013-02-01T10:13:56.970 回答
1

我使用 Intent 让 Broadcast Receiver 知道主 Activity 线程的 Handler 实例,并使用 Message 将消息传递给 Main Activity

我已经使用这种机制来检查广播接收器是否已经注册。有时,当您动态注册您的广播接收器并且不想让它两次或者您在广播接收器正在运行时向用户展示时,需要它。

主要活动:

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

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

广播接收器:

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

}

}
于 2013-10-13T18:41:06.380 回答
1

在我的情况下,我想用传入的短信更新我的活动中的文本视图,我所做的是使用 putextra 添加所需的信息,然后从广播接收器开始活动:

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

然后在接收端,即在注册活动中,我使用以下内容提取了该信息并更新了我的 textview:

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

不确定它是否有帮助,但肯定会引导你找到你想要的。

干杯!

于 2015-06-13T20:17:18.933 回答
1

使用 getter 和 setter 可以轻松解决这个问题。

只需如下声明一个类。

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

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

在您的主要活动或片段活动上,创建 DetailsGetters 类的实例。

DetailsGetters newdetailsinstance=new DetailsGetters();

在返回视图调用之前newdetailsinstance.setview(view);

在广播接收器上获取视图为 newdetailsinstance.getview(view);

以下可用于从片段中获取视图并使用 setText 等更新 Ui。

要在主要活动上更新 UI,请传递 Textview 并更改 DeailsGetters 类并为 Textview 创建 getter 和 setter。希望这对某人有所帮助。

于 2017-12-21T07:42:55.227 回答
0

我使用了 Handler 及其 post() 方法。而不是 runOnUiThread()。无需将 Context 转换为 Activity。它是 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();
于 2015-02-26T11:45:55.667 回答
0

您应该将广播接收器作为内部类,这样它就可以访问所有字段来更新 UI。

请参阅 nick butcher Plaid- Nick Butcher(Github) 制作的这款 Plaid 应用程序

于 2017-03-01T11:16:49.247 回答
0

通过广播接收器获取当前日期时间和秒并在 UI 中更新

    package com.keshav.broadcasttest;

    import java.util.Date;

    import android.app.Service;
    import android.content.Intent;
    import android.os.Handler;
    import android.os.IBinder;
    import android.util.Log;

    public class BroadcastService  extends Service {
       private static final String TAG = "BroadcastService";
       public static final String BROADCAST_ACTION = "com.keshav.broadcasttest.displayevent";
       private final Handler handler = new Handler();
       Intent intent;
       int counter = 0;

       @Override
       public void onCreate() {
          super.onCreate();

           intent = new Intent(BROADCAST_ACTION); 
       }

        @Override
        public void onStart(Intent intent, int startId) {
            handler.removeCallbacks(sendUpdatesToUI_Runnable);
            handler.postDelayed(sendUpdatesToUI_Runnable, 1000); // 1 second

        }

        private Runnable sendUpdatesToUI_Runnable = new Runnable() {
           public void run() {
              DisplayLoggingInfo();         
               handler.postDelayed(this, 10000); // 10 seconds
           }
        };    

        private void DisplayLoggingInfo() {
           Log.d(TAG, "entered DisplayLoggingInfo");

           intent.putExtra("time", new Date().toLocaleString());
           intent.putExtra("counter", String.valueOf(++counter));
           sendBroadcast(intent);
        }

       @Override
       public IBinder onBind(Intent intent) {
          return null;
       }

       @Override
       public void onDestroy() {     
            handler.removeCallbacks(sendUpdatesToUI_Runnable);
          super.onDestroy();
       }     
    }
    ============================================

    package com.keshav.broadcasttest;

import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;

public class BroadcastTest extends Activity {
    private static final String TAG = "BroadcastTest";
    private Intent intent;

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

        intent = new Intent(this, BroadcastService.class);
    }

    private BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            updateUI(intent);       
        }
    };    

    @Override
    public void onResume() {
        super.onResume();       
        startService(intent);
        registerReceiver(broadcastReceiver, new IntentFilter(BroadcastService.BROADCAST_ACTION));
    }

    @Override
    public void onPause() {
        super.onPause();
        unregisterReceiver(broadcastReceiver);
        stopService(intent);        
    }   

    private void updateUI(Intent intent) {
        String counter = intent.getStringExtra("counter"); 
        String time = intent.getStringExtra("time");
        Log.d(TAG, counter);
        Log.d(TAG, time);

        TextView txtDateTime = (TextView) findViewById(R.id.txtDateTime);   
        TextView txtCounter = (TextView) findViewById(R.id.txtCounter);
        txtDateTime.setText(time);
        txtCounter.setText(counter);
    }
}
    =============================

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        >
        <TableLayout android:id="@+id/tableGPS"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="7px"
            android:stretchColumns="1">
            <TableRow
                android:layout_margin="1dip">
                <TextView android:layout_gravity="right"
                    android:text="Time:"
                    android:layout_marginRight="7px"
                    android:layout_width="130px" />
                <TextView android:id="@+id/txtDateTime"
                    android:gravity="left"
                    android:layout_span="2" />
            </TableRow>
            <TableRow
                android:layout_margin="1px">
                <TextView android:layout_gravity="right"
                    android:text="Counter:"
                    android:layout_marginRight="7px"
                    android:layout_width="160px" />
                <TextView android:id="@+id/txtCounter"
                    android:gravity="left" />
            </TableRow>
        </TableLayout>
    </LinearLayout>

    ===========================================

    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.keshav.broadcasttest">

        <application
            android:allowBackup="true"
            android:icon="@mipmap/ic_launcher"
            android:label="@string/app_name"
            android:roundIcon="@mipmap/ic_launcher_round"
            android:supportsRtl="true"
            android:theme="@style/AppTheme">
            <activity android:name=".BroadcastTest">
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />

                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>

            <service android:name=".BroadcastService" />
        </application>

    </manifest>
于 2019-03-13T12:42:49.467 回答
0

BroadcastReceiver 的 onReceive() 方法在主线程中运行,因此您可以在此方法中修改 UI,也可以在主线程中运行 onReceive() 避免从这里执行长时间运行的操作。

来自官方文档:

因为接收者的 onReceive(Context, Intent) 方法在主线程上运行,所以它应该快速执行并返回。如果您需要执行长时间运行的工作,请注意生成线程或启动后台服务,因为系统可以在 onReceive() 返回后终止整个进程。有关更多信息,请参阅对进程状态的影响 要执行长时间运行的工作,我们建议:

在接收器的 onReceive() 方法中调用 goAsync() 并将 BroadcastReceiver.PendingResult 传递给后台线程。这在从 onReceive() 返回后保持广播活动。然而,即使采用这种方法,系统仍希望您很快完成广播(不到 10 秒)。它确实允许您将工作转移到另一个线程以避免主线程出现故障。使用 JobScheduler 调度作业。有关详细信息,请参阅智能作业计划。

于 2020-01-04T07:47:08.287 回答