2

My alarmManager is in the MainActivity it fires every 30 second to the MyReceiver class then from it I start the GetLLRD IntentService class. Thereafter, I am sending a request from the onHandleIntent method to the Server following which I am getting a Response. Now I want to achieve the following, every time the alarmManager fires in the MainActivity I want to pass the Intent from the Response from the Server in the GetLLRD class to the Map class.

I have tried it twice with the intent's code in the GetLLRD class with this part Intent intent1 = new Intent(this, Map.class); I received the intent just once in the Map activity. With this one Intent intent1 = new Intent(mContext, Map.class); the app crashes and I got this error below. How can I achieve my purposes?

Error:

07-08 13:04:33.482: E/AndroidRuntime(16838): FATAL EXCEPTION: IntentService[IntentService]
07-08 13:04:33.482: E/AndroidRuntime(16838): Process: com.bustracker, PID: 16838
07-08 13:04:33.482: E/AndroidRuntime(16838): java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String android.content.Context.getPackageName()' on a null object reference
07-08 13:04:33.482: E/AndroidRuntime(16838):    at android.content.ComponentName.<init>(ComponentName.java:77)
07-08 13:04:33.482: E/AndroidRuntime(16838):    at android.content.Intent.<init>(Intent.java:4570)
07-08 13:04:33.482: E/AndroidRuntime(16838):    at com.bustracker.GetLLRD.onHandleIntent(GetLLRD.java:98)
07-08 13:04:33.482: E/AndroidRuntime(16838):    at android.app.IntentService$ServiceHandler.handleMessage(IntentService.java:65)
07-08 13:04:33.482: E/AndroidRuntime(16838):    at android.os.Handler.dispatchMessage(Handler.java:102)
07-08 13:04:33.482: E/AndroidRuntime(16838):    at android.os.Looper.loop(Looper.java:145)
07-08 13:04:33.482: E/AndroidRuntime(16838):    at android.os.HandlerThread.run(HandlerThread.java:61)

MainActivity:

public class MainActivity extends ActionBarActivity{
        Context context;

                    getLRLD.received_MainActvity_Context(context);
                    Intent intent = new Intent(MainActivity.this,
                            IntentReceiver.class);
                    intent.putExtra("json_data", json);
                    PendingIntent pendingIntent = PendingIntent.getBroadcast(
                            getApplicationContext(), 1, intent,
                            PendingIntent.FLAG_UPDATE_CURRENT);
                    AlarmManager alarm = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
                    Calendar cal = Calendar.getInstance();
                    alarm.setRepeating(AlarmManager.RTC_WAKEUP,
                            System.currentTimeMillis(), 30 * 1000,
                            pendingIntent);
                  startService(intent);

 }

MyReceiver class:

public class MyReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        try {
            String action = intent.getStringExtra("json_data");

            if (!action.isEmpty()) {

                startService(context, action);

            }
        } catch (Exception e) {
        }
    }

    public void startService(Context context, String action) {
        Intent inetent = new Intent(context, GetLLRD.class);
        inetent.putExtra("json_data", action);
        context.startService(inetent);
    }

}

GetLLRD class:

public class GetLLRD extends IntentService {
    Context mContext;

    public GetLLRD() {
        super("IntentService");

    }
    public void received_MainActvity_Context(Context context){
        this.mContext = context;


    }

    @Override
    protected void onHandleIntent(Intent intent) {

        String jSONString = intent.getStringExtra("json_data");

        if (jSONString != null) {
                 //So if I try it in this way I am just receiving the data intent just once in the Map activity.
                             Intent intent1 = new Intent(this, Map.class);
                             intent1.putExtra("list_data", data);
                             intent1.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                             startActivity(intent1);

               //When I do it in this way I am getting the error above:
                             Intent intent1 = new Intent(mContext, Map.class);
                             intent1.putExtra("list_data", data);
                             intent1.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                             mContext.startActivity(intent1);

        }
    }
 }

Map activity:

public class Map extends ActionBarActivity{

        @Override
        protected void onCreate(Bundle savedInstanceState) {
            // TODO Auto-generated method stub
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);

            Intent intent = getIntent();        
            @SuppressWarnings("unchecked")
             ArrayList<ItemDTO> list =(ArrayList<ItemDTO>) intent.getSerializableExtra("list_data");
                for (ItemDTO itemDTO : list) {
                    double latitude = itemDTO.getLatitude();
                    double longitude = itemDTO.getLongitude();
                    int route = itemDTO.getRoute();
                    String direction = itemDTO.getDirection();
                    System.out.println("test from Map activity:  " + latitude + ", " + longitude
                            + ", " + ", " + route + ", " + direction);

                }
        }       
    }

Edit:

GetLLRD IntentService class:

            if (data != null && !data.isEmpty()) {
                                            Intent localIntent = new Intent(
                                Constants.BROADCAST_ACTION).putExtra(
                                "data_list", data);
                        LocalBroadcastManager.getInstance(this).sendBroadcast(localIntent);
            } 

Inside the Map activity:

onCraete(Bundle savedInstanceState){
        IntentFilter data_filter = new IntentFilter();
        data_filter.addAction(Constants.BROADCAST_ACTION);
        registerReceiver(data_receiver, data_filter);
}


