Android: calling a method from a Service to an Activity - android

I have a simple question to solve, but I am not sure how to do it.
I have a class that extends Service that runs a thread looking for a TCP connection. If one comes in, it read an input message.
If the input message is "START", I start an activity, in this fashion:
Intent dialogIntent = new Intent(getBaseContext(), VoIPCall.class);
dialogIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
dialogIntent.putExtra("inetAddress", clientSocket.getInetAddress());
getApplication().startActivity(dialogIntent);
While this activity is running, the Service keeps running. At some point I may reserve a "STOP". I would like to call a method in the previously created Activity but I am not sure how to interact with it.
I do not want to use a static method. How can I please do that?
Thank you very much,
EDIT: I changed my code to this:
Intent dialogIntent = new Intent("com.voip.rudy.START_CALL");
dialogIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
dialogIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
dialogIntent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
dialogIntent.putExtra("inetAddress", clientSocket.getInetAddress());
getApplication().startActivity(dialogIntent);
And in the manifest:
<activity android:name=".VoIPCall">
<intent-filter>
<action android:name="com.voip.rudy.START_CALL" />
<action android:name="com.voip.rudy.STOP_CALL" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<category android:name="android.intent.category.DEFAULT" /> was required to avoid having it crash.
EDIT:
The solution given has fixed my issue but I wanted to actually act on member variables on that class, that are previously initialized. Say I call the constructor, then I would like to go back into this activity and act on the member variables.
The member variables are not initialized when I call one action after another, it seems to create a new activity somehow. Would there be anyway to act on the same activity, and keep the objects intact please?
James

Add the Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_REORDER_TO_FRONT flags to your intent and call startActivity with a new action or a special extra that can identify the intent.
In the activity, write a method called :
private void handleIntent(Intent intent) {
}
call this from onCreate (or onResume) using:
handleIntent(getIntent());
and also write:
#Override
protected void onNewIntent(Intent intent) {
setIntent(intent);
handleIntent(intent);
}

There are a few ways to do it, really depends on the overall structure of your application. All can work. Off the top of my head these are the methods that come to mind
1) Create a custom intent and have the activity or service react to it when the otehr sends it
2) Instead of the service, setup the logic looking for the tcp connection as an async task within the dialog activity, when you have the tcp connection you could pass it off to the service to do its work
3) Take a look at the local service and remote service SDK examples and use the callback code as the basis for passing data back to the activity. You can also call through the interface back to the service.
4) Maybe even setup a broadcast receiver 'architecture'. This has the advantage of decoupling the user activity from the service entirely. You could put some of your application logic in a service in another process, or even in a process that runs at device boot.

I think any of the techniques would work. I'm guessing that the behavior you are seeing is related to the lifecycle of the activities within android and you might need to move some of your processing to the onResume/onPause or onStart/onStop methods. If you you find that your activity onCreate is not being called, but you now your activity is active, it might jsut be that an activity instance from a previous invocation is still alive in the system. If so, it is possible that the OS is using that instead of the new activity that you want. The best way to see if this is a problem is to put some "Log.d" calls at the beginning and end of all of the activity methods that you override. You will be able to tell what is happening by watching logcat. The technique that you use may also be dependent on how synchronous you want the activity's reaction to be with the TCP event. If you want completely async you can go with a standard broadcast, or a service callback with a message send. If you want synchronous then do it with a service callback. In case you haven't seen it this SDK link has a pretty good description of the activity lifecycle http://developer.android.com/reference/android/app/Activity.html

Related

How can I send a message from one activity to another in real time

I have two activities, when I open Activity2, the Activity1 won't be closed. In Activity1 I have a handle that post a code (handler.postDelayed()), when this code run I need my Activity2 be notified in order to execute a other code too.
My question is: How can I send this message to Activity2 without reopening it.
I tried use an Intent with a specific action and catch it in onNewIntent() in Activity2; it works but the problem is that this reopen my Activity2. And I can't save the data in SharedPrefs cause my postDelayed() have no fix time, then I'd have to be checking all the time.
Does anyone know how I can send this message when my postDelayed() runs and how I catch it in Activity2 without reopening it? Please if possible post a example or a link to one.
Really thanks...
It was a simple solutions, like said #njzk2, was only add
<activity ..
android:launchMode= "singleInstance" />
or
<activity ..
android:launchMode= "singleTask" />
(both works).
Thanks
You shouldn't be using an Activity to handle long-running code, you should probably look into creating an IntentService to handle your background code. The IntentService can broadcast a new Intent when it is finished running the code. Have your first Activity start the Service, then instantiate a BroadcastReceiver in your second Activity to listen for updates from the Service.
Sending an broadcast Intent doesn't start or resume an Activity.
The BroadcastReceiver for an Activity receives and processes
Intent objects even when your app is in the background, but doesn't
force your app to the foreground.

