0

my app not send a JSON string to PHP script when app is hidden or a screen is off. I use HttpURLConnection. My app send a GPS position. I would like, that app to work in backgoround like messanger. Sending and receive a data takes place in AsyncTask. What is wrong?

public class MyAsyncTask extends AsyncTask<JSONObject, Void, JSONObject> {

    String addr = GlobalConfig.addr;
    String prot = GlobalConfig.prot;
    int port = GlobalConfig.port;

    @Override
    protected void onPreExecute() {

    }

    @Override
    protected JSONObject doInBackground(JSONObject... params) {

        JSONObject json = params[0];
        String string = "json="+json;

        try {

            URL url = new URL(prot,addr,port,"json/myLocation.php");

            HttpURLConnection httpCon = (HttpURLConnection) url.openConnection();
            httpCon.setDoOutput(true);
            httpCon.setDoInput(true);
            httpCon.setUseCaches(false);
            httpCon.setConnectTimeout(15000);
            httpCon.setRequestProperty("Content-Length", Integer.toString(string.length()));
            httpCon.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
            httpCon.setRequestMethod("POST");

            DataOutputStream wr = new DataOutputStream(httpCon.getOutputStream());
            wr.writeBytes(string);
            wr.flush();
            wr.close();

            int responseCode = httpCon.getResponseCode();

        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;

    }

    @Override
    protected void onPostExecute(JSONObject json) {

    }

}


public class GPSTracker extends Service implements LocationListener {

    private final Context mContext;

    boolean isGPSEnabled = false;

    boolean isNetworkEnabled = false;

    boolean canGetLocation = false;

    Location location;
    double latitude;
    double longitude;

    private static final long MIN_DISTANCE_CHANGE_FOR_UPDATES = 10;

    private static final long MIN_TIME_BW_UPDATES = 10000;

    protected LocationManager locationManager;

    public GPSTracker(Context context) {
        this.mContext = context;
        getLocation();
    }

    public Location getLocation() {
        try {
            locationManager = (LocationManager) mContext.getSystemService(LOCATION_SERVICE);

            isGPSEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);

            isNetworkEnabled = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);

            if (!isGPSEnabled && !isNetworkEnabled) {

            } else {
                this.canGetLocation = true;

                if (isNetworkEnabled) {
                    locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER,
                            MIN_TIME_BW_UPDATES,
                            MIN_DISTANCE_CHANGE_FOR_UPDATES, this);

                    if (locationManager != null) {
                        location = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
                        if (location != null) {
                            latitude = location.getLatitude();
                            longitude = location.getLongitude();
                        }
                    }
                }

                if (isGPSEnabled) {
                    if (location == null) {
                        locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,
                                MIN_TIME_BW_UPDATES,
                                MIN_DISTANCE_CHANGE_FOR_UPDATES, this);

                        if (locationManager != null) {
                            location = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
                            if (location != null) {
                                latitude = location.getLatitude();
                                longitude = location.getLongitude();
                            }
                        }
                    }
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
        }

        return location;
    }


    public void stopUsingGPS(){
        if(locationManager != null){
            locationManager.removeUpdates(GPSTracker.this);
        }
    }


    public double getLatitude(){
        if(location != null){
            latitude = location.getLatitude();
        }

        return latitude;
    }


    public double getLongitude(){
        if(location != null){
            longitude = location.getLongitude();
        }

        return longitude;
    }


    public boolean canGetLocation() {
        return this.canGetLocation;
    }


    public void showSettingsAlert(){
        AlertDialog.Builder alertDialog = new AlertDialog.Builder(mContext);

        alertDialog.setTitle("GPS is settings");

        alertDialog.setMessage("GPS is not enabled. Do you want to go to settings menu?");

        alertDialog.setPositiveButton("Settings", new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog,int which) {
                Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
                mContext.startActivity(intent);
            }
        });

        alertDialog.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int which) {
                dialog.cancel();
            }
        });

        alertDialog.show();
    }

    @Override
    public void onLocationChanged(Location location) {

        int ID = GlobalConfig.ID;
        int Random = GlobalConfig.Random;

        double latitude = location.getLatitude();
        double longitude = location.getLongitude();

        try {

            JSONObject json = new JSONObject();
            json.put("ID", ID);
            json.put("Random", Random);
            json.put("latitude", latitude);
            json.put("longitude", longitude);

            new MyAsyncTask().execute(json);

        } catch(Exception e){
            e.printStackTrace();
        }

    }

    @Override
    public void onProviderDisabled(String provider) {
    }

    @Override
    public void onProviderEnabled(String provider) {
    }

    @Override
    public void onStatusChanged(String provider, int status, Bundle extras) {
    }

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

}