final BroadcastReceiver data_receiver = new BroadcastReceiver() {

    @Override
    public void onReceive(Context context, Intent intent) {
        @SuppressWarnings("unchecked")
        ArrayList<ItemDTO> list = (ArrayList<ItemDTO>) intent
                .getSerializableExtra("list_data");
        for (ItemDTO itemDTO : list) {
            double latitude = itemDTO.getLatitude();
            double longitude = itemDTO.getLongitude();
            int route = itemDTO.getRoute();
            String direction = itemDTO.getDirection();
            System.out.println("test from Apple activity:  " + latitude
                    + ", " + longitude + ", " + ", " + route + ", "
                    + direction);

        }

    }

};
MrPencil
  • 934
  • 8
  • 17
  • 36

1 Answers1

4

Your architecture is flawed. The IntentService is created when you call startService(). Then onCreate() and onHandleIntent() is called in the Service. Upon completion of onHandleIntent(), if there are no other pending Intents to be processed the Service stops.

You are making this call in MainActivity before you call startService():

getLRLD.received_MainActvity_Context(context);

You don't show how you are setting the reference variable getLRLD, but this isn't going to work. The Service isn't actually created until you call startService().

You are trying to establish a communcations channel between the Service and the Activity. However, you are using IntentService which is a non-persistent Service. It gets created as needed and when it has nothing to do it goes away. You therefore cannot pass a reference to the Service to the Activity, and you also should not pass a reference to the Activity to the Service.

The best way to achieve communication between the Service and the Activity is one of the following:

  1. Service sends a broadcast Intent with the data. The Activity can register a BroadcastRecevier to listen for this.

  2. Activity creates a PendingIntent containing the necessary ACTION, COMPONENT, etc. and passes this to the Service as an "extra" in the Intent it uses when calling startService(). The Service calls send() on that PendingIntent in order to return data to the Activity.

In both cases the Service doesn't need to know anything about the Activity, and the Activity doesn't need a reference to the Service.

EDIT: Add code to start Activity

If you want to start an Activity, you can do this in the Service.onHandleIntent():

Intent intent1 = new Intent(this, Map.class);
intent1.putExtra("list_data", data);
intent1.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
              Intent.FLAG_ACTIVITY_SINGLE_TOP);
startActivity(intent1);

Using Intent.FLAG_ACTIVITY_SINGLE_TOP will prevent Android from launching a new instance of the Activity, if there is already an instance of the Activity running. In case the Activity is already running, you can get the "extras" from the Intent by overriding onNewIntent() in the Activity.

If you use this approach you don't need to use the broadcast Intent to send the data from the Service to the Activity.

David Wasser
  • 93,459
  • 16
  • 209
  • 274
  • I am Setting the reference variable as the following `GetLLRD getLRLD = new GetLLRD();` I have tried to set this line ` getLRLD.received_MainActvity_Context(context);` after `startService(intent)` but as you said I am getting the same error. Also in the `onHandleIntent` method I am receiving the PendingIntent from the alarmManager every 30 second but when I try to pass the result from the Server to the Map activity, the error occurs and the alarmManager stop firing the PendingIntent. which onCreate do you mean here `Then onCreate() and onHandleIntent() is called in the Service. `? – MrPencil Jul 08 '15 at 12:39
  • Can you please add some code too see how the first Approach with BroadcastRecevier looks like? – MrPencil Jul 08 '15 at 12:49
  • You absolutely positively cannot create Android components (like `Activity`, `Service`, `BroadcastReceiver`, etc.) using keyword `new`. Only the Android framework can instantiate these components. Also, the `onCreate()` I refer to is in the `Service`. – David Wasser Jul 08 '15 at 14:21
  • For sample code using broadcast `Intent` see https://developer.android.com/training/run-background-service/report-status.html – David Wasser Jul 08 '15 at 14:27
  • But I dont have `onCreate()` in the IntentService class I ahve once in MainActivity and in Map. Please can you take a look a my edit code I am trying to implement the first Approach. – MrPencil Jul 08 '15 at 14:37
  • Yes, you don't need to have `onCreate()` in your Service. I was just describing what happens. `IntentService` implements `onCreate()` itself. – David Wasser Jul 08 '15 at 14:44
  • To catch the data returned by the Service to the Activity, you need to create a `BroadcastReceiver` in the Activity. Your edit is wrong. An Intent ACTION is just a String. Just define a String constant like `public static final String INTENT_ACTION = "MY_INTENT_ACTION";` – David Wasser Jul 08 '15 at 14:49
  • I have changed my edit code again as you decribed and from the link but now when I click the button the Map is not being opened. Please take a look at my edit Code. How can I start the Map activity with this Approach? – MrPencil Jul 08 '15 at 15:13
  • If you want to start the `Map` Activity as well, you can use another approach. You need to have the Service call `startActivity()`. You already had code that did that. I'll add this to my answer. – David Wasser Jul 08 '15 at 15:40
  • I've added a code example to help. Sending the data using broadcast `Intent` makes sense if you know that the receiving Activity is already running and is listening for the responses. Starting an Activity from the Service makes more sense if you cant be sure the Activity is running and you want to initiate the Activity from the Service. There are different scenarios that require different solutions. – David Wasser Jul 08 '15 at 15:48
  • 1
    Yes it Woks with `FLAG_ACTIVITY_SINGLE_TOP)` and `onNewIntent()` method. Thanks for your Support. – MrPencil Jul 08 '15 at 16:13
  • can you please help me to fix this issue https://stackoverflow.com/questions/51405397/cannot-solve-attempt-to-invoke-virtual-method-java-lang-string-android-content @DavidWasser – Zhu Jul 18 '18 at 15:13