3

I made a service which makes an intent after the location changed and puts the location data into it.

intent.putExtra("Latitude", String.valueOf(loc.getLatitude())); //Double
            intent.putExtra("Longitude", String.valueOf(loc.getLongitude())); //Double
            intent.putExtra("Provider", loc.getProvider()); //String
            intent.putExtra("Altitude", loc.getAltitude());//Double
            intent.putExtra("Accuracy", loc.getAccuracy()); //float
            intent.putExtra("Speed", loc.getSpeed()); //float

Now, I have a Broadcastreceiver which is being fired every 30 seconds for posting that information to a server. However, when I try to get the Intent:

        Intent myIntent = new Intent(context, GPSService.class); //GPSService is the service
        String lat = (String) myIntent.getExtras().get("Latitude");
        String longi = (String) myIntent.getExtras().get("Longitude");

I get a NullPointerException

Attempt to invoke virtual method 'java.lang.Object android.os.Bundle.get(java.lang.String)' on a null object reference

Why is that? I checked the other solutions: Some say to check whether I put the right Dateformat into the intent (Which in this case is String), which I did, some say to use getIntent().getExtras().getString("aKey"); I also tried that as you can see above, but I still get null from the String.

There has to be some problem while passing it to the broadcastreceiver, because I log the values after doing the intent.putExtra() stuff, and they are definitely not null.

EDIT:

GPSService:

    package com.dandddeveloper.alarmisto;

import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;
import android.widget.Toast;

public class GPSService extends Service
{
    public static final String BROADCAST_ACTION = "Hello World";
    private static final int TWO_MINUTES = 1000 * 60 * 2;
    public LocationManager locationManager;
    public MyLocationListener listener;
    public Location previousBestLocation = null;

    Intent intent;
    int counter = 0;

    @Override
    public void onCreate()
    {
        super.onCreate();
        intent = new Intent(BROADCAST_ACTION);
    }

