javaandroidservicekryonet

Class references null when starting service in background


I am trying to implement a "never-ending background service" in my android app. It should be used to wait for a server sending a certain type of object to the client and notify the user when this happens. As a template I use fabcirablog. When I try to start the Service with an intent the references I have to use in onStartCommand these refs appear to be null.

I tried setting the variables one by one in the Service-constructor and fetch them in onStartCommand itself. Every time they result in nullreferences.

MainActivity:

protected void onCreate(Bundle bundle) {
    super.onCreate(bundle);

    ...

    if (clientHandler == null)
        clientHandler = new ClientHandler(this, this);

    if (clientService == null) {
        clientService = new ClientService(this, this);
        mServiceIntent = new Intent(this, clientService.getClass());

        if (!isMyServiceRunning(clientService.getClass()))
            startService(mServiceIntent);                            //somehow creates a new ClientService instance with null variables such as mainActivity, clientHandlder...
    }
}

Service:

Constructor:

public ClientService(Context applicationContext, MainActivity mainActivity) {
    super();

    this.mainActivity = mainActivity;
    client = mainActivity.getClient();
}

onStartCommand:

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    super.onStartCommand(intent, flags, startId);

    client.addListener(new Listener(){              //FIXME client is null (a mainActivity would be null too)
        @Override
        public void connected(Connection connection) {
            super.connected(connection);
        }

        @Override
        public void disconnected(Connection connection) {
            super.disconnected(connection);
        }

        @Override
        public void received(Connection connection, Object o) {
            Log.i("SERVICE", "Received: " + o.toString());
        }
    });

    client.start();
    Network.register(client);

    return START_STICKY;
}

Error log:

java.lang.RuntimeException: Unable to start service com.simplecodings.smma.tools.ClientService@b6efbc2 with Intent { cmp=com.simplecodings.smma/.tools.ClientService }: java.lang.NullPointerException: Attempt to invoke virtual method 'void com.esotericsoftware.kryonet.Client.addListener(com.esotericsoftware.kryonet.Listener)' on a null object reference
    at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:3343)
    at android.app.ActivityThread.-wrap21(ActivityThread.java)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1582)
    at android.os.Handler.dispatchMessage(Handler.java:102)
    at android.os.Looper.loop(Looper.java:154)
    at android.app.ActivityThread.main(ActivityThread.java:6119)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)
 Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void com.esotericsoftware.kryonet.Client.addListener(com.esotericsoftware.kryonet.Listener)' on a null object reference
    at com.simplecodings.smma.tools.ClientService.onStartCommand(ClientService.java:50)
    at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:3326)
    at android.app.ActivityThread.-wrap21(ActivityThread.java) 
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1582) 
    at android.os.Handler.dispatchMessage(Handler.java:102) 
    at android.os.Looper.loop(Looper.java:154) 
    at android.app.ActivityThread.main(ActivityThread.java:6119) 
    at java.lang.reflect.Method.invoke(Native Method) 
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886) 
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776) 

Can I, e.g. reference the client / mainActivity by passing them via .putExtra?


Solution

  • Read this and implement a bound service using the method "Extending the Binder class". The way you are trying to communicate between your Activity and your Service is incorrect.

    Having a never-ending background service is also not possible. You might get away with using a foreground service. You should consider not monitoring your server in a Service, but instead use push messages like Firebase Cloud Messaging to notify your app when something happens in your server.