PDA

View Full Version : Android Threading



Arty Ziff
02-10-2011, 02:19 PM
Hi Lads,

I'm building an application that runs completely in the background and deposits information into a text file.

I'm using a standard Java thread to do most of the work, but for some reason, the phone seems to occasionally reset the app, for no apparent reason. Sometimes I'll get 2 or 3 text files out, and then it'll reset.

I think that the system is killing an app that it thinks isn't needed. The app is (1) doing a bluetooth search for surrounding devices, (2) Recording audio and (3) recording incoming/outgoing SMS/Calls before writing the details of all recorded data to a file.

Any ideas as to why this might be getting killed?

Ivan452
02-11-2011, 06:25 AM
well describe the error a bit and give some messages/warnings or logs.

Arty Ziff
02-11-2011, 06:42 AM
well describe the error a bit and give some messages/warnings or logs.

It just seems to reset the program.

I'm using standard java threading to implement background work, and I suspect that the thread is killed when the application is killed.

The individual components work well, and if I keep the app in the foreground it works perfectly, but I want it to work in the background.

Can anyone point me towards a decent tutorial for Android Services?

Arty Ziff
02-11-2011, 08:16 AM
It just seems to reset the program.

I'm using standard java threading to implement background work, and I suspect that the thread is killed when the application is killed.

The individual components work well, and if I keep the app in the foreground it works perfectly, but I want it to work in the background.

Can anyone point me towards a decent tutorial for Android Services?

Right, I've had a quick gawk at tutorials, but I still can't get it right.

My service is called MyService.java. I'm starting it from the activity's OnCreate method.


startService(new Intent(this,MyService.class));

I've put the following into the manifest.xml file.


<service android:enabled="true" android:name=".Ramiel.MyService" />

Ramiel being the package name. If .Ramiel is taken out the app crashes on install. If it's in, the UI comes up but no sign that the Service is running.

Here's a few snippets from the service class itself.


@Override
public void onCreate() {
super.onCreate();
Toast.makeText( getApplicationContext(),
"Service Created!",
Toast.LENGTH_SHORT).show();

@Override
public void onStart(Intent intent, int startid) {
Toast.makeText( getApplicationContext(),
"Service started!",
Toast.LENGTH_SHORT).show();

}

But the toasts don't show up. Any idea as to why that's not working?

Scythe
02-11-2011, 09:18 AM
So, I think you're missing a the underlying understanding of how services work within the Android OS.

Services are started when you tell them to start. Usually the activity will start it, but you can have it start up via a broadcast receiver as well (such as when the phone starts up). Unless you specify in the android manifest otherwise, the service will run in the same process as your activities, threads, etc. You can get around that, but then for your activities to communicate with the service you have to setup a message broker. There are some examples in the android tutorials on how to do this. That's an "advanced" service however.

Think of a process within Android as an app server container. Anything you do within that container only exists for as long as the container does. So, if Android thinks your Activity is no longer of value, it will kill the process its in. Thus, killing your service, threads, activities, etc. That's how it ensures that each app is not going to interfere with each other as far as resources are concerned.

Android also has services which are "sticky", but you have to tell Android it's a sticky service. Basically if it accidentally crashes, or the process was closed by Android for whatever reason, it will restart it when it deems there's enough resources to do so. This is only recommended if you have a service which is suppose to run in the background at all time.

To prevent the random restart of a service that's meant to not have any UI-interaction, you have to make it foreground visible. Android by default will recycle services as more resources are needed to support user interactive apps/widgets/etc. It's the only way to guarantee your service will not be shutdown. To do that you set an ongoing tray notification.

Anyway, there's a start for you. There's a lot you'll learn about the underlying Android OS when you get into services land.

Arty Ziff
02-11-2011, 09:42 AM
So how would I go about placing my app entirely in the background?

I'm using a UI activity to test it, but if I've to get rid of it to keep the Service running, how will I start the Service to start.

Also, that line of code I have that should start the Service class doesn't seem to work.

Have you any idea why it won't start the Service class at all?

Thanks mate.

Scythe
02-11-2011, 10:51 AM
So how would I go about placing my app entirely in the background?

I'm using a UI activity to test it, but if I've to get rid of it to keep the Service running, how will I start the Service to start.

Also, that line of code I have that should start the Service class doesn't seem to work.

Have you any idea why it won't start the Service class at all?

Thanks mate.

So, you'll probably want the service in its own "remote" process. To do that you can do something like:


<service android:name=".app.MyService"
android:process=":remote" />


The :[namewhateverhere] portion is what makes it remote and start in its own process.

If you need tue service to interact with your activity (eg: to update a timer via a textview), then you'll want to follow this guide to get a broker going: http://developer.android.com/guide/developing/tools/aidl.html

If you just need the service to take in data and/or process behind the scenes, then doing what you're currently doing is fine. You can pass it simple flags if you need by calling startService and adding the flags to a bundle. startService only creates the service on the initial call, all calls afterwards hit the onStart method in the service but it doesn't actually recreate the service. It'll just give you a means for communicating to it through bundles.

Also the actual starting code for your service should be in the onCreate method. When Android kills and restarts your service, that is the only call it makes. It will not call onStart like you'd expect it to. onCreate is called before onStart when using startService, and startService is the only way onStart will get called. So I usually just use the onStart method as a way of passing message bundles.


From glancing at your startService code, it looks like it should start. I can double check what I use on my projects when I get home.

If you need the app to start on android start up, there's a broadcast intent you can receive and then start your service via a startService call. Should be a quick google to find.

Arty Ziff
02-12-2011, 10:51 AM
Solved the problem with the service - i had a content resolver throwing a null pointer exception.

Could you tell me how to use Content Providers/Cursors in Services?

I'm using the a Content Resolver query, and it seems to be returning, but when I try to start polling the Cursor (ie. Cursor,moveToFirst()), it crashes the service.

It seems managedquery isn't supported in Services at all.

Here's the code for you to have a look at.


public void SentMessageLog(){
Toast.makeText( getApplicationContext(),
"SMS Method entered",
Toast.LENGTH_SHORT).show();
Uri allCalls = Uri.parse("content:sms/sent"); // Local address of Sent Messages
String[] projection = new String[]{"address","person","date"};
// Details from the MessageLog to be returned
cr = getContentResolver();
Cursor c = cr.query(allCalls, projection, null,null, "date" + " DESC");
Toast.makeText( getApplicationContext(),
"query returned",
Toast.LENGTH_SHORT).show();
//Query the MessageLog for details


if (c.moveToFirst())
{
Toast.makeText( getApplicationContext(),
"query success",
Toast.LENGTH_SHORT).show();
do{ // For each result returned, the following occurs
String telephoneNumber = c.getString(c.getColumnIndex("address"));
String Name = c.getString(c.getColumnIndex("person"));
String Time = c.getString(c.getColumnIndex("date"));
if (Double.parseDouble(Time)<WriteTime){
// TestTime = System.currentTimeMillis();
return;
}
SMSDetails AnSMS = new SMSDetails(Name,telephoneNumber,"Sent", Time);
}
while (c.moveToNext());
}
Toast.makeText( getApplicationContext(),
"SMS Log called end",
Toast.LENGTH_SHORT).show();
return;
}