    @Override
    public void onStart(Intent intent, int startId)
    {
        locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
        listener = new MyLocationListener();
        //locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 4000, 0, listener);
        locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 4000, 0, listener);
    }

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

    protected boolean isBetterLocation(Location location, Location currentBestLocation) {
        if (currentBestLocation == null) {
            // A new location is always better than no location
            return true;
        }

        // Check whether the new location fix is newer or older
        long timeDelta = location.getTime() - currentBestLocation.getTime();
        boolean isSignificantlyNewer = timeDelta > TWO_MINUTES;
        boolean isSignificantlyOlder = timeDelta < -TWO_MINUTES;
        boolean isNewer = timeDelta > 0;

        // If it's been more than two minutes since the current location, use the new location
        // because the user has likely moved
        if (isSignificantlyNewer) {
            return true;
            // If the new location is more than two minutes older, it must be worse
        } else if (isSignificantlyOlder) {
            return false;
        }

        // Check whether the new location fix is more or less accurate
        int accuracyDelta = (int) (location.getAccuracy() - currentBestLocation.getAccuracy());
        boolean isLessAccurate = accuracyDelta > 0;
        boolean isMoreAccurate = accuracyDelta < 0;
        boolean isSignificantlyLessAccurate = accuracyDelta > 200;

        // Check if the old and new location are from the same provider
        boolean isFromSameProvider = isSameProvider(location.getProvider(),
                currentBestLocation.getProvider());

        // Determine location quality using a combination of timeliness and accuracy
        if (isMoreAccurate) {
            return true;
        } else if (isNewer && !isLessAccurate) {
            return true;
        } else if (isNewer && !isSignificantlyLessAccurate && isFromSameProvider) {
            return true;
        }
        return false;
    }



    /** Checks whether two providers are the same */
    private boolean isSameProvider(String provider1, String provider2) {
        if (provider1 == null) {
            return provider2 == null;
        }
        return provider1.equals(provider2);
    }



    @Override
    public void onDestroy() {
        // handler.removeCallbacks(sendUpdatesToUI);
        super.onDestroy();
        Log.v("STOP_SERVICE", "DONE");
        locationManager.removeUpdates(listener);
    }

    public static Thread performOnBackgroundThread(final Runnable runnable) {
        final Thread t = new Thread() {
            @Override
            public void run() {
                try {
                    runnable.run();
                } finally {

                }
            }
        };
        t.start();
        return t;
    }




    public class MyLocationListener implements LocationListener
    {

        public void onLocationChanged(final Location loc)
        {
            Log.i("***********************", "Location changed");
            if(isBetterLocation(loc, previousBestLocation)) {
                loc.getLatitude();
                loc.getLongitude();
                intent.putExtra("Latitude", String.valueOf(loc.getLatitude())); //Double
                intent.putExtra("Longitude", String.valueOf(loc.getLongitude())); //Double
                intent.putExtra("Provider", loc.getProvider()); //String
                intent.putExtra("Altitude", loc.getAltitude());//Double
                intent.putExtra("Accuracy", loc.getAccuracy()); //float
                intent.putExtra("Speed", loc.getSpeed()); //float
                intent.putExtra("Bearing", loc.getBearing()); //float
                Log.v("LOC", String.valueOf(loc.getLatitude()));
                Log.v("LOC", String.valueOf(loc.getLongitude()));
                Log.v("LOC", loc.getProvider());
                Log.v("LOC", String.valueOf(loc.getAltitude()));
                Log.v("LOC", String.valueOf(loc.getAccuracy()));
                Log.v("LOC", String.valueOf(loc.getSpeed()));
                Log.v("LOC", String.valueOf(loc.getBearing()));

                sendBroadcast(intent);

            }
        }

        public void onProviderDisabled(String provider)
        {
            Toast.makeText( getApplicationContext(), "Gps Disabled", Toast.LENGTH_SHORT ).show();
        }


        public void onProviderEnabled(String provider)
        {
            Toast.makeText( getApplicationContext(), "Gps Enabled", Toast.LENGTH_SHORT).show();
        }


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

        }

    }
}

Calling the Alarmreceiver in MainActivity:

Intent alarmIntent = new Intent(getApplicationContext(), AlarmReceiver.class);
    pendingIntent = PendingIntent.getBroadcast(MainActivity.this, 0, alarmIntent, 0);

manager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, timeInMillis, pendingIntent);
Mark Tyers
  • 93
  • 9
  • Can I have a look at your complete code for both classes?? – Sourav Chandra Jun 23 '16 at 14:55
  • @SouravChandra Sure, added the necessary code. If you are wondering why this isn't everything from the Broadcastreceiver, really, there isn't anything else related to getting the intentextras from the service. It's a typical `public class AlarmReceiver extends WakefulBroadcastReceiver` with `public void onReceive(Context context, Intent intent) {` – Mark Tyers Jun 23 '16 at 15:07
  • Instead creating a new Intent. You should receive the intent as private AlarmReceiver mMessageReceiver = new AlarmReceiver() { @Override public void onReceive(Context context, Intent intent) { // Extract data included in the Intent } } }; Assuming that AlarmReceiver extends BroadcastReceiever. I don't know if you are following this or not. – Sourav Chandra Jun 23 '16 at 15:40
  • @SouravChadra So I have to make an Alarmreceiver inside my `Alarmreceiver`? I'm not sure whether you understood that I call the class Alarmreceiver every 30 seconds from my `MainActivity`. And inside that `Alarmreceiver` I want to get the data from the `GPSservice`. – Mark Tyers Jun 23 '16 at 15:46
  • Okay, I understood your problem. I'll update my answer with the potential solution. I thought you already have a broadcast receiver object in your MainActivity. – Sourav Chandra Jun 23 '16 at 15:48
  • I have updated my solution. please check – Sourav Chandra Jun 23 '16 at 15:56

2 Answers2

3

Create a BroadcastReceiver object in your MainActivity class as follows:

private BroadcastReceiver mMessageReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        // Extract data included in the Intent

    }
};

