3

I have an Android app that works fine, but I want it to be able to run in the background and continue running even when it doesn't have focus.

QueryDB (see below) extends AsyncTask in the current version of the app. I've been advised to use a Service (or IntentSerivce) to accomplish the above goal.

So I changed QueryDB to extend IntentService for starters.

Doing so caused this exception in Android Studio 1.5.1:

04-29 12:02:45.544 1523-1523/com.dslomer64.wordyhelperton E/AndroidRuntime: 
FATAL EXCEPTION: main

    Process: com.dslomer64.wordyhelperton, PID: 1523

    java.lang.RuntimeException: Unable to instantiate service 
    com.dslomer64.wordyhelperton.DatabaseConnector$QueryDB: 
                                                   ^^^^^^^
    java.lang.InstantiationException: 
    java.lang.Class<com.dslomer64.wordyhelperton.DatabaseConnector$QueryDB> 
    has no zero argument constructor

            at android.app.ActivityThread.handleCreateService(ActivityThread.java:2880)
            at android.app.ActivityThread.access$1900(ActivityThread.java:157)
            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1439)
            at android.os.Handler.dispatchMessage(Handler.java:102)
            at android.os.Looper.loop(Looper.java:148)
            at android.app.ActivityThread.main(ActivityThread.java:5551)
            at java.lang.reflect.Method.invoke(Native Method)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:730)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:620)


 Caused by: java.lang.InstantiationException:
 java.lang.Class<com.dslomer64.wordyhelperton.DatabaseConnector$QueryDB> 
                                                                ^^^^^^^
     has no zero argument constructor


            at java.lang.Class.newInstance(Native Method)
            at android.app.ActivityThread.handleCreateService(ActivityThread.java:2877)
            at android.app.ActivityThread.access$1900(ActivityThread.java:157) 
            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1439) 
            at android.os.Handler.dispatchMessage(Handler.java:102) 
            at android.os.Looper.loop(Looper.java:148) 
            at android.app.ActivityThread.main(ActivityThread.java:5551) 
            at java.lang.reflect.Method.invoke(Native Method) 
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:730) 
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:620) 

Here's the start of QueryDB that caused the error:

 public class QueryDB extends IntentService
  {
    public QueryDB()
    {
      super("QueryDB");
    }

    public QueryDB(String name)
    {
      super(name);
    }

QueryDB, which is linked to the error, is a class within DatabaseConnector.

After considerable Googling and following SO links, I found an SO Answer that suggested making class QueryDB static. Doing so got rid of the above error.

But since changing QueryDB from AsyncTask to IntentService is the only change I've made, I'm getting another error that I think I know what to do about, but I have a long way to go and I don't want this change to come back and bite me.

After QueryDB executes and terminates, it will be executed again after further user input.

Is making class QueryDB static perfectly safe and a good idea as long as I only need to have one instance of it executing at any time? I think it has to be an inner class of DatabaseConnector.

EDIT

Per suggestion in first comment, this will prove to be interesting reading.

So may this.

Community
  • 1
  • 1
DSlomer64
  • 4,234
  • 4
  • 53
  • 88
  • 1
    Perhaps you should read about and understand what a static nested class is vs. a non-static nested class (aka inner class). See https://docs.oracle.com/javase/tutorial/java/javaOO/nested.html. Then you can answer the question about "safe" yourself, because the answer is "it depends". – Andreas Apr 29 '16 at 19:26

1 Answers1

2

As opposed to AsyncTask, which you directly handle, Service is a component and it should be registered/indexed by OS. So you have indirect influence on lifecycle of the component. If IntentService is implemented as an inner class it should be static or Android system would not able to start the service. Also a proper registration would look like

<service android:name=".MyEnclosedClass$MyIntentService" />

As for safety with static classes (in general) a memory leaks can be a problem. You should be careful when giving references to the static object, because it may outlive (due to configuration changes) enclosed object (EO), so garbage collector can not reap EO.

Maxim G
  • 1,479
  • 1
  • 15
  • 23