Well, I have a service, I have an Activity. They communicate via messages (It must communicate with messages so don't tell me about Intents or other things, please).
I receive a Bundle from the Service, all ok.
Now with the Bundle i've received I want to do something. I want to call a method from "SomeClass", but I can't, because I'm inside of "IncomingHandler" class.
What's the best way to call SomeClass from inside IncomingHandler?
Thanks in advance
class SomeClass implements ServiceConnection {
class IncomingHandler extends Handler {
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MyService.MS_GET_SOMETHING:
Bundle received=msg.getData();
...
If you really want the activity to be calling methods on the service, its time to learn about AIDL, which allows an Activity to make function calls on a bound service via an RPC mechanism. Documentation found here.
I have implemented the feature (Service calls method in activity) like this:
Service sends a broadcast-message.
Activity has a local nested broadcastreceiver that can call a method in the parent activity.
public class MainActivity extends Activity {
private BroadcastReceiver myReceiver = null;
class _RemoteTimeTrackerReceiver extends BroadcastReceiver {
#Override
public void onReceive (Context context, Intent intent) {
// call method in activity
reloadGui();
}
}
#Override
public void onResume() {
super.onResume();
if (myReceiver == null)
{
myReceiver = new _RemoteTimeTrackerReceiver();
IntentFilter filter = new IntentFilter(Global.REFRESH_GUI);
registerReceiver(myReceiver, filter);
}
reloadGui();
}
#Override
public void onPause() {
if (myReceiver != null)
{
unregisterReceiver(myReceiver);
myReceiver = null;
}
super.onPause();
}
void reloadGui() {}
Related
I have an activity class A for the layout and a non-activity class B for Location Request; the class B triggers some events like onConnectionSuspended and i want to get these back in the classe A. How can i do that ?
Thank you for the previous answers, i worked on it but i add some details.
I want to separate the Activity code from the GoogleApi.Connection code. To do that i made a non-activity class (maybe a service is better ?) with Connection code (see the structure code below).
1) Is it a good idea ?
2) If it is not, what is better to do (maybe put all in the same Activity ?) ?
3) If it is yes, i don't think that i can put some "Toast" in the connections events of my non-activity code so how can i get back the connections events in the Activity to display some messages ?
Thank you for the answers
import android.os.Bundle;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
public class SATlocation implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener{
#Override
public void onConnected(Bundle bundle) {
}
#Override
public void onConnectionSuspended(int i) {
}
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
}
}
As an alternative to broadcast receivers, if you have access to your class B instance from your Activity, you can also create an interface for listening to those events.
public interface LocationRequestEventListener {
void onConnectionSuspended();
...
}
public class SomeActivity extends Activity implements LocationRequestEventListener {
private ClassB classB;
#Override
public void onCreate() {
...
classB.setListener(this);
}
...
#Override
void onConnectionSuspended() {
//react to the event here
}
}
public class ClassB {
private LocationRequestListener listener;
....
public void setListener(LocationRequestListener listener) {
this.listener = listener;
}
private void connectionSuspended() {
// suppose this is where your class fire the event of interest
if (listener != null) {
listener.onConnectionSuspended();
}
}
}
use Local broadcast receiver add receiver in your activity as below
private BroadcastReceiver onNotice = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// intent can contain anydata
}
}
inside onresume register receiver as below
protected void onResume() {
super.onResume();
IntentFilter intentFilter = new IntentFilter(MyIntentService.ACTION);
LocalBroadcastManager.getInstance(this).registerReceiver(onNotice, intentFilter);
}
unRegister receiver in onPause
protected void onPause() {
super.onPause();
LocalBroadcastManager.getInstance(this).unregisterReceiver(onNotice);
}
In your location service add following code to send local broadcast
Intent intent = new Intent("custom-event-name");
// You can also include some extra data.
intent.putExtra("message", "This is my message!");
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
How could I know if an activity is the top of stack? I thought about using onResume/onPause, but this is not exactly, as it would fail once the app goes to background.
The fact is that I'm sending a broadcast receiver that is received for all activities (I have a BaseActivity that is extended by all activities and that registers to the broadcast). So, only the activity that is at the top of the stack must react to the broadcast. If I use the isResumed() then it would work always but when the app goes to background. Any idea?
Thanks in advance!
in base activity you register the broadcast Receiver and in receiver function you call one abstract function which one is implemented by all child activities.
The activity which is on top will automatically receive that function call.
Edit sample code:
public abstract class BaseActivity extends AppCompatActivity {
private static final String NOTIFICATION_ARRIVED = "arrived";
public abstract void receivedFunction(Intent intent);
private BroadcastReceiver mMessageReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
displayToast(" received in Base");
receivedFunction(intent);
}
};
public void displayToast(String s) {
Toast.makeText(this,s,Toast.LENGTH_SHORT).show();
}
#Override
public void onResume() {
super.onResume();
registerReceiver(mMessageReceiver, new IntentFilter(BaseActivity.NOTIFICATION_ARRIVED));
}
#Override
public void onPause() {
super.onPause();
unregisterReceiver(mMessageReceiver);
}
}
public class MainActivity extends BaseActivity {
#Override
public void receivedFunction(Intent intent) {
displayToast(" received in child");
}
// do whetever you want . if you ovveride onpause and onResume then call super as well
}
or any other child
public class MainActivity2 extends BaseActivity {
#Override
public void receivedFunction(Intent intent) {
displayToast(" received in child");
}
// do whetever you want . if you ovveride onpause and onResume then call super as well
}
// to broadcast
Intent intent = new Intent(BaseActivity.NOTIFICATION_ARRIVED);
sendBroadcast(intent);
I have one subclass of android.support.v4.app.FragmentActivity(MyActivity), one subclass of android.app.Service and one subclass(MyAsyncTask) of android.os.AsyncTask.
Sample Code:
MyActivity.java
onCreate(...) { // start MyService }
MyService.java
onStartCommand(...){ // execute MyAsyncTask }
MyAsyncTask.java
onPostExecute(String result) { // send result to MyActivity};
My question is, how can i send results from MyAsyncTask when success to MyActivity.
This is not easy to answer in a short paragraph. But basically what you want to do is use binding for your service.
It's certainly not a trivial task, but it's the elegant way to go. Besides of initiating your service with startService() you would additionally bind to your service. The binding mechanism allows your Activity to have a pointer to your Service class. With this pointer you can do whatever you want, including passing a pointer of the Activity itself to the Service, so the service would have a pointer to your Activity.
Once the Service has a pointer to your Activity, you can call any methods and set any variables you want, including setting the return value from your AsyncTask.
You can make a SingleInstance model with the MyActivity.
class MyActivity extends Activity{
private static MyActivity instance;
public static MyActivity getInstance(){
return instance;
}
public void onCreate(Bundle savedInstanceState) {
instance = this;
//xxx
}
public void onDestroy() {
instance = null;
///
}
public void doSomething(){}
}
Then you can call MyActivity.getInstance().doSomething();inside the onPostExecute
Some alternatives:
use an IntentService, which is basically a Service that handles asynchronous requests
send a broadcast from your AsyncTask's onPostExecute and receive it in you Activity (simple example here)
I have tried this structure and its works on my app. Hope its helpful.
Create the service class extended with async task and singleton ..
<service android:name=".myService" />
Service class
public class myService extends AsyncTask<String,String,String>
{
private Activity active = null;
protected myService () {}
public static myService getInstance(Activity activity) {
myService myTask = new myService ();
myTask.active = activity;
return myTask;
}
public startTask() {
//start the async task..
this.execute(new String[] {});
}
protected void onPostExecute(String result) {
//check result sucess cond and call
active.updateActivity(result)
}
}
Activity class
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
myService.getInstance(this).startTask();
}
public void updateActivity(result){
//do something on activity with result...
}
You can send result from service(MyAsyncTask.java and MyService.java) class to activity(myactivity) class through "Broadcast"
here is an example
in your onPostExecute(String result) method add those:
Intent intent = new Intent("your activity class[myactivity.java]");
intent.putExtra("RESULT", result)
sendBroadcast(intent);
and your myactivity class
receive sending broadcast like this:
private BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String bundle = intent.getStrings();// get resulting string and do whatever you want.
}
}
don't forget to register and unregister broadcast in myactivity class, like:
#Override
protected void onResume() {
super.onResume();
registerReceiver(receiver, new IntentFilter("your service class"));
}
#Override
protected void onPause() {
super.onPause();
unregisterReceiver(receiver);
}
A way is to Bind your Activity to your service so that they can share a common communication channel.
i have one activity Main.java is open in my application, i want to close the activity using broadcast receiver , how to close the activity?
Firstly your Main.java needs to be registered as a receiver. You could register it in Main.java's onResume():
#Override
public void onResume() {
registerReceiver(broadcastReceiver, new IntentFilter(BroadcasterClassName.NAME_OF_ACTION));
}
Then handle the broadcast and finish your activity:
private BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(BroadcasterClassName.NAME_OF_ACTION)) {
finish();
}
}
}
You could send a message to the activity which implements Handler.Callback, and handle it there to close the activity.
Quick example:
class Act1 extends Activity implements Handler.Callback {
public static final int CLOSE_ACTIVITY = 54212;
public boolean handleMessage(Message msg) {
if(msg.what == CLOSE_ACTIVITY) {
finish();
}
}
}
And then, since you BroadcastReceiver runs on main thread, in most of the cases. Just send the message via Handler.
new Handler().sendMessage(MessageFactory.createShutdownMsg()).
you could do this:
in your main have:
private static Main mInstance;
onCreate()
{
...
mInstance = this;
}
public static boolean closeActivity()
{
if (mInstance != null)
{
mInstance.finish();
return true;
}
return false;
}
although, this implies only one Main exists at any one time. I think you can achieve that by adding android:noHistory="true" or something similar in the manifest.
I have an Android application which uses C2DM services (aka push).
I have a separate class which implements the registration process and which receives the data (and extends BroadcastReceiver).
I want to communicate this data to the activity which currently is in the foreground. The activity currently in the foreground may differ depending on user action.
What's the best way to communicate in between the receiver and the current activity?
Thanks.
I solved this problem by sending out a new broadcast from the C2DMReceiver class, which looked something like this.
The C2DMReceiver class:
public class C2DMReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals("com.google.android.c2dm.intent.REGISTRATION")) {
handleRegistration(context, intent);
} else if (intent.getAction().equals("com.google.android.c2dm.intent.RECEIVE")) {
handleMessage(context, intent);
}
}
private void handleRegistration(Context context, Intent intent) {
// handle registration
}
private void handleMessage(Context context, Intent intent) {
Intent i = new Intent("push");
i.putExtras(intent);
// context.sendOrderedBroadcast(i, null);
context.sendBroadcast(i);
}
}
Another class I called PushReceiver. This is the class that will extend BroadcastReceiver and receive the broadcast sent by C2DMReceiver.
public class PushReceiver extends BroadcastReceiver {
public PushReceiver() {
}
#Override
public void onReceive(Context context, Intent intent) {
// do stuff
abortBroadcast();
}
public static class PushFilter extends IntentFilter {
private static final int DEFAULT_PUSH_PRIORITY = 1;
public PushFilter() {
this(DEFAULT_PUSH_PRIORITY);
}
public PushFilter(int priority) {
super("push");
setPriority(priority);
}
}
}
And the activity class, in this case called MyActivity. This should work well if you are using a base activity class that all other activities extend. That way every activity registers the receiver. By doing the register/unregister in onResume/onPause, you should be able to guarantee that only the current activity receives the broadcast. If not, you can send an ordered broadcast from C2DMReceiver and use priority in the PushFilter.
public class MyActivity extends Activity {
private PushReceiver pushReceiver;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// your onCreate method
pushReceiver = new PushReceiver();
}
public void onResume() {
super.onResume();
// your onResume method
registerReceiver(pushReceiver, new PushReceiver.PushFilter());
}
public void onPause() {
super.onPause();
// your onPause method
unregisterReceiver(pushReceiver);
}
}
In my case, I wrote the PushReceiver constructor to take a View and then "did stuff" with the view in the onReceive method. Without knowing more about what your trying to do, I can't elaborate on this, but hopefully this can provide a decent template to work from.