How to startActivity() from BroadcastReceiver without recreating the activity?

I need to receive a broadcast event inside a broadcast receiver and than pass this information to an activity that is already open. How can I inform the activity from the broadcast receiver without it getting recreated? This causes a total refresh which is not needed.
Now I could receive intent inside a broadcast receiver that is declared within the activity, but I also need to receive the intent when its in background as well, hence the main place I am processing the intents is in a separate broadcast receiver. So I just don't know how to inform the activity that a new intent has arrived without onCreate() getting called and re-init the whole UI.
I think I need the NEW_TASK flag or it won't run.
PS: What are these insane downvotes about. What could be more relevant than how to start an activity from a broadcast receiver in such a way as not to recreate the activity. BTW, I am going to find an answer w/wo you. Why the bitter downvotes? I suspect it is because you know I could use an answer. Well I'll probably be posting an answer to this great question myself quite soon.
if you want to recreate this activity do this:
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
if don't want to recreate , just do this:
while this activity on your task's top,intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
declare the actvity in the manifest with: android:lauchMode= "singleTask";
And the answer is .....
declare the Activity in the manifest with
android:launchMode="singleTop"
Still would like feedback on this answer as I notice that in onResume() the intent does not seem to carry over the values as it did before. So I cannot pull out values that I set on the intent inside the broadcast receiver ...
Update: In order to get the values from the receiver you may need to do the following inside the Activity:
#Override
public void onNewIntent(Intent intent)
{
setIntent(intent);
}

Android Explicit Intent, Loading second Activities layout, not reaching OnCreate method

This is my first android app attempt after reading "Android 2 Application Development" and lots of stuff online.
Here is the relevant code:
from MovieRatingsActivity.java [my main]
Intent i = new Intent(MovieRatingsActivity.this, DisplayMovies.class);
startActivity(i);
from Manifest:
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".DisplayMovies"
android:label="Display Movies" >
</activity>
note: i do not have any intent filters for the second activity. Do I need any if it is an explicit intent that I never plan on interacting with another application? I have tried with multiple combinations of different intent filters just out of spite, but its hard to have this answered, as every source I go to jumps to implicit intents and doesn't answer this question.
As for behavior:
Whether in debug mode, or run mode, when I click on the button and create the intent, the emulator switches to the second activity and displays the label at the top, but nothing else. Worse, in debugger mode, when I try to step-into startActivity(i), it just suspends the main thread and goes no where. Do you need a special debug technique for when jumping to next activity?
There is a chance that my intents are fine, my logic to display the list is wrong, but even still I would like to be able to reach the code in the debugger. I also added a System.out.printline at the beginning of the second activities OnCreate method that is not executing.
Do I need any if it is an explicit intent that I never plan on
interacting with another application?
you dont need any explicit intents in that case.
Do you need a special debug technique for when jumping to next
activity?
You could put a breakpoint in onCreate() of second activity.

What is the cleanest way to create a GUIless application?

