问题
I have a serious issue about passing data from BroadcastReceiver
to an Activity
. Let see my issue carefully. I have a class PhoneStateReceiver extends BroadcastReceiver
that used to received an incoming phone.
public class PhoneStateReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
try {
System.out.println("Receiver start");
String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
String incomingNumber = intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER);
if(state.equals(TelephonyManager.EXTRA_STATE_RINGING)){
}
}
catch (Exception e){
e.printStackTrace();
}
}
}
The incoming phone will be sent to an Activity
, called ReceiverActivity
. The ReceiverActivity
receives the incoming phone and sends it to a server via a socket connection. The socket connection is initialized in the onCreate
function. I googled and found server way to pass the data from BroadcastReceiver
to an Activity
. The common way is that send data via putExtra
function and call startActivity
. However, the way will call the onCreate
again and then connect the socket, draw the UI again. Thus, it is not helpful in my case.
In my goal, If the phone receives an incoming call, it will send the incoming call to the ReceiverActivity
. The ReceiverActivity
receives the message and calls the send function. Which is the best way to do it? Thank you
The common way to pass data from a BroadcastReceiver
to a ReceiverActivity
that I used as follows
In PhoneStateReceiver class :
Intent intent_phonenum = new Intent(context, ReceiverActivity.class);
intent_phonenum.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent_phonenum.putExtra("phone_num", incomingNumber);
context.startActivity(intent_phonenum);
In ReceiverActivity class :
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
connect_socket();
Intent intent = getIntent();
phone_num = intent.getStringExtra("phone_num");
send(phone_num);
}
回答1:
There is a very simple design pattern you can use here to ease communication between your classes and also decouple your code: publisher/subscriber
. My favorite library for this is EventBus
:
First, add to your build.gradle file:
compile 'org.greenrobot:eventbus:3.0.0'
Then, create a simple POJO - Plain Old Java Object
like this:
public class OnReceiverEvent{
private String phoneNumber;
public OnReceiverEvent(String phone){
this.phoneNumber = phone;
}
public String getPhoneNumber(){
return phoneNumber;
}
}
Next, by making your Receiver
class a publisher
, and your Activity
a subscriber
, you should be able to easily pass the information to your activity like this:
//inside your PhoneStateReceiver class when you want to pass info
EventBus.getDefault().post(new OnReceiverEvent(phoneNumber));
Next, inside your activity, simply do this:
//onStart
@Override
public void onStart(){
super.onStart();
EventBus.getDefault().register(this);
}
//onStop
@Override
public void onStop(){
super.onStop();
EventBus.getDefault().unregister(this);
}
Finally, handle the posted data i.e phoneNumber value:
@Subscribe
public void onPhoneNumberReceived(OnReceiverEvent event){
//get the phone number value here and do something with it
String phoneNumber = event.getPhoneNumber();
//display or something?
}
UPDATE
If you have another Event that you want this activity to subscribe to, simply create a method like you did in the first one using the @Subscribe
annotation.
@Subscribe
public void onSomeOtherEvent(EventClassName event){
//get the variables here as usual;
}
This is the easiest way to pass the data from your receiver to your activity without having to worry about starting the activity over and over!
I hope this helps and good luck!
回答2:
Simple without any third party libs.
Make sure BroadcastReceiver
must be registered and also unregistered on OnPause()
.
You have to do two thing
Register a receiver in you activity like below.
public class MainActivity extends Activity {
Context context;
BroadcastReceiver updateUIReciver;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
context = this;
IntentFilter filter = new IntentFilter();
filter.addAction("service.to.activity.transfer");
updateUIReciver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
//UI update here
if (intent != null)
Toast.makeText(context, intent.getStringExtra("number").toString(), Toast.LENGTH_LONG).show();
}
};
registerReceiver(updateUIReciver, filter);
}
}
Now in you service
public class PhoneStateReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
try {
System.out.println("Receiver start");
String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
String incomingNumber = intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER);
if (state.equals(TelephonyManager.EXTRA_STATE_RINGING)) {
Intent local = new Intent();
local.setAction("service.to.activity.transfer");
local.putExtra("number", incomingNumber);
context.sendBroadcast(local);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
回答3:
So I understand you don't want to recreate your Activity everytime.
In your Intent
changing this flag will help you :
intent_phonenum.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
In Intent class if you read method summary of FLAG_ACTIVITY_CLEAR_TOP
:
- If set, and the activity being launched is already running in the
- current task, then instead of launching a new instance of that activity,
- all of the other activities on top of it will be closed and this Intent
- will be delivered to the (now on top) old activity as a new Intent. (you can read more ...)
In this case: If your app is running and you have an Activity instance then Intent
will not recreate your Activity. But assume that your app is in closed state and when BroadcastReceiver triggered, the Intent
will create new Activity because you don't have instance of that Activity.
@Edit :
You can specify special Intent like that in your BroadcastReceiver
:
public void onReceive(Context context, Intent intent) {
Bundle extras = intent.getExtras();
Intent i = new Intent("mycustombroadcast");
i.putExtra("phone_num", incomingNumber);
context.sendBroadcast(i);
}
Then in your Activity inside onCreate()
register receiver like that :
BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
Bundle bundle = intent.getExtras();
int incoming_number= bundle.getInt("phone_num");
Log.e("incoming number", "" + incoming_number);
}
};
//then register receiver like that :
registerReceiver(broadcastReceiver, new IntentFilter("mycustombroadcast"));
You can unregister Receiver in onDestroy()
: unregisterReceiver(broadcastReceiver);
Also another way is overriding onNewIntent()
in your Activity:
@Override
protected void onNewIntent(Intent intent) {
//your intent is here, you can do sth.
super.onNewIntent(intent);
}
来源:https://stackoverflow.com/questions/38954261/how-to-pass-data-from-broadcastreceiver-to-activity-without-in-oncreate