Ensure service is executed before an activity section - android

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.

Related

Clear an Android application of all Activity's (above/launched by, and including the main launched one)

I have a root activity which of necessity is defined singleTop
<activity
android:name=".MyMainActivity"
android:label="#string/app_name"
android:launchMode="singleTop" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
I have a notification that sends a broadcast to my foreground service telling it, and the Activity if it is bound to MyMainActivity, to stop. A widget can be touched to restore MyMainActivity to its previous state, hence the need for singleTop.
The problem is that since introducing the stop service button on the notification (de rigeur, as I understand) it is killing just MyMainActivity meaning that any Activitys started from it will persist, as I intended it, but fail to return meaningful results since their originating, MyMainActivity has already been destroyed.
I've stuck with a simple finish() to handle the termination broadcast from MyMainActivity, after disconnecting from the service. All the other finish variants had undesired side effects.
System.exit(0); does actually work great. Except that the expected life cycle course towards destruction gets ignored and restarting is a bit of a bother.
finishAffinity is another candidate, except it is described:
Finish this activity as well as all activities immediately below it
when I need to finish the activities above it, according to the android dev terminology.
How to do this?
The answer is very simple, and has been since API 1. Call finishActivity(int intent_id) with the same intent_id that was supplied to startActivityForResult(Intent, int).

Must every activity have a layout?

I'm just getting started with Android and was reading up BroadcastReceiver. Since the MainActivity was being used only to get the alarm time in seconds, it got me thinking whether layout XML files are must for every activity in Android. I mean, is it possible to have an app that when launched, shows no view, but successfully sets up a receiver?
The answer is yes it's possible. Activities don't have to have a UI. It's mentioned in the documentation, e.g.:
An activity is a single, focused thing that the user can do. Almost
all activities interact with the user [...]
(see http://developer.android.com/reference/android/app/Activity.html)
Related SO question: https://stackoverflow.com/a/12817384/534471
To e.g. display a Toast from an Activity without layout you would define the activity in your manifest like so:
<activity
android:name=".MainActivity"
android:theme="#android:style/Theme.NoDisplay">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
The code would look like this:
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Toast.makeText(this, "I'm alive", Toast.LENGTH_LONG).show();
finish();
}
}
You can implement an Activity without a UI. In the manifest you can specify android:theme="#android:style/Theme.NoDisplay". Take a look at this
You can also implement a Service which does not have any UI so you do not need layout inflation. Service just runs in background and shows no views.
Take a look at Android Training and API Guide to learn more about Services

Android Application vs Activity

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>

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();
}
}

Android: calling a method from a Service to an 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

Categories

Resources