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();
}
}
Related
Is there any way to use alertbox in service rather then making another activity for it and then starting that activity from service?
A Service cannot show a Dialog , only you can show short lived Toast from there.
But If your Requirement is of showing dialog I will not disappoint you .You have got following options:
If you have a MainActivity use a LocalBroadcastReceiver to send a broadcast to your activity and let your MainActivity show a Dialog. (This will be possible only when your activity is visible)
The other option is Define a Dialog theme activity (take a look here) in your manifest and start that activity from service.
Another option could be , Define a Activitiy in Manifest whose sole purpose would be display a Dialog and start that activity from service
Edit
I have a suggestion , If you wish to present information to your users , you should use Notification . The main reason that you cannot show a dialog from service is that Google wants information to be decently presented to its users , instead of surprising them when suppose they are in middle of a call , or typing message etc.
if the user is interested, then he will touch the notification and you start your own activity, possibly resuming your activity, creating a new one, and then using a dialog requesting action to be performed, or whatever you want to do.
Alternative Solution
However If you persist I have another solution if you like hacking, (but I don't like hacks in good application).
Create a custom Broadcast Receiver
public class MyBroadcastReceiver extends BroadcastReceiver{
#Override
public void onReceive(Context context, Intent intent) {
// AlertDialogue will be here
}
}
Register it in the manifest file
<receiver android:name="MyBroadcastReceiver">
<intent-filter>
<action android:name="com.sample.A_CUSTOM_INTENT">
</action>
</intent-filter>
</receiver>
Trigger the BroadcastReceiver from service
Intent intent = new Intent("MyCustomIntent");
EditText et = (EditText)findViewById(R.id.extraIntent);
// add data to the Intent
intent.putExtra("message", (CharSequence)et.getText().toString());
intent.setAction("com.sample.A_CUSTOM_INTENT");
sendBroadcast(intent);
in my app i run a service in which i keep record of incoming and out going calls on text file(saved it on internal storage) using broadcastReciever. but when i press clear data button(settings=>apps=>Myapp=>clear data) my service also stops. i used Log.d() in onDestroy() method but it is not logged in logcat when i press clear data.
i read this question having same problem but i didn't find any solution. then i went through Developer Guide. i am really confused.
The data associated the the app will no longer persist on clearing. To avoid this you need to sign your app as a system app.
Clear Data does kill the app, and always has.
"Force Stop" has gone through various iterations of meanings. It used
to mean to just kill all processes and services, and clearing data
would also do the same as a force stop. There were also older
iterations of the platform that were not as good as figuring out when
to disable the button, which is probably why you are seeing it remain
enabled in 2.2.
However in 3.2 I believe the meaning of "Force Stop" change to put the
application in a state where it would not be able to run until the
user had done something to explicitly start it (such as launching it
from launcher, selecting it as an input method, etc). When that change
was made, "Clear Data" continued to just kill the processes and stop
its services, so the app was not in the full stopped state so the
button remains enabled.
Edit:
Example of working code:
Step 1) Create one Android BroadCastReciever and register it for two action
Manifest
<service android:name="ServiceTest" >
</service>
<receiver android:name="ReceiverCall" >
<intent-filter>
<action android:name="com.android.techtrainner" />
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
com.android.techtrainner is the custom action. BroadCastReceiver Class contain code to restart service again
public class ReceiverCall extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Log.i("Service Stops", "Ohhhhhhh");
context.startService(new Intent(context, ServiceTest.class));;
}
}
Step 2) Create Android service class , do some task there (I have taken one Timer to print Log) and in onDestory()
public void onDestroy() {
try {
mTimer.cancel();
timerTask.cancel();
} catch (Exception e) {
e.printStackTrace();
}
Intent intent = new Intent("com.android.techtrainner");
intent.putExtra("yourvalue", "torestore");
sendBroadcast(intent);
}
I have an app with some activities. These activities need common resources (matrix arrayLists), so in order to avoid reload several times this resources (when change to another activity or on an orientation change), I've created a service.
Firstly I call it with startService(Intent) for let it be sticky.
After that, I bind the service to the activity, bindService(sIntent, mConnection, BIND_AUTO_CREATE);
Finally, I have some code which try to get data from the service, but it generates a NullPointerException. I know that's because (as I see with logs) the service starts after the app has crashed, although I put startService and bindService before the accessing data code.
Anyone knows how can I ensure to get loaded data before trying to access it?
Thanks in advance.
It might be easier for you to save your common resources in SharedPreference, The SharedPreference is accessible by all threads of your application, and is persistent between runs. This depending on what your resources are.
If you want your services to work for your method you could do this with a transparent Activity. AsyncTask might be an easier and simpler solution though.
Try to load your data with an AsyncTask, you can choose whatever you want what the Activity does while loading (Progress dialog? ) and make sure you continue your app using your data after when your AsyncTask calls the ready method ( onPostExecute() ). This means AsyncTask will replace your idea of a service as background thread, managing your resources. (loading, downloading, etc).
Also post your logs next time, they might help.
Start your Service in the onCreate() of a class that extends Application. Or even better, do the work the Service is doing in your Application class, which is guaranteed to be created before any other part of your app. A Service may take a while to start up and you may encounter a race condition, but the class extending Application is always the first part of an app to be launched.
I recently came across this problem and created a solution. Similar to the invisible activity, but the idea is to create a "loading" activity that does not need the service. Here is an example:
in AndriodManifest.xml:
...
<application
... >
<activity
android:name="com.example.LoadingActivity"
android:label="#string/app_name" >
<!-- A do-nothing activity that is used as a placeholder while the service is started. -->
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name="com.example.MyActivity"
android:label="#string/app_name" >
<!-- The real activity, started by the loading activity. -->
</activity>
<service
android:name="com.example.MyService" >
<!-- The background service, started by the loading activity. -->
</service>
</application>
...
com/example/LoadingActivity.java:
package com.example;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
public class LoadingActivity extends Activity
{
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
super.setContentView(R.layout.activity_loading);
super.startService(new Intent(this, MyService.class)); // listed first so it will start before the activity
Intent intent = new Intent(this, MyActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); // makes it so the 'loading' activity is not kept on the back-stack
super.startActivity(intent);
}
}
The MyActivity.java and MyService.java files are just standard. You also need an activity_loading.xml layout resource, probably just an ImageView.
I have written a few Android apps, and have always declared a starting Activity as the:
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
It would be great for scoping some global methods, statics, shared prefs, etc if I could start my app using an Application that then calls the first Activity from it's onCreate() after setting up prefs, etc, but I haven't been able to find any examples of this design pattern... when I try this in code, I get a ClassCastException:
public class MyApplication extends Application {
#Override
public void onCreate() {
super.onCreate();
// do stuff (prefs, etc)
// start the initial Activity
Intent i = new Intent(this, InitialActivity.class);
startActivity(i);
}
}
InitialActivity.class is indeed an Activity that works fine if I set it to be MAIN, but trying to start it from MyApplication that is declared MAIN generates the error. Probably a very silly question, but am I tackling this all wrong?
Thanks,
Paul
You can fix this by using FLAG_ACTIVITY_NEW_TASK flag:
Intent intent = new Intent(this, ApplicationActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
That's because you need to start new task when Activity is started outside of Activity context. But I strongly recommend to not start Activity from your Application's onCreate().
Android has 4 components: Activity, Service, ContentProvider and Broadcast.
When Android needs to activate one of this components from your application, it looks if there is already existing running process with your application. If not, then Android starts new process, initializes it, then it initializes your custom Application instance. And then it activates one of needed components.
Now, let's consider next scenario: your application declared content provider in AndroidManifest.xml, and Android just about to start your application so you can provide some data to another foreground application.
Content Provider request is sent
Your application wasn't running, and Android starts new process for it.
Your custom Application instance is created
Application.onCreate() is called.
You start an activity
Your Content Provider receives request
Somebody just wanted to connect to your content provider, but your application started an Activity instead. Same true for starting background Service and sometimes broadcast receivers.
And also consider if some other application's activity A wanted to started activity X from your application. But in onCreate() you started activity Y, and then X is also started by Android. Then user presses back. What should happen? Its tricky...
Starting activities from Application's onCreate may result in quite weird user experience. So don't do it.
UPDATE:
Because Android guarantees that Application will be created only once and before any other component, you can use next code to access your Application's single instance:
public class MyApplication extends Application
{
private static MyApplication s_instance;
public MyApplication()
{
s_instance = this;
}
public static MyApplication getApplication()
{
return s_instance;
}
}
Did you set it in you manifest activity tag for this intent you are starting (another one besides your main) ?
</activity>
<activity android:name=".InitialActivity"
android:label="#string/app_name">
<intent-filter>
<action android:name="com.package.INITACT" /> <--- this is only name by which you activity can be called.
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
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