Like this?

SeaDog
  • 645
  • 1
  • 9
  • 32

3 Answers3

1

I think you are mixing different things:

AsyncTask means that the code runs in a separate task (thread) but still in the context of your activity. That means it runs in background of your app and does not stop the execution of your app.

A Service is able to execute code in the background without any activity context. This is like in background of the system.

To achieve what you want you have to put your tasks in a Service.

Christian
  • 4,596
  • 1
  • 26
  • 33
0

Just like christian said, you will need a service , if you want to update the coordinates when app is in background.

The service will implement the location listener, when the location updates, you will have run the asynctask.

meda
  • 45,103
  • 14
  • 92
  • 122
  • I updated my post. My code includes a service with which you are writing and yet it does not send data. GPSTracker is a serivce. When the location changes then JSONObject is transfer to AsyncTask. – SeaDog Nov 02 '15 at 19:00
  • @SeaDog yes that's what you need to do , but don't forget the manifest file in order for it to run – meda Nov 02 '15 at 19:14
  • I added the entry: is it enough? – SeaDog Nov 02 '15 at 20:03
  • yes , see http://developer.android.com/guide/topics/manifest/service-element.html for complete list – meda Nov 02 '15 at 20:23
  • Great!! :) [Please accept the answer](http://meta.stackexchange.com/a/5235/226432) – meda Nov 03 '15 at 14:32
  • Sorry, I must write again :-( Unfortunately my app sometimes gives the wrong position and sometimes the position is of a few hours. I removed from manifest.xml "" What is wrongs? I want only real position. – SeaDog Nov 03 '15 at 17:07
  • What do you mean? the coordinates are not correct or the time? – meda Nov 03 '15 at 17:10
  • @SeaDog you can keep the coarse location , but add `` it is more precise – meda Nov 03 '15 at 17:17
  • I noticed that when I add then an app show location a cell phone. It seems to me I have to add only . I don't want other location than real a phone location. – SeaDog Nov 04 '15 at 12:35
  • Unfortunately my app not working when is hidden. A class GPSTracker works as service so what is wrong? – SeaDog Nov 06 '15 at 13:02
  • OK, I used IntentService. It looks like it works but now I have a problem with my onLocationChanged. After run my app coordinates will be sent to the server. When my coordinates is changed and I try call IntentService in onLocationChanged then my app is closed. Can you help? – SeaDog Nov 23 '15 at 14:12
  • 11-23 14:28:59.469 28729-28729/com.example.seadog.gps E/AndroidRuntime: FATAL EXCEPTION: main Attempt to invoke virtual method on a null object reference – SeaDog Nov 23 '15 at 14:34
  • I think you should move your code in onLocation change inside of the try/catch block – meda Nov 23 '15 at 15:09
  • It is not good idea. When I put my code in onLocationChanged, then it performs condition catch. – SeaDog Nov 23 '15 at 18:35
0

You need a combination of things to make this work.

First, you will need to have a look at making your service sticky. To do that, follow the steps here:

Android Service needs to run always (Never pause or stop)

A sticky service is a service that runs until you explicitly tell it to shut down (http://developer.android.com/reference/android/app/Service.html#START_STICKY)

You also want to look at wakefulBroadcastReceiver as per the documentation: https://developer.android.com/reference/android/support/v4/content/WakefulBroadcastReceiver.html

This is so that when the device is restarted or brought up after a shutdown, it starts your service again.

To be extra safe, you also need to have a look at implementing some form of network broadcast receiver, for example by implementing the solution here: Broadcast receiver for checking internet connection in android app

This last one is so that you don't try to send stuff when there's no network connection and instead, you start your service when the device is back online.

I do however suggest that you exercise caution with this. Your always running, always uploading service will consume a lot of power and perhaps you'd like to limit the amount of data it sends and the interval it collects this data but that's up to you to listen to or not :).

Community
  • 1
  • 1
kha
  • 19,123
  • 9
  • 34
  • 67