Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Starting a service on android platform

I am starting a service using startService(Intent intent) method. When i call this function it reaches the onCreate of service but it is unable to call onStartCommand. Here is my code--

@Override
public void onReceive(Context context, Intent intent) {
    // Send a text notification to the screen.
    Log.e("mudit", "Action: " + intent.getAction());

    try {
        ConnectivityManager connManager = (ConnectivityManager) context
                .getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo info = connManager.getActiveNetworkInfo();
        Log.e("mudit", "getType: " + info.getType());
        Log.e("mudit", "isConnected: " + info.isConnected());
        if (info.isConnected()) {

            Intent newinIntent = new Intent(context, service.class);
            context.startService(newinIntent);
        }

    } catch (Exception e) {
        e.printStackTrace();
        Intent newinIntent = new Intent(context, service.class);
        context.stopService(newinIntent);

    }

}

Service Code --

package com.android.service;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.widget.Toast;

public class service extends Service {

    @Override
    public IBinder onBind(Intent arg0) {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Toast.makeText(this, "Service created...", Toast.LENGTH_LONG).show();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Toast.makeText(this, "Service destroyed ...", Toast.LENGTH_LONG).show();
    }

    public int onStartCommand(Intent intent, int flags, int startId) {

        Toast.makeText(this, "onStartCommand...", Toast.LENGTH_LONG).show();
        return 1;
    }

}  

Manifest.xml --

<receiver class=".AReceiver" android:name=".AReceiver">
        <intent-filter>
            <action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
        </intent-filter>
    </receiver>
    <service class=".service" android:name=".service"
        android:enabled="true" android:icon="@drawable/icon">
    </service>
like image 500
mudit Avatar asked Feb 27 '23 13:02

mudit


2 Answers

  1. Unbound Service: it runs in the background indefinitely even started activity with service ends also.
  2. Bound Service : it will run till life time of activity.

Activity can start service via startService() and it will stop via stopService(). If activity wants to interact with service, it can use bindService().

First onCreate() is called, after onStartCommand is called with the intent data provided by the activity.

Source

like image 198
srinivas Nidadavolu Avatar answered Mar 05 '23 16:03

srinivas Nidadavolu


larsVogel solves this problem (and many others like it) in this excellent post.

this is how i adapted his code to create a connectivity receiver that monitors when the user connects to a WIFI network so as to batch upload usage data:

in the Manifest file, place a receiver and declare a service right before the end tag for your < / application >:

    <receiver android:name=".ConnMonitor" android:enabled="true">
        <intent-filter>
            <action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
        </intent-filter>
    </receiver>
    <service android:name=".BatchUploadGpsData" ></service>

</application>

create a broadcast receiver class in a separate file called ConnMonitor.java (please uncomment the Log calls to be able to properly monitor the flow)

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.util.Log;

public class ConnMonitor extends BroadcastReceiver {
    private String TAG = "TGtracker";

    @Override
    public void onReceive(Context context, Intent intent) {
        //String typeName = "";
        String state = "";
        int type = -1;
        ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService( Context.CONNECTIVITY_SERVICE );
        NetworkInfo test = (NetworkInfo) connectivityManager.getActiveNetworkInfo();
        //Log.v(TAG,"there has been a CONNECTION CHANGE -> "+intent.getExtras().get(ConnectivityManager.EXTRA_NETWORK_INFO));
        try {
            //typeName = test.getTypeName().toString();
            type = test.getType();
            state = test.getState().toString();
            //Log.i(TAG,"type -> '"+typeName +"'  state -> '"+state+"'"   );
        } catch (Exception e) {
            //typeName = "null";
            type = -1;
            state = "DISCONNECTED";
            //Log.i(TAG,"type -> error1 "+e.getMessage()+ "   cause = "+e.getCause()   );
        }

        if ( (type == 1)  &&  (state == "CONNECTED") ) {
            //Log.i(TAG, "I am soooo friggin uploadin on this beautiful WIFI connection ");
            Intent batchUploadDataService = new Intent(context, BatchUploadGpsData.class);
            context.startService(batchUploadDataService);
        } else {
            //Log.e(TAG,"NO FOUND MATCH type -> '"+typeName +"'  state -> '"+state+"'"   );
        }
    }
}

and, finally, create a service BatchUploadGpsData.java like this:

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;

public class BatchUploadGpsData extends Service {
    final String TAG = "TGtracker";

    @Override
    public void onCreate() {
        Log.e(TAG, "here i am, rockin like a hurricane.   onCreate service");
    // this service tries to upload and terminates itself whether it is successful or not 
    // but it only effectively DOES anything while it is created 
    // (therefore, you can call 1 million times if uploading isnt done, nothing happens)
    // if you comment this next line, you will be able to see that it executes onCreate only the first it is called
    // the reason i do this is that the broadcast receiver is called at least twice every time you have a new change of connectivity state with successful connection to wifi
        this.stopSelf();
    }
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        //Log.i(TAG, "Received start id " + startId + ": " + intent);
        Log.e(TAG, "call me redundant BABY!  onStartCommand service");
        // this service is NOT supposed to execute anything when it is called
        // because it may be called inumerous times in repetition
        // all of its action is in the onCreate - so as to force it to happen ONLY once
        return 1;
    }
    @Override
    public IBinder onBind(Intent intent) {
        // TODO Auto-generated method stub
        return null;
    }

}

this is not pseudocode, this is actual code, tested and running on android 2.2 and up.

the way to test this service is to shut down and restart your WIFI services on your android (powering off the wifi router will also do the trick). BUT this code does not verify if you are effectively connected to the net. for that, i recomend that you make an httpclient request and check out the result of the call. beyond the scope of this discussion.

NOTE: since services run on the same thread as the UI, i highly recommend that you implement the uploading proper on a separate thread or asynctask, depending your specific needs. you can also run the whole service on a separate thread, but that is once again not the scope of this discussion, despite being standard practice in these cases.

like image 42
tony gil Avatar answered Mar 05 '23 18:03

tony gil