I have two activities: one is the main (A), and the second one which is started from A (B). I start B with startActivityForResult(intent, id).
I know I can send the result back to A via the setResult() method, but as far as I know, the result isn't sent until finish() is called. I need to send data from B to A without closing B (even several times before closing). Is there a way to achieve that?
As far as I've read, there are not many options to achieve this. I could use SharedPreferences but then I'd need also some kind of event to inform A that it has to read a value!
Any ideas appreciated.
------ FINAL SOLUTION ------
Finally I got it thanks to #Nathaniel Waggoner's advice. Here's what I did:
Inside my activity I declared the extension of BroadcastReceiver:
class ActivityBroadcast extends BroadcastReceiver {
#Override
public void onReceive(final Context context, final Intent intent) {
final String txt2send = intent.getStringExtra("txt2send");
if ((txt2send != null) && (!txt2send.isEmpty())) {
// Do the needed stuff
...
}
}
}
So now I declared the ActivityBroadcast instance in my class and initialized it:
private static ActivityBroadcast broadcast_signal;
broadcast_signal = new ActivityBroadcast();
The way I control that it's just my Intent the one who triggers the onReceive method is with an IntentFilter set to the SENDTXT2SOCK customized action, this way:
// CustomActions.SENDJOIN2CHAN is just a constant from a customized public class
// where I define my own constants to not interfere with the "official" ones
registerReceiver(broadcast_signal, new IntentFilter(CustomActions.SENDTXT2SOCK));
This way I'm saying that on broadcast_signal will just be registered the CustomActions.SENDTXT2SOCK action, so any other is ignored. Now we just have to send a signal from the desired activity to that receiver:
final Intent intentResult = new Intent(CustomActions.SENDTXT2SOCK);
intentResult.putExtra("txt2send", "blabla");
sendBroadcast(intentResult);
And that's all, works like a charm!
Use broadcasts and intents.
Broadcast Receivers:
http://developer.android.com/reference/android/content/BroadcastReceiver.html
You can also give a shot to OnsharedPreferenceChangelistner
you can use eventBus simple library.
first register eventbus in receiver activity
#Override
public void onStart() {
super.onStart();
EventBus.getDefault().register(this);
}
then set a subscriber method
#Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(MessageEvent event) {/* Do something */};
then in other activity post your entity like this
EventBus.getDefault().post(new MessageEvent());
You can use broadcasts and observers to call a method of one activity from another activity. You will use an intent to call a broadcast from activity B, and then you will use an observer to call a method in activity A from the broadcast.
For example, if you want to call ActivityA.someMethod from ActivityB, you can do the following (don't forget implements Observer on ActivityA):
public class ActivityA extends AppCompatActivity implements Observer{
//This is the method you want to call from ActivityB
public void someMethod(Intent intent){
//intent will be the Intent object created in ActivityB, you can pass data to this method by setting extras in the intent
}
//Define the observer and broadcast receiver classes
private static class MyObservable extends Observable{
private static final MyObservable instance = new MyObservable();
public void updateValue(Object data){
synchronized(this){
setChanged();
notifyObservers(data); //This method calls ActivityA.update
}
}
}
public static class MyBroadcastReceiver extends BroadcastReceiver{
//This class must be public and static and must be added to the manifest
//To add this class to the manifest in Android Studio put the cursor on the name of the class, press Alt+Enter and choose "Add to manifest"
#Override
public void onReceive(Context context, Intent intent){ //This method will be called when the broadcast is sent from ActivityB
MyObservable.instance.updateValue(intent);
}
}
//Connect the observer to the activity in the onCreate method
#Override
protected void onCreate(Bundle savedInstanceState){
MyObservable.instance.addObserver(this);
//Do everything else in onCreate as usual
}
//This method will be called when the notifyObservers method is called from the oberver
#Override
public void update(Observable observable, Object data){
this.someMethod((Intent) data); //Call the method that you need
}
}
public class ActivityB extends AppCompatActivity{
public void callSomeMethodOnActivityB(){
Intent intent = new Intent(this, ActivityA.MyBroadcastReceiver.class);
//Add some extras to the intent to pass data
sendBroadcast(intent); //Calls ActivityA.MyBroadcastReceiver.onReceive
}
}
Most of this answer is based on ilw's answer to "Communication between BroadcastReceiver and Activity", credits to them.
Related
I want to call a custom method in a class which can be passed in Intent. In the receiver side of Intent, I want to call my custom method of the class. Lets say I have a class extends ResultReceiver which two methods
class MyClass extends ResultReceiver {
public doBefore(){ //custom method
Log.d("sdf","before");
}
public doAfter(){ // custom method
Log.d("sdf","After");
}
#Override
public void onReceiveResult(final int resultCode, final Bundle resultData) {
}
}
I want to pass the MyClass in the Intent to another Activity or Service. So Lets say i am passing the MyClass to a service
MyClass mcl = new MyClass()
final Intent intent = new Intent(mContext, MyService.class);
intent.putExtra(INTENT_EXTRA_RECEIVER, mcl);
In MyService class, I get the intent in onHandleIntent() method.
Method in MyService Class
#Override
protected void onHandleIntent(Intent intent) {
MyClass eval = (MyClass) intent.getParcelableExtra(INTENT_EXTRA_RECEIVER);
eval.doBefore(); // Is this possible??
eval.doAfter();
sendSuccess(intent, null);
}
Now I want to execute the two methods in the of the class "MyClass". onReceiveResult() in the "MyClass" is called at the end but I am not able to call my custom method. I dont want to start an activity or service. I want to my custom method to be executed.
Is there anyway I can call my custom method from the Service or Activity like ResultReceiver's onReceiveResult().??
I am not sure if I understand your question properly, because it seem confusing that you try to access through your intent calls. Would it not be possible to simply do like below?
mcl.doBefore();
In my Android application, I have a simple list view with adapter. There's a heavy query which is to fill the list view with data. So I put it to an IntentService that runs in another thread.
The IntentService is normally running separately, on its own, just to query some data and insert it into the SQLite database.
But now I would like to have the following possibility:
The activity starts the IntentService with startService().
The IntentService does its heavy work.
When the IntentService is finished, it should inform the activity about the result so that the activity can be refreshed to show the new data.
Is this possible? I read a lot of questions here on Stack Overflow on this topic. But in every question, there was another solution. So I want to ask you all: Which solution is the best for my purpose?
Binding the IntentService to the Activity does not seem to be the best solution as there might be conflicts with configuration changes of the activity etc. Correct?
This blog post suggests using AIDL with Parcelables - which sounds very complex to me. There is an easier way, isn't it?
One could set up a broadcast receiver in the activity and fire this broadcast in the IntentService when it is finished.
Some people say you should use createPendingResult() to pass a PendingIntent to the IntentService. If the IntentService finds that PendingIntent in its extras, it uses this to trigger off onActivityResult() in the Activity. Is this the way to choose?
As an example, I use a ResultReceiver to call notifyDataSetChanged() on the adapter of my Activity (which extends ListActivity). It can be adapted to do whatever you need.
ResultReceiver code:
public class MyResultReceiver extends ResultReceiver {
private Context context = null;
protected void setParentContext (Context context) {
this.context = context;
}
public MyResultReceiver(Handler handler) {
super(handler);
}
#Override
protected void onReceiveResult (int resultCode, Bundle resultData) {
// Code to process resultData here
((BaseAdapter) ((ListActivity)context).getListAdapter()).notifyDataSetChanged();
}
}
MyActivity code:
public class MyActivity extends ListActivity {
private MyResultReceiver theReceiver = null;
...
private void callService () {
theReceiver = new MyResultReceiver(new Handler());
theReceiver.setParentContext(this);
Intent i = new Intent("com.mycompany.ACTION_DO_SOMETHING");
// Code to define and initialize myData here
i.putExtra("someData", myData);
i.putExtra("resReceiver", theReceiver);
startService(i);
}
}
IntentService code:
Bundle resultBundle = new Bundle();
ResultReceiver resRec = intent.getParcelableExtra("resReceiver");
// Do some work then put some stuff in resultBundle here
resRec.send(12345, resultBundle);
When the IntentService completes, it should use LocalBroadcastManager to send an intent to any registered activity.
The IntentService will contain code like this:
private void sendBroadcast() {
Intent intent = new Intent("myBroadcastIntent");
intent.putExtra("someName", someValue);
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
}
The activity receiving the notification will contain code like this:
#Override
protected void onCreate(Bundle savedInstanceState) {
// ...
BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String someValue = intent.getStringExtra("someName");
// ... do something ...
}
};
LocalBroadcastManager.getInstance(this)
.registerReceiver(receiver, new IntentFilter("myBroadcastIntent"));
}
For more depth, see the blog post Using LocalBroadcastManager In Service To Activity Communications.
None of the other answers references the official android documentation
https://developer.android.com/training/run-background-service/report-status.html
that states clearly that for the Activity-IntentService communication "The recommended way to send and receive status is to use a LocalBroadcastManager, which limits broadcast Intent objects to components in your own app"!
I would suggest using a Broadcast Receiver in the The Activity waiting for the result.
Your Service would just use sendBroadcast with a custom Intent.
I think the event bus is the way to go. Simple and effective interprocess communication.
http://square.github.io/otto/
https://github.com/greenrobot/EventBus
I have an Activity that calls a Broadcast Receiver. The Broadcast Receiver waits and listens to GPS. When the listener gets the new point I want to send that new point to Activity. How can I send data from Broadcast Receiver to Activity?
I need a listener in my Activity waiting for response from Broadcast Receiver. How can I do that?
You can call the receiver from your activity. If you don't want to add the logic of the receiver in you activity you can use an abstract receiver.
You abstract receiver:
public abstract class SmsReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
//Add you receiver logic here
...
...
onNewPosition();
}
protected abstract void onNewPosition();
}
In your activity:
public class MyActivity extends Activity {
private smsReceiver smsReceiver;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.map_one_position);
smsReceiver = new smsReceiver() {
// this code is call asyncrously from the receiver
#Override
protected void onNewPosition() {
//Add your activty logic here
}
};
IntentFilter intentFilter = new IntentFilter("android.provider.Telephony.SMS_RECEIVED");
intentFilter.setPriority(999);
this.registerReceiver(smsReceiver, intentFilter);
}
#Override
protected void onPause() {
super.onPause();
this.unregisterReceiver(this.smsReceiver);
}
}
I hope it will help you...
I defined a listener for my receiver and use it in activity and it is running perfect now. Is it possible to happen any problem later?
public interface OnNewLocationListener {
public abstract void onNewLocationReceived(Location location);
}
in My receiver class wich is named as ReceiverPositioningAlarm:
// listener ----------------------------------------------------
static ArrayList<OnNewLocationListener> arrOnNewLocationListener =
new ArrayList<OnNewLocationListener>();
// Allows the user to set an Listener and react to the event
public static void setOnNewLocationListener(
OnNewLocationListener listener) {
arrOnNewLocationListener.add(listener);
}
public static void clearOnNewLocationListener(
OnNewLocationListener listener) {
arrOnNewLocationListener.remove(listener);
}
// This function is called after the new point received
private static void OnNewLocationReceived(Location location) {
// Check if the Listener was set, otherwise we'll get an Exception when
// we try to call it
if (arrOnNewLocationListener != null) {
// Only trigger the event, when we have any listener
for (int i = arrOnNewLocationListener.size() - 1; i >= 0; i--) {
arrOnNewLocationListener.get(i).onNewLocationReceived(
location);
}
}
}
and in one of my activity's methods:
OnNewLocationListener onNewLocationListener = new OnNewLocationListener() {
#Override
public void onNewLocationReceived(Location location) {
// do something
// then stop listening
ReceiverPositioningAlarm.clearOnNewLocationListener(this);
}
};
// start listening for new location
ReceiverPositioningAlarm.setOnNewLocationListener(
onNewLocationListener);
you have couple of ways you can do it and several considerations.
you can poll, meaning check every now an again using either Handler
or Timer to see if info has arrived.
you can register the broadcast receiver as an inner class of your activity and then you can call methods in your activty.
you can have the Broadcast send Intent to your class with the info, but if your activity is not in foreground you might bring it there , and that's not 100% what you want...
Regarding some consideration, BroadCastReciver is mainly used as a listener, not notider so inner class, is best practice, in my opinion, for use with Activities, for Services you can use it as a standalone class and register it in the Manifest.xml...
Now you got to remember that when broadcast is being broadcast your Activity might be inactive due to orientation change or event that pauses your app so you might miss the event. i don't listen to system events but to my own events so i use sticky broadcast to prevent that issue.
Just need to implement the broadcast receiver in the activity. register the receiver with activity's context.
I've a simple Main Activity which has to stop till an SMS is received... How can I launch a method from the MainActivity within the BroadcastReceiver's onReceive() Method?
Is there away with Signal and Wait? Can I pass something with a pending Intent, or how can I implement this communication?
Communication from BroadcastReceiver to Activity is touchy; what if the activity is already gone?
If I were you I'd set up a new BroadcastReceiver inside the Activity, which would receive a CLOSE message:
private BroadcastReceiver closeReceiver;
// ...
closeReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
//EDIT: receiving parameters
String value = getIntent().getStringExtra("name");
//... do something with value
finish();
}
};
registerReceiver(closeReceiver, new IntentFilter(CLOSE_ACTION));
Then from the SMS BroadcastReceiver you can send out this action:
Intent i = new Intent(CLOSE_ACTION);
i.putExtra("name", "value"); //EDIT: this passes a parameter to the receiver
context.sendBroadcast(i);
I hope this helps?
I had the exact same problem, I tried using intent but i was unsuccessful
The easiest way to use it would be using static methods and static variables
MainActivity.java
public static void stopsms()
{
/*
some code to stop the activity
*/
}
SMSReceiver.java
at the end call this function
MainActivity.stopsms();
It works amazing if your code does not affect when you use static methods and variables. Let me know if you need any help.
The problem with registering a second receiver within the activity, however, is that it will not be persistent like registering in the manifest... thus, although, this solution may work, will only work if the activity is running in background.
it's easy, use interface like that:
1) in your broadcast receiver create an interface.
public interface ChangeListener{
public void functionWhoSendData(String type);
public void etc();
}
and instantiate that interface in your broadcast receiver, use it:
public void onReceive(....
String data=functionWhereYouReceiveYouData();
ChangeListener.functionWhoSendData(data);
}
And in your activity, make it implements your interface
When i have a broadcastReceiver say android.intent.action.MEDIA_BUTTON and i want to update the current activity's UI without creating a new activity, is there any good practice on this one?
What i know (might not be correct)
1) I can put the BroadcastReceiver in the same class as the activity and call the updateUI function after certain activity
2) Create a ContentObserver?
3) Communicate to a service created by the activity, use aidl. (I dont know how to get the current service if its registered from an activity)
4) Create a custom filter on the broadcastReceiver located on the same class as the activity, and use context.sendBroadcast(msg of custom filter) and in the custom filter call updateUI (same as one but more generic?)
The final flow is it would come from a BroadcastReceiver and ends up updating the UI without renewing the activity (unless the activity is dead?)
Kindly provide links/source code on your how you tackle this kind of problem. Thanks a lot in advance :)
The easiest way to provide this functionality is to put the broadcast receiver in you Activity and bind / unbind it using registerReceiver and unregisterreceiver:
public class MyActivity extends Activity {
private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
MyActivity.this.receivedBroadcast(intent);
}
};
#Override
public void onResume() {
super.onResume();
IntentFilter iff = new IntentFilter();
iff.addAction("android.intent.action.MEDIA_BUTTON");
// Put whatever message you want to receive as the action
this.registerReceiver(this.mBroadcastReceiver,iff);
}
#Override
public void onPause() {
super.onPause();
this.unregisterReceiver(this.mBroadcastReceiver);
}
private void receivedBroadcast(Intent i) {
// Put your receive handling code here
}
}
Depending on the intent you wish to receive, you may need to add the appropriate permissions to your AndroidManifest.xml file.
What I recently had to do to change a Button's text after receiving data from a LocalBroadcastManager is to store the value in a private field and then do the UI stuff in my onResume() method.
public class myClass extends Activity {
private String myString;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// register to receive data
LocalBroadcastManager.getInstance(getActivity()).registerReceiver(receiver, new IntentFilter("myAction"));
}
private BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// get the extra data included in the intent
myString = intent.getStringExtra("myString");
}
};
#Override
public void onResume() {
super.onResume();
System.out.println("onResume");
// do something to the UI
myButton.setText(myString != null ? myString : "Default");
}
}