Good Morning.
I have a question about how to create an application without GUI. It should start when the user pushes the icon. Reading other posts, seems that the natural way of doing this would be a Service.
Since the app has no GUI, it makes no sense to add any Activity. For this reason, the Service has to be unbinded. So, if there is no component calling startService, and no external component is sending an intent, ¿how does the service start?
Is there any attribute in the manifest to achieve this? Or maybe extending Application and using onCreate to start the service?
Thanks.
UPDATES:
-There's no way to start a Service in the same app without an Intent. Other options would be autostart or Broadcast receivers, but these don't fit my requirements.
-Tried a test app without Activities, and the icon isn't even showing in the launcher. Don't know the reason of this, maybe related to the manifest not having a LAUNCHER activity.
The list of applications shown in the Android launcher is basically the list of all activities in the system that have a LAUNCHER intent filter:
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
If you put this intent filter on a <service>, it will not work (just tried). Thus, the only way to do what you want to do is through an Activity. I think the cleanest way is something like this:
public void onCreate(Bundle savedInstanceState) {
Intent service = new Intent(this, MyService.class);
startService(service);
Toast.makeText(this, "Service started.", Toast.LENGTH_SHORT).show();
finish();
}
The user will not see anything except a small message at the bottom of the screen saying "Service started." that will automatically disappear in a couple of seconds. It's clean and user-friendly.
The service is started either when somebody calls startService() or when somebody calls bindService(). Note that if service is only started via bindService() it will be automatically stopped when Activity either explicitly unbinds from it or is destroyed (and it was the only binder).
You can declare BOOT_COMPLETED_ACTION broadcast receiver in your AndroidManifest.xml and start your service on system boot. But you service will only start on next device reboot. And there are some issues with applications without activities and this broadcast event in Android 3.1. More info can be found here.
In general, its good to have at least one activity in your application, even if your primary component is service. This activity will start the service when user launches it, and also may expose some ability to configure the service behavior.
Example of activity that starts service:
public class ServiceStarterActivity extends Activity
{
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
startService(new Intent(this, ServiceA.class));
finish();
}
}

How to bring an Activity to foreground (or create if not existing)?

I am intercepting sms messages with some information in them. Then in my SmsListener I'm creating notification to show in statusbar.
Then, when user clicks on a notification I want
Bring MainActivity to foreground (If such activity does not exist yet it should be created)
Pass to it data from the sms
Perform some ui changes basing on this data in this MainActivity
My activity is defined as
<activity
android:name=".MainActivity"
android:screenOrientation="sensor"
android:label="#string/app_name"
android:launchMode="singleTask"/>
Activity is launched as
Intent i = new Intent();
i.setClass(context, MainActivity.class);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(i);
Also in my activity I have overridden method onNewActivity
#Override
public void onNewIntent(Intent intent){
super.onNewIntent(intent);
// I have data from broadcast in intent variable passed to this activity
processDataFromBroadcast(intent);
}
It works fine if the MainActivity already exists but if MainActivity does not exist it is started however onNewIntent was not called
Then I tried to invoke processDataFromBroadcast from onCreate: processDataFromBroadcast(getIntent()).
First time data is passed correctly from my broadcast to the activity.
However if MainActivity is sent to background and then again brought to foreground either onCreate or onNewIntent is called and processDataFromBroadcast is executed again with intent sent by broadcast and thus my MainActivity is updated with data from broadcast every-time the app is bringing to foreground - the latter is unwanted, how can I make my activity to forget this intent after first handling.
Here is sample application.
For an activity to launch only one instance of itself, have a look at the <activity> manifest element, and particularly android:launchMode. You want to configure it with either singleTask or singleInstance.
To pass data to your activity, you add data to the Intent you use to open it. To pass data with the intent, use the putExtra() methods of the intent before sending it off, and getExtra() methods to retrieve them in your receiving activity.
I'm assuming that you know roughly how intents work, but if not you could learn more about intents by taking a look at this Android developers article.
in case your problem is still unresolved, as I was just running into the same issue, here's how I solved it:
I am putting a timestamp as intentId as an extra upon the intent during it's creation. the first time, I am handling the intent in onCreate() or onNewIntent() I am reading the intentId and store it as the last intent handled. so the next time onCreate() or onNewIntet() is invoked I can check the intentId and if it equals the id of the last intent handled, I ignore it! It don't know if this helps in your case, maybe you can adopt it.
To keep intentId independent from activity lifecycles you could persist it in the userdefaults.
I agree that one would expect calling setIntent(new Intent()) in onNewIntent should do the trick.
It it late to answer, but it might be helpful to others looking for the solution.
Just add below lines of code :
Intent mIntent = new Intent(this, SplashActivity.class);
mIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); // You need this if starting the activity from a service
mIntent.setAction(Intent.ACTION_MAIN);
mIntent.addCategory(Intent.CATEGORY_LAUNCHER);
Where SplashActivity is the name of initial application that is the first screen of your application.
Hope it helps. :)

Categories

Resources