4

I'm running my application with single activity and call startService(new Intent(this, TCPClient.class)); in onStart. Also I start thread in onCreate() of service that sets up TCP connection to my server. Service is running in separate process. It works well until I restart my application (I do not stop service when app is closed). When I do that, I'm getting 1 more connection from same IP. So, I have 2 client connected from same device and same IP. Question is: How to prevent creating more services?

Manifest:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.sample.servicetest" >

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/MainActivityTheme" >
        <!-- android:theme="@style/AppTheme" > -->
        <service android:name=".TCPClient"
            android:process=":service">
        </service>
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name"
            android:theme="@style/MainActivityTheme" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>

OnStart:

@Override
    protected void onStart() {
        super.onStart();

        Log.v(TAG, "onStart");
        startService(new Intent(this, TCPClient.class));
    }

onStartCommand:

public int onStartCommand(Intent intent, int flags, int startId) {
        if (intent != null) {
            Bundle bundle = intent.getExtras();
            if (bundle != null) {
                if (bundle.containsKey("stop"))
                {
                    stopClient();
                }
            }
        }
        Log.v(TAG, "onStartCommand...");
        return TCPClient.START_STICKY;
    }

stopClient:

private void stopClient() {

        // send mesage that we are closing the connection
        sendCmd(CLOSED_CONNECTION);

        mRun = false;

        SharedPreferences prefSettings = getSharedPreferences("settings", MODE_PRIVATE);
        Editor settingsEd = prefSettings.edit();
        settingsEd.putInt("connected", 0);
        settingsEd.apply();

        if (mBufferOut != null) {
            mBufferOut.flush();
            mBufferOut.close();
        }

        mBufferIn = null;
        mBufferOut = null;
        mServerMessage = null;
    }
Alex Hide
  • 555
  • 5
  • 18
  • 3
    AFAIK startService() can start only one instance of service. The first call startService() will trigger Service.onCreate() event, then onStartCommand(). Subsequent calls of startService() will trigger onStartCommand() only. Check your code that it doesn't starts something unnecessary on onStartCommand() (for example Threads or Handlers) – Mixaz Nov 12 '14 at 21:20
  • @Mixaz, I start thread in onCreate of Service. You can see full source of onStartCommand() in my post. – Alex Hide Nov 12 '14 at 21:23
  • Yeah, I'm sorry I missed that. Anyway I think that only one instance of service should exist. How do you know that there are 2 service instances? – Mixaz Nov 12 '14 at 21:25
  • @Mixaz, I got second connection on server from same IP address (I am the only one who connected from this IP). – Alex Hide Nov 12 '14 at 21:28
  • But it doesn't necessary mean that there are 2 service instances. As @beworker wrote, you probably should check your connect/disconnect logic. Service is not a thread, but telnet most likely uses a thread, and probably you have 2 thread instances created by the same service – Mixaz Nov 12 '14 at 21:30
  • @Mixaz, Probably you are right. But this is supposed to mean that somehow onCreate() called instead of onStartCommand() – Alex Hide Nov 12 '14 at 21:33
  • I do not know; it depends on that where the TCP connections and threads are created. Seems you will have to dig that yourself )) – Mixaz Nov 12 '14 at 21:36

4 Answers4

5

When I do that, new process with service is created.

Open Process View (e.g. DDMS perspective -> Devices) and check how many services are started. I bet there will be only one.

So, I have 2 client connected from same device and same IP. Question is: How to prevent creating more services?

I suspect you need to check your connect/disconnect logic inside the service, because Android allows only one instance of a service to be started. When service is started onCreate() gets called. All following startService() commands come into onStartCommand() method of the service. Just put a break point into your service onCreate() and onStartCommand() and see what happens there.

sergej shafarenka
  • 20,071
  • 7
  • 67
  • 86
3

Ok, I figured it out: When I swipe my application from recent apps, both processes (main and service) closed, then serivce restarted. I solved it by adding startForeground(R.string.app_name, new Notification()); in onCreate of my service (Can a service be killed by a task killer). Thanks all :)

Community
  • 1
  • 1
Alex Hide
  • 555
  • 5
  • 18
  • This was a wonderful trick which I was looking for it (keep service running after removing app from recent app list) – VSB Oct 26 '16 at 12:58
3

android:process should be used with caution

(Quote from the link below)

A little-known and seemingly undocumented behaviour of Android is that each process of an application has is own Application instance. 

So, if you have a service which runs in a different process, calling startService() will init the Appplication class for your app.

More info - Starting Service in Android calls Applications onCreate

Veeresh Charantimath
  • 4,641
  • 5
  • 27
  • 36
0

When you start a service in Android, its not a separate process. From the Android Documentation:

Most confusion about the Service class actually revolves around what it is not:

  • A Service is not a separate process. The Service object itself does not imply it is running in its own process; unless otherwise specified, it runs in the same process as the application it is part of.
  • A Service is not a thread. It is not a means itself to do work off of the main thread (to avoid Application Not Responding errors).

I assume that you are trying to create a NON UI application that just runs the service. Please refer the official documentation that gives a very clear understanding about the service lifecycle and related concepts. It has a few sample implementations worth looking..

http://developer.android.com/reference/android/app/Service.html

Community
  • 1
  • 1
nkz
  • 144
  • 2
  • 9
  • 3
    `If we want to make this service run in a remote process (instead of the standard one for its .apk), we can use android:process in its manifest tag to specify one` – Alex Hide Nov 12 '14 at 21:29
  • 1
    Also please consider: As the services runs in its own process, you need to use some interprocess communication (IPC) to communicate to your service from other parts. Even if the service runs in its own process, you need to use asynchronous processing to perform network access, because Android does not allow network access in the main thread of a process. – nkz Nov 12 '14 at 21:36