从 Android 中的 BroadcastReceiver 调用 Activity 方法

Posted

技术标签:

【中文标题】从 Android 中的 BroadcastReceiver 调用 Activity 方法【英文标题】:Calling a Activity method from BroadcastReceiver in Android 【发布时间】:2014-04-10 02:31:43 【问题描述】:

这里我正在创建一个仅依赖于 Internet 的在线应用程序。

因此,每当出现网络错误时,它都必须通知用户。为此,我创建了一个 BroadcastReciver,它在网络连接丢失(Internet)时接收呼叫。

这一切都完美无缺。现在我需要的是我必须从这个广播接收器调用一个 Activity 方法,我在其中创建了一个警报对话。

我在 stack-overflow.com 上阅读了很多答案,我可以将该方法声明为静态并仅使用 Activity 名称进行调用,

例如MyActivityName.myMethod()

但我不能将我的方法声明为静态,因为我在那里使用警报对话,它在线显示错误,

AlertDialog.Builder alertDialog = new AlertDialog.Builder(this);

不能在静态上下文中使用它

那么,我怎样才能从广播接收器调用 Activity 的方法(不能是静态的且不启动该 Activity)?

我可以从当前正在运行的广播接收器中获取活动(或片段)名称吗?

【问题讨论】:

【参考方案1】:

试试这个代码:

您的网络丢失类的广播接收器类:

public class InternetLostReceiver extends BroadcastReceiver
@Override
public void onReceive(Context context, Intent intent) 
    context.sendBroadcast(new Intent("INTERNET_LOST"));


在你的活动中添加这个来调用广播:

public class TestActivity  extends Activity

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

    registerReceiver(broadcastReceiver, new IntentFilter("INTERNET_LOST"));


BroadcastReceiver broadcastReceiver = new BroadcastReceiver() 
    @Override
    public void onReceive(Context context, Intent intent) 
        // internet lost alert dialog method call from here...
    
;

@Override
protected void onDestroy() 
    super.onDestroy();
    unregisterReceiver(broadcastReceiver);


【讨论】:

感谢您的代码 jay,它运行良好。我在 onReceive() 中添加了用于创建警报对话的代码。只有一个错误存在。每当互联网断开连接时,都会立即创建四个警报对话,而不是一个。 如果打开AlertDialog,请输入if条件,如果打开而不打开另一个。请,如果它的工作比接受我的回答。 AlertDialog.Builder alertDialog = new AlertDialog.Builder(this); alertDialog.setMessage("找不到网络。"); alertDialog.setPositiveButton("检查设置", new DialogInterface.OnClickListener() public void onClick(DialogInterface dialog, int which) ); alertDialog.setNegativeButton("Cancel", new DialogInterface.OnClickListener() public void onClick(DialogInterface dialog, int which) ); alertDialog.show(); 附注:内部BroadcastReceiver 不得与外部BroadcastReceiver 具有相同的意图过滤器。如果他们这样做,您将获得无限循环。 谢谢你节省了我的时间:)【参考方案2】:

接口:将广播接收器和活动代码分开!

您可以创建一个 CallBackListener 接口。该接口将充当BroadcastReceiverActivity 之间的桥梁。

1) 创建回调监听器

interface ConnectionLostCallback

      public void connectionLost();

 

2) 在您的 BroadcastReceiver 中提供ConnectionLostCallback

public class MyBroadcastReceiver extends BroadcastReceiver

     private ConnectionLostCallback listener;

     public MyBroadcastReceiver(ConnectionLostCallback listener )

           this.listener = listener     //<-- Initialze it

     

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

           listener.connectionLost();

     

3) 在您的 Activity 中实现 ConnectionLostCallback 并覆盖该方法

YourActvity extends AppcompatActivity implements ConnectionLostCallback

    // Your Activity related code //
      //    new MyBroadcastReceiver(this);  <-- create instance

    private void showAlertMessage()
       AlertDialog.Builder alertDialog = new AlertDialog.Builder(this);
     


    @Override 
    public void connectionLost()

         showAlertMessage();          //<--- Call the method to shoe alert dialog

    



相关链接:

如果您想知道如何使 BroadcastReceiver 独立于任何 活动即你如何重用相同的广播接收器 不同的活动?然后READ THIS

【讨论】:

如果不能调用构造函数怎么办?例如,使用AlarmManager时,从alarmmanager方法调用广播接收器 如果您想跟踪 wifi 状态变化,情况相同 - 那是在清单级别并且您捕获系统级别的广播。在这种情况下,设置一个监听器【参考方案3】:

在您打开警报对话框的活动中添加一个布尔变量

boolean isDialogOpened = false;

// in broadcast recever check 
if(isDialogOpened) 
    alertDialog();

并用这个替换你的 alertdialog 代码

