0

My app has a Foreground Service and I prefer that all my network calls happen in that, to keep things sane. I also implement a Room database in the Service.

My plan is to have all database operations take place based on triggers, at the Service end. The broadcast has the data passed to the service in the form of a Bundle in the Intent.

However, my problem is:

  1. BroadcastListeners operate on the main thread.
  2. Room DB operations need to be off the main thread so the app is not ANR'd
  3. When I implement a HandlerThread or a Thread with Runnable in the BroadcastListener, I am unable to pass the data as the intent variable is 'accessed from an inner class and needs to be declared final'

My code (as it stands) is as below.

BroadcastReceiver houseCallCancelReceiver = new BroadcastReceiver () {
        @Override
        public void onReceive(Context context, Intent intent) {
            new Thread(new Runnable()  {
                @Override
                public void run() {
                    Bundle bundle = intent.getParcelableExtra ("housecall");
                    String email = bundle.getString("email");
                    String housecallid = bundle.getString("housecallid");
                    .
                    .
                    .
                    }
                }
            }).start();
        }
    }; 

Atm I can think of several options, including:

  1. Writing the DB logic (and thread) in a function and passing the intent as a parameter to the thread. - this leads to code that is not all together and makes it harder to read as I will have one function per operation
  2. Making the call in an AsyncTask - same as above plus a lot of one-off AsyncTask calls. Plus can I call an AsyncTask in a ForegroundService?
  3. Upgrading to Java 1.8 and using Lambdas - I'm worried this may break compatibility with older phones.

Any help is much appreciated!

kilokahn
  • 1,136
  • 2
  • 18
  • 38

1 Answers1

0

I found an answer (of sorts) in this thread: Runnable with a Parameter

By moving the Room DB logic to a separate function, and declaring a class in the function itself and invoking the function in the constructor, I can pass the Intent to the Class as a parameter.

BroadcastReceiver refreshHousecallsReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            Log.d(TAG, "onReceive: In refreshHousecallsReceiver");
            class OneShotTask implements Runnable {
                // idea from https://stackoverflow.com/questions/5853167/runnable-with-a-parameter
                Intent intent;
                OneShotTask(Intent intent1) { intent= intent1; }
                public void run() {
                    refreshHouseCalls(intent);
                }
            }
            Thread t = new Thread(new OneShotTask(intent));
            t.start();
        }
    };

I tried this and it works. However, this is not a reusable way to do things, and I am on the lookout for other ways to do the same thing - please share your examples or ideas as well!

kilokahn
  • 1,136
  • 2
  • 18
  • 38