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();
Related
In my public class BluetoothLeService extends Service, I have the following code:
private void updateTimeValues(BluetoothGattCharacteristic characteristic) {
TextView time = (TextView) findViewById(R.id.time);
time.setText(R.string.time);
findViewById is undefined for the type BluetoothLeService. I know that the function is declared in the Activity class but how do I implement the function without extending the Activity class.
I am a novice in Android development so please detail as possible your answer :)
Thanks!
That's correct. Service doesn't have ui. From the documentation
A Service is an application component that can perform long-running
operations in the background and does not provide a user interface.
you could use a LocalBroadcastManager to communicate with the Activity whose started the Service in order to update the UI
As you will not be able to access the textView directly from the service, you need to create a broadcast receiver in the activity.
In your service, call this onCreate
myBroadcast = LocalBroadcastManager.getInstance(this);
Now in your updateTimeValues() use myBroadcast:
Intent intent = new Intent("myNewBroadcastIntent");
intent.putExtra("newtime", "//value you want to send");
myBroadcast.sendBroadcast(intent);
Now create receiver in the onCreate of your mainActivity as follows:
myReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String s = intent.getStringExtra("newtime");
//now you can set it to the textView
}
};
And register it onStart as:
LocalBroadcastManager.getInstance(this)
.registerReceiver((myReceiver),new IntentFilter("myNewBroadcastIntent"));
And unregister onStop as :
LocalBroadcastManager.getInstance(this).unregisterReceiver(myReceiver);
super.onStop();
Hope this helps!
I'm trying to get push notification working in my Android app, using parse.com's push notification service. They implement a Broadcast receiver, which I am extending in my own class:
public class MyPushBroadcastReceiver extends ParsePushBroadcastReceiver
{
#Override
protected void onPushReceive(Context context, Intent intent)
{
JSONObject data = getDataFromIntent(intent);
[...]
super.onPushReceive(context, intent);
}
#Override
protected void onPushOpen(Context context, Intent intent)
{
ParseAnalytics.trackAppOpenedInBackground(intent);
Intent i = new Intent(context, MyActivity.class);
i.putExtras(intent.getExtras());
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(i);
}
}
I'm over-riding two methods:
onPushReceive - this is called when a notification arrives
onPushOpen - this is called when the user clicks on a notification in the notification area
There are three things I need to do:
When a notification arrives, I need to save it
When the user clicks on a notification, I need to open the app to an activity that displays the notifications I've saved
If a notification arrives while I have the app open to the display notifications activity, I need to update the UI to include the new activity.
The first part was easy. I'm just writing some JSON to a file.
The second I've had no trouble with. I create an intent, and that opens my activity. It reads the JSON from the file, and Bob's your uncle.
I've not been able to find a clean way of handling the third part.
I think where I'm stuck is that I haven't a clear understanding of the lifecycle of Activities or BroadcastServices. I'm not creating either, in my app, they're declared in the manifest, and constructed whenever.
Does the Android framework create one of each, as it processes the manifest? Is it possible for an activity to find the instance of the BroadcastReceiver? If I could, it'd be easy enough for me to wire up a callback between them.
Or do I need to define my own BroadcastService, that the ParsePushBroadcastReceiver would use to publish events, and that the activity would consume? The examples I've seen on doing that seem excessively complicated for what should be a fairly simple thing.
Help would be appreciated.
The suggestion on using a static variable got me thinking, and I think I've found a workable solution.
There may be multiple instances of an Activity, but only one can be active at any time.
I spent some time playing around with setting various flags on the Intent I'd pass to startActivity(), and didn't like any of the behaviors I'd see. (Some combinations would crash, some would create multiple entries in the stack so that the back button returned you to an older instance of the activity, all of them created visual effects as the old activity was replaced by the new.)
So, why not create a static field that points to the currently active Activity?
public class MyActivity extends Activity implements ReceiveNotifications
{
public static ReceiveNotifications notificationReceiver = null;
#Override
protected void onResume()
{
super.onResume();
NotificationsActivity.notificationReceiver = this;
updateMessages();
}
#Override
protected void onPause()
{
NotificationsActivity.notificationReceiver = null;
super.onPause();
}
#Override
public void notificationReceived()
{
updateMessages();
}
private void updateMessages()
{
[...]
}
}
Whenever an instance of MyActivity is active, the static variable notificationReceiver will point to it. Of course, I'm using an interface to control how much of MyActivity is visible through that variable:
public interface ReceiveNotifications
{
void notificationReceived();
}
Then, when we receive a notification, if notificationReceiver is not null, we call notificationReceived():
public class MyPushBroadcastReceiver extends ParsePushBroadcastReceiver
{
#Override
protected void onPushReceive(Context context, Intent intent)
{
JSONObject data = getDataFromIntent(intent);
[...]
super.onPushReceive(context, intent);
if (MyActivity.notificationReceiver != null)
MyActivity.notificationReceiver.notificationReceived();
}
#Override
protected void onPushOpen(Context context, Intent intent)
{
ParseAnalytics.trackAppOpenedInBackground(intent);
Intent i = new Intent(context, MyActivity.class);
i.putExtras(intent.getExtras());
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(i);
}
}
You can use the onNewIntent() (docs) method of the Activity to send the new info about something happened and then display some prompt.
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.
I have a main Activity A, in which I create a background thread to load data from db. After the loading is done, I want to update the list which might have been already shown in a child activity B (If user has navigated to B in the meanwhile). If user hasnt yet navigated to B, its not an issue.
But how to update B's list once thread in A has finished?
B is a child of A.
Thanks,
Set the list as empty at first .You can take the user to activity B . Store the content of list dataand fill the list using a static list which is empty when the background thread is incomplete. Once loading from db is done called the notifydatasetchanged() method of the list's adapter .
An easy way to implement the background thread would be an asynchronous task . You can define different phases of the asynchronous tasks by overriding the corresponding methods.
Thanks Imran,
I handled it by creating an IntentService in a separate class (inner class was not working), and start it from A. After work is done I fire a BroadCast from the IntentService which B's broadcastreceiver is listening. It updates the list eventually.
Here is the code:
In class A, just start the IntentService in for ex OnCreate():
Intent contactIntent = new Intent(this, ContactLoaderService.class);
startService(contactIntent);
Create IntentService like (in a separate class):
public class ContactLoaderService extends IntentService {
public ContactLoaderService() {
super("ContactLoaderService");
}
#Override
protected void onHandleIntent(Intent arg0)
{
populateContacts();
Intent broadcastIntent = new Intent();
broadcastIntent.setAction(ContactsResponseReceiver.ACTION_RESP);
broadcastIntent.addCategory(Intent.CATEGORY_DEFAULT);
sendBroadcast(broadcastIntent);
}
}
In class B I create an inner class which just updates the list like:
public class ContactsResponseReceiver extends BroadcastReceiver {
public static final String ACTION_RESP = "com.a.b.c.ContactsLoaded";
#Override
public void onReceive(Context context, Intent intent) {
mCurrentAdapter.notifyDataSetChanged();
}
}
In B, dont forget to register the receiver. In B's onCreate() method:
IntentFilter filter = new IntentFilter(ContactsResponseReceiver.ACTION_RESP);
filter.addCategory(Intent.CATEGORY_DEFAULT);
receiver = new ContactsResponseReceiver();
registerReceiver(receiver, filter);
And the usual service tag in AndroidManifest.xml
<service android:name="com.a.b.c.ContactLoaderService"> </service>
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