1

I am sending android user location lat and longitude to server together with registration ID and other parameters as json object in Asynctask(a nested class of the activity). But the Location object(that had values at the start of the app) instantiated in the activity as such

location = LocationServices.FusedLocationApi
                    .getLastLocation(mgoogleapiclient);

is returning null in the Asynctask Class. Can someone explain to me why? Do I have to use separate class to get user location and send it in another asynctask or service(which doesn't make sense from architectural standpoint)?

Location mLastLocation = LocationServices.FusedLocationApi.getLastLocation(
                mGoogleApiClient);
        if (mLastLocation != null) {
            PostData pdata = new PostData();
            double latitude = mLastLocation.getLatitude();
            double longitude = mLastLocation.getLongitude();
            pdata.execute(String.valueOf(latitude), String.valueOf(longitude));
        }

I am retrieving this from the AsyncTask class as such:

json.put("latitude", String.valueOf(args[1]));
                    json.put("longitude", String.valueOf(args[2]));

But when I debug it, I am getting the getting the registration ID which I sent to the AsyncTask class from another method. I hope I am making myself clear.

@Override
        protected String doInBackground(String... args) {   
            try {
                try {
                    URL url;
                    HttpURLConnection urlConn;
                    url = new URL ("myphp.php");
                    urlConn = (HttpURLConnection)url.openConnection();
                    urlConn.setDoInput (true);
                    urlConn.setDoOutput (true);
                    urlConn.setUseCaches (false);
                    urlConn.setRequestProperty("Content-Type","application/json");   
                    urlConn.setRequestProperty("Accept", "application/json");
                    urlConn.setChunkedStreamingMode(0);
                    urlConn.setRequestMethod("POST");
                    urlConn.connect();                  
                    //get google account
                    AccountManager am = AccountManager.get(getBaseContext()); // "this" references the current Context
                    Account[] accounts = am.getAccountsByType("com.google");

                    //Create JSONObject here
                    JSONObject json = new JSONObject();
                    json.put("regID", String.valueOf(args[0]));
                    json.put("Google account", accounts[0].name);
                    json.put("name", "Amanda");
                    json.put("tel", "2069994444");
                    json.put("latitude", String.valueOf(args[1]));
                    json.put("longitude", String.valueOf(args[2]));

                    String postData=json.toString();

                    // Send POST output.
                    OutputStreamWriter os = new OutputStreamWriter(urlConn.getOutputStream(), "UTF-8");
                      os.write(postData);
                      Log.i("NOTIFICATION", "Data Sent");
                      os.close();

                    BufferedReader reader = new BufferedReader(new InputStreamReader(urlConn.getInputStream())); 
                    String msg=""; 
                    String line = ""; 
                    while ((line = reader.readLine()) != null) {
                        msg += line; } 
                    Log.i("msg=",""+msg);
                } catch (MalformedURLException muex) {
                    // TODO Auto-generated catch block
                    muex.printStackTrace();
                } catch (IOException ioex){
                    ioex.printStackTrace();
                } 
            } catch (Exception e) {
                e.printStackTrace();
                Log.e("ERROR", "There is error in this code");

            }
            return null;

        }

The following is how I sent the registration ID

gcm = GoogleCloudMessaging.getInstance(this);
            regid = getRegistrationId(context);
            if (!regid.isEmpty()) {
                PostData pd = new PostData();               
                pd.execute(regid); 
            } else {
                //register
                registerInBackground();
            }
The_Martian
  • 3,684
  • 5
  • 33
  • 61
  • `getLastLocation()` is probably returning null. It does that quite often. Register a listener, and call your AsyncTask from the `onLocationChanged()` callback. – Daniel Nugent May 21 '15 at 21:57
  • @Daniel thanks for your answer but as of right now I have no luck. Can I call the Asynctask twice to pass the ID and to pass the latitude and longitude from two different methods? How do I retrieve the values in the doInBackground(String ...params) method? – The_Martian May 22 '15 at 21:01
  • Are you having trouble accessing both the JSONObject and the Location object in your AsycTask? Please post your code of what you have tried so far. You can also look at the example code here for registering a location listener: http://stackoverflow.com/questions/30191047/access-coarse-location-permission-gives-a-cell-tower-precision-on-android/30315009#30315009 – Daniel Nugent May 22 '15 at 22:35
  • Are you starting the AsyncTask in a different way somewhere else in your code? Can you add your code that calls it with registration ID, and can you also add your entire AsyncTask code? – Daniel Nugent May 22 '15 at 22:45
  • you call `execute` apparently at 2 points with different numbers of arguments, but your `doInBackground` expects 3 arguments. – njzk2 May 22 '15 at 23:21
  • @njzk2 I did that because my location returned null when I call execute once for both. And I was trying to separate both to see what caused that. – The_Martian May 23 '15 at 20:23

2 Answers2

2

The problem is that you are sending two separate sets of varargs to the AsyncTask at different times.

You should be sending all necessary data to the AsyncTask when you call execute() in order for it to have the data is needs.

So, you need to get all of the data ready, and send it in one call to execute(), something like this:

Location mLastLocation = LocationServices.FusedLocationApi.getLastLocation(
        mGoogleApiClient);

gcm = GoogleCloudMessaging.getInstance(this);
regid = getRegistrationId(context);
if (!regid.isEmpty() && mLastLocation != null) {
    double latitude = mLastLocation.getLatitude();
    double longitude = mLastLocation.getLongitude();
    PostData pd = new PostData();
    pd.execute(regid, String.valueOf(latitude), String.valueOf(longitude));
} else {
    //register if regid is empty
    if (regid.isEmpty()){
       registerInBackground();
    }
}

Also, there is no need to call String.valueOf() on your String arguments that are passed in to doInBackground(), so you can remove those calls:

@Override
protected String doInBackground(String... args) {
    try {
        try {
            URL url;
            HttpURLConnection urlConn;
            url = new URL ("myphp.php");
            urlConn = (HttpURLConnection)url.openConnection();
            urlConn.setDoInput (true);
            urlConn.setDoOutput (true);
            urlConn.setUseCaches (false);
            urlConn.setRequestProperty("Content-Type","application/json");
            urlConn.setRequestProperty("Accept", "application/json");
            urlConn.setChunkedStreamingMode(0);
            urlConn.setRequestMethod("POST");
            urlConn.connect();
            //get google account
            AccountManager am = AccountManager.get(getBaseContext()); // "this" references the current Context
            Account[] accounts = am.getAccountsByType("com.google");

            //Create JSONObject here
            JSONObject json = new JSONObject();
            json.put("regID", args[0]); //modified
            json.put("Google account", accounts[0].name);
            json.put("name", "Amanda");
            json.put("tel", "2069994444");
            json.put("latitude", args[1]); //modified
            json.put("longitude", args[2]); //modified

            String postData=json.toString();

            // Send POST output.
            OutputStreamWriter os = new OutputStreamWriter(urlConn.getOutputStream(), "UTF-8");
            os.write(postData);
            Log.i("NOTIFICATION", "Data Sent");
            os.close();

            BufferedReader reader = new BufferedReader(new InputStreamReader(urlConn.getInputStream()));
            String msg="";
            String line = "";
            while ((line = reader.readLine()) != null) {
                msg += line; }
            Log.i("msg=",""+msg);
        } catch (MalformedURLException muex) {
            // TODO Auto-generated catch block
            muex.printStackTrace();
        } catch (IOException ioex){
            ioex.printStackTrace();
        }
    } catch (Exception e) {
        e.printStackTrace();
        Log.e("ERROR", "There is error in this code");

    }
    return null;

}

Edit: It sounds like you should register a location listener in order to explicitly request a location. Here is sample code that you can use as a reference in order to register a location listener in your code:

public class MainActivity extends Activity implements
        GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, LocationListener {

    LocationRequest mLocationRequest;
    GoogleApiClient mGoogleApiClient;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        buildGoogleApiClient();
        mGoogleApiClient.connect();
    }

    @Override
    protected void onPause(){
        super.onPause();
        if (mGoogleApiClient != null) {
            LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
        }
    }

    protected synchronized void buildGoogleApiClient() {
        Toast.makeText(this,"buildGoogleApiClient",Toast.LENGTH_SHORT).show();
        mGoogleApiClient = new GoogleApiClient.Builder(this)
                .addConnectionCallbacks(this)
                .addOnConnectionFailedListener(this)
                .addApi(LocationServices.API)
                .build();
    }

    @Override
    public void onConnected(Bundle bundle) {
        Toast.makeText(this,"onConnected",Toast.LENGTH_SHORT).show();

        mLocationRequest = new LocationRequest();
        mLocationRequest.setInterval(10);
        mLocationRequest.setFastestInterval(10);
        mLocationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
        //mLocationRequest.setPriority(LocationRequest.PRIORITY_LOW_POWER);
        //mLocationRequest.setSmallestDisplacement(0.1F);

        LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);
    }

    @Override
    public void onConnectionSuspended(int i) {
        Toast.makeText(this,"onConnectionSuspended",Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onConnectionFailed(ConnectionResult connectionResult) {
        Toast.makeText(this,"onConnectionFailed",Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onLocationChanged(Location location) {

        Log.d("locationtesting", "accuracy: " + location.getAccuracy() + " lat: " + location.getLatitude() + " lon: " + location.getLongitude());

        Toast.makeText(this,"Location Changed",Toast.LENGTH_SHORT).show();


        //unregister here if you only need one location update:
        if (mGoogleApiClient != null) {
            LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
        }
    }
}
Daniel Nugent
  • 43,104
  • 15
  • 109
  • 137
  • I tried this approach before and now I get null pointer exception because the last known location returns null at pd.excecute(regid, String.valueOf(latitude), String.valueOf(longitude)); – The_Martian May 23 '15 at 00:45
  • @Quantumdroid you just need to make sure that `mLastLocation` is not null, look at the check at `if (!regid.isEmpty() && mLastLocation != null)`, and look at the update I just made in the answer. – Daniel Nugent May 23 '15 at 00:48
  • I did that but mLastLocation is null. I am trying to figure out what is causing that. I will update you when I do. Thank you so much. – The_Martian May 23 '15 at 20:20
  • @Quantumdroid As I mentioned in my first comment, `getLastLocation()` can and will return null, as it does not explicitly request a location. I just added sample code you can use as a reference to register a location listener, which will explicitly request a location. The location that you get in `onLocationChanged()` will not be null. – Daniel Nugent May 23 '15 at 20:23
  • even then I was getting null pointer exception but I figured it finally. I blame on Eclipse on this as it was very timid to state the cause :( I will give you credit for guiding me and giving me clear answer. You are so awesome. I will take yours as the best answer. – The_Martian May 26 '15 at 00:29
0
private void startReceivingLocationUpdates() {
        if (locationManager == null) {
            locationManager = (android.location.LocationManager)context.getSystemService(Context.LOCATION_SERVICE);
        }

        if (locationManager != null) {
            try {locationManager.requestLocationUpdates(android.location.LocationManager.NETWORK_PROVIDER, 1000, 0F, 
                    (android.location.LocationListener) listener);
            } 
         catch (SecurityException ex) 
             {
                Log.i(TAG, "fail to request location update, ignore", ex);
            } 

           catch (IllegalArgumentException ex)
           {
                Log.d(TAG, "provider does not exist " + ex.getMessage());
            }

            try {
                locationManager.requestLocationUpdates(android.location.LocationManager.GPS_PROVIDER, 1000, 0F, 
                        (android.location.LocationListener) listener);
                //if (listener != null) listener.showGpsOnScreenIndicator(false);
            }
           catch (SecurityException ex) {
                Log.i(TAG, "fail to request location update, ignore", ex); 
                } 

            catch (IllegalArgumentException ex) {
                Log.d(TAG, "provider does not exist " + ex.getMessage());  
                }

            Log.d(TAG, "startReceivingLocationUpdates");
        }
    }

This solved the null pointer exception on my Location object, I got it from here

Community
  • 1
  • 1
The_Martian
  • 3,684
  • 5
  • 33
  • 61