0

Hi I am trying to use the service class for first time and have been facing problems. What I want is an infinitely running (unless killed by Android System) service with an active Network connection. I have written the code which works fine on Android 4.3 and 4.4 but the application crashes when I try running on Android 2.2. My code is as follows:

public class BackgroundMusicService extends Service {

private MediaPlayer mp;
private int id;

private static class BackgroundAsyncTaskClass extends AsyncTask<Void, Void, Void>{
    protected Void doInBackground(Void... params) {
        Log.v("Async","Async Called");

                    /*Network connection will be created here*/

        return null;
    }
}

private class ForThread implements Runnable{
    public void run() {
        while (true) {
            try {
                Log.v("ThreadSleeping","5 sec");
                BackgroundAsyncTaskClass task = new BackgroundAsyncTaskClass();
                task.execute();
                Thread.sleep(5000);
            } catch (InterruptedException e) {
            }finally{
                Log.v("Finally called","Finally called");
            }   
        }
    }
}

@Override
public IBinder onBind(Intent intent) {
    return null;
}

@Override
public void onCreate() {
    super.onCreate();
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    Log.v("onStartCommand Called","onStart Command Called");

    Thread t;
    ForThread ft = new ForThread();
    t = new Thread(ft);
    t.start();

    return START_NOT_STICKY;
}


@Override
public void onDestroy() {
    super.onDestroy();
    if(null != mp){
        mp.stop();
        mp.release();
        Log.v("Destroyed","onDestroy Called");
    }
}

public void onTaskRemoved(Intent rootIntent) {

    Intent restartServiceIntent = new Intent(getApplicationContext(),
            this.getClass());
    restartServiceIntent.setPackage(getPackageName());

    PendingIntent restartServicePendingIntent = PendingIntent.getService(
            getApplicationContext(), 1, restartServiceIntent,
            PendingIntent.FLAG_ONE_SHOT);
    AlarmManager alarmService = (AlarmManager) getApplicationContext()
            .getSystemService(Context.ALARM_SERVICE);
    alarmService.set(AlarmManager.ELAPSED_REALTIME,
            SystemClock.elapsedRealtime() + 1000,
            restartServicePendingIntent);

    super.onTaskRemoved(rootIntent);
}

}

and the exception thrown by Android 2.2 is as follows:

04-28 09:51:41.435: W/dalvikvm(280): threadid=7: thread exiting with uncaught exception (group=0x4001d800)
04-28 09:51:41.435: E/AndroidRuntime(280): FATAL EXCEPTION: Thread-8
04-28 09:51:41.435: E/AndroidRuntime(280): java.lang.ExceptionInInitializerError
04-28 09:51:41.435: E/AndroidRuntime(280):  at com.example.backgroundservicedemo.BackgroundMusicService$ForThread.run(BackgroundMusicService.java:45)
04-28 09:51:41.435: E/AndroidRuntime(280):  at java.lang.Thread.run(Thread.java:1096)
04-28 09:51:41.435: E/AndroidRuntime(280): Caused by: java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
04-28 09:51:41.435: E/AndroidRuntime(280):  at android.os.Handler.<init>(Handler.java:121)
04-28 09:51:41.435: E/AndroidRuntime(280):  at android.os.AsyncTask$InternalHandler.<init>(AsyncTask.java:421)
04-28 09:51:41.435: E/AndroidRuntime(280):  at android.os.AsyncTask$InternalHandler.<init>(AsyncTask.java:421)
04-28 09:51:41.435: E/AndroidRuntime(280):  at android.os.AsyncTask.<clinit>(AsyncTask.java:152)

Also, when I try using handler.post(new Runnable(){.... run(){}....} The UI hangs up but the background thread continues running and exits after it becomes out of memory.

Another thing that I have doubts about is: When the application restarts, I want this active Service to stop, but how do I get a reference to this thread running in Background and how do I stop this? I would appreciate if anyone can redirect me to a suitable link/reference or could help me out with the code. Thanks

Roadblock
  • 2,041
  • 2
  • 24
  • 38

1 Answers1

2

You have this inside a thread's run method

 BackgroundAsyncTaskClass task = new BackgroundAsyncTaskClass();
 task.execute();

Threading rules from the docs

  1. The AsyncTask class must be loaded on the UI thread. This is done automatically as of JELLY_BEAN.

  2. The task instance must be created on the UI thread. execute(Params...) must be invoked on the UI thread.

  3. Do not call onPreExecute(), onPostExecute(Result), doInBackground(Params...), onProgressUpdate(Progress...) manually.

  4. The task can be executed only once (an exception will be thrown if a second execution is attempted.)

Raghunandan
  • 132,755
  • 26
  • 225
  • 256
  • That's nice. Reading the documentation is alway the first thing to do. Still it does not explain why execute() must called on the UI Thread. – Blackbelt Apr 28 '14 at 10:12
  • @blackbelt right. will find a source to explain that. – Raghunandan Apr 28 '14 at 10:13
  • @blackbelt the docs does not give details regarding the why part. If you know pls update my post. I am checking the source – Raghunandan Apr 28 '14 at 10:25
  • I don't think you're even getting as far as execute(). It looks like the exception is from `new BackgroundAsyncTaskClass()`. The reason is clear in the stack trace: something in your class or one of its superclasses is creating a Handler. There is seldom a reason to use explicit threads or `Thread.sleep()` in Android. You can usually replace them with the proper use of Handlers. – Kevin Krumwiede Apr 28 '14 at 15:34
  • @kjkrum http://stackoverflow.com/questions/18705945/android-cant-create-handler-inside-thread-that-has-not-called-looper-prepare. Looks like calling execute in a background thread is the problem. But i am not able to answer the why part. – Raghunandan Apr 28 '14 at 15:37
  • The why is "because it creates a Handler." – Kevin Krumwiede Apr 28 '14 at 15:38
  • @kjkrum Handler is bound to the thread that created it. I already posted what was there in the docs. I also looked at the source code. But it would nice if some one could give a better explanation than my post – Raghunandan Apr 28 '14 at 15:41
  • The thread that creates a Handler must be a Looper. The UI thread is a Looper. A thread created with `new Thread()` is not a Looper. You can make a new Thread into a Looper, but you probably shouldn't. – Kevin Krumwiede Apr 28 '14 at 15:53