public void alertDialog() 
    AlertDialog.Builder alertDialog = new AlertDialog.Builder(this);

    alertDialog.setMessage("Network not found.");
    alertDialog.setPositiveButton("Check Setting",
            new DialogInterface.OnClickListener() 
                public void onClick(DialogInterface dialog, int which) 
                
            );
    alertDialog.setNegativeButton("Cancel",
            new DialogInterface.OnClickListener() 
                public void onClick(DialogInterface dialog, int which) 
                
            );

    alertDialog.setOnDismissListener(new OnDismissListener() 
        @Override
        public void onDismiss(DialogInterface dialog) 
            isDialogOpened = false;
        
    );

    alertDialog.setOnCancelListener(new OnCancelListener() 
        @Override
        public void onCancel(DialogInterface dialog) 
            isDialogOpened = false;
        
    );

    alertDialog.show();

【讨论】:

抱歉,您的代码不起作用,在 alertDialog.setonDismissListenet 上告诉我“NoSuchMethodException”【参考方案4】:

将 Activity 的上下文传递给 BroadcastReceiver 的构造函数。

public class ResponseReceiver extends BroadcastReceiver

    MainActivity ma; //a reference to activity's context

    public ResponseReceiver(MainActivity maContext)
        ma=maContext;
    

    @Override
    public void onReceive(Context context, Intent intent) 
        ma.brCallback("your string"); //calling activity method
    


在你的 MainActivity 中

public class MainActivity extends AppCompatActivity 
    ...
    public void onStart()
        ...        
    ResponseReceiver responseReceiver = new ResponseReceiver(this); //passing context
    LocalBroadcastManager.getInstance(this).registerReceiver(responseReceiver,null);
        ...
    

    public void brCallback(String param)
        Log.d("BroadcastReceiver",param);
    

希望对你有帮助

【讨论】:

你试过了吗?我认为这不起作用,因为brCallback 不是AppCompatActivity 的有效消息。当然,你可以降低你的活动,但你最终会耦合。【参考方案5】:

使用 lambdasConsumer 就可以了。

protected void onCreate(Bundle savedInstanceState) 
    ...

    receiver = new LocationBroadcastReceiver((whatever) -> doSomething(whatever));
    registerReceiver(receiver, new IntentFilter("YOUR_MESSAGE"));

doSomething 将是您的 Activity 中的一个方法。

...

class YourBroadcastReceiver extends BroadcastReceiver 

    private Consumer<Whatever> callback;

    public LocationBroadcastReceiver(Consumer<Whatever> callback) 
        this.callback = callback;
    

    @RequiresApi(api = Build.VERSION_CODES.N)
    @Override
    public void onReceive(Context context, Intent intent) 
            
        this.callback.accept(new Whatever());
    

是所有其他的替代品:

将该方法声明为静态并仅使用 Activity 名称进行调用。

除了你解释的,这是一种耦合方式。

将 Activity 的上下文传递给 BroadcastReceiver 的构造函数。

这行不通,因为您想调用不属于AppCompatActivity 的方法。是的,你可能会沮丧,但你最终会与你的活动耦合。

改用另一个广播或本地广播

嗯,你只能通过这种方式传递一堆原语。如果你想传递一个对象怎么办?此外,声明一个新的 BroadcastReceiver 会变得非常冗长,而且可能难以理解。

【讨论】:

【参考方案6】:

与 Vijju 的回答相同,但改用本地广播

public class SampleReceiver extends BroadcastReceiver 

    @Override
    public void onReceive(Context context, Intent intent) 
        Intent intentToBroadcast =  new Intent("YOUR_ACTION_HERE");
        LocalBroadcastManager.getInstance(context).sendBroadcast(intentToBroadcast);
    

在你的活动中添加这个

public class SampleActivity extends Activity 

    @Override
    protected void onResume() 
        super.onResume();
        LocalBroadcastManager.getInstance(this).registerReceiver(mSampleReceiver, new IntentFilter(YOUR_ACTION_HERE));
    

    @Override
    protected void onPause() 
        LocalBroadcastManager.getInstance(this).unregisterReceiver(mSampleReceiver);
        super.onPause();
    

    private SampleReceiver mSampleReceiver = new BroadcastReceiver() 
        @Override
        public void onReceive(Context context, Intent intent) 
            // your code here
        
    ;

注意将注册/取消注册调用移动到 onCreate/onDestroy 是您希望即使您的活动在后台也能收到通知。

【讨论】:

当我想像你一样声明一个变量时:“private SampleReceiver mSampleReceiver = new BroadcastReceiver()”,给我错误,要求类型:SampleReceiver,但提供的是 BroadcastReceiver 尝试用新的 SampleReceiver() 替换新的 BroadcastReceiver()

以上是关于从 Android 中的 BroadcastReceiver 调用 Activity 方法的主要内容,如果未能解决你的问题,请参考以下文章

Android复习

Android 通过广播获取网络状态

从服务更新 UI

BroadcastReceiver

为啥 BroadcastReceiver 需要一个默认构造函数?

android中的java.lang.OutOfMemoryError,同时从android中的画廊获取图像