Also instead to using periodic checks in the MainActivity, instead create a Timer object and use sendBroadcast(intent) to send timed boradcasts.

Sourav Chandra
  • 843
  • 12
  • 21
  • Op has already mentioned that `getIntent().getExtras().getString("aKey");` also didn't work. – Shree Krishna Jun 23 '16 at 14:53
  • 1
    @SouravChandra Can I use this `BroadcastReceiver` in my AlarmReceiver `BroadcastReceiver`? If I understand your solution, I would have to pass the intent to this private mMessageReceiver, extract it, and then somehow pass it to the other `BroadcastReceiver`? – Mark Tyers Jun 23 '16 at 16:03
  • No buddy just use the snippet in your MainActivity. sendBroadcast takes care of the sending part and the receiving is done from the parameters of this BroadcastReceiver object. – Sourav Chandra Jun 23 '16 at 16:18
  • Sure, but what do I do with the strings I got in the mMessageReceiver? – Mark Tyers Jun 23 '16 at 16:20
  • Yes you can use the Broadcast receiver in your AlarmReceiver – Sourav Chandra Jun 23 '16 at 16:20
  • @SouravChandra to explain my problem more simple: I use [this](http://stackoverflow.com/a/14478281/6436114) Service in the Background, how do I get the values from it in my Broadcastreceiver? (Part with Intent.putextra etc.) – Mark Tyers Jun 23 '16 at 16:28
  • Where do you need those strings? MainActivity or AlarmReceiver? – Sourav Chandra Jun 23 '16 at 16:29
  • @SouravChandra AlarmReceiver. – Mark Tyers Jun 23 '16 at 16:29
  • Then you need to declare an object of BroadcastReceiver in your AlarmReceiver class as i mentioned in my answer. The intent will contain your data. You will only receive data when you call the sendBroadcast() method. And as per your requirements you can acheive this with a Timer implementation in your service. – Sourav Chandra Jun 23 '16 at 16:32
  • Thanks! Sorry for the stupid question, but how do I register that BroadcastReceiver in my AlarmReceiver.class (With GPSService.class!) and how do I get the Strings from it? Or do they become available automatically in the whole class? EDIT: I also found this from where the gpsservice was originally posted: `registerReceiver(broadcastReceiver, new IntentFilter(YourLocationServiceClass.BROADCAST_ACTION));` – Mark Tyers Jun 23 '16 at 16:41
  • They become easily available but you can use and intent filter to filter to avoid other receiving other intents. – Sourav Chandra Jun 23 '16 at 16:48
  • Exactly just replace your service class name with it. – Sourav Chandra Jun 23 '16 at 16:50
  • Are you sure? I put the Broadcastreceiver in my class, tried it outside and inside the onReceive method, but the variables which are being set in the mMessageReceiver don't get recognised in other places of the class... :/ – Mark Tyers Jun 23 '16 at 16:58
  • Buddy the intent variable in your mMessageReceiver is limited to its scope. Initialize them to another class variable or create an interface to achieve any operation whenever you receive something in OnReceive – Sourav Chandra Jun 23 '16 at 17:07
  • @SouravChandra well shit: `BroadcastReceiver components are not allowed to register to receive intents` apparently you can't register new receivers in a broadcastreceiver – Mark Tyers Jun 23 '16 at 17:41
-1

There must be an onreceieve method for receiver.So use its intent and use intent.getStringExtra("key"); and use it.

Pritish
  • 1,284
  • 1
  • 19
  • 42
  • 1
    I tried to call the code above (The Part in the broadcastreceiver) in onReceive. Do you mean I can't create new intents and get extras from them in a broadcastreceiver? – Mark Tyers Jun 23 '16 at 15:11