0

I have a Plugin.java class where I define two methods, one to use a JobScheduler (if API >= 21), and other to use an AlarmManager (if API < 21).

@Override
public void onCreate() {
    super.onCreate();

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        scheduleDeleteJobScheduler(...);
    } else {
        scheduleDeleteAlarmManager(...);
    }
}

The scheduleDeleteJobScheduler() method uses a JobService to delete some old entries I have in a database.

public class ScheduleDeleteService extends JobService {

    @Override
    public boolean onStartJob(JobParameters params) {
        deleteOldEntries();
        jobFinished(params, false);
        return false;
    }

    @Override
    public boolean onStopJob(JobParameters params) {
        return false;
    }

    public void deleteOldEntries(){...}
}

The scheduleDeleteAlarmManager() method uses a BroadcastReceiver to do the same as the JobService.

public class ScheduleDeleteReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        deleteOldEntries();
    }

    public void deleteOldEntries(){...}
}

Both classes call a deleteOldEntries() method to delete old entries from a database. This method is equal for both (JobService and BroadcastReceiver). What I want to do it's to avoid having two methods with an equal implementation.

  • Since I cannot use an Abstract or Super classes because I'm already extending the JobService and BroadcastReceiver. I know that Java doesn't allow me to extend multiple classes because it will result in the "Diamond Problem" where the compiler can't decide which superclass method to use.
  • And by using an Interface, I can only declare the method without an implementation (method signature).
  • I know that I can use static and Default methods (using an Interface), but they were introduced in Java 8 (Android Nougat - API 24). So if I used them, the entire logic of using a JobScheduler (API >= 21) and AlarmManager (API < 21) would make no sense.

I could have another class implementing the method and just call it from both ScheduleDeleteService (JobService) and ScheduleDeleteReceiver (BroadCastReceiver) classes, but I would like some advice to help me to make a better implementation.

Ricardo Faria
  • 764
  • 13
  • 30
  • 1
    "but they were introduced in Java 8 (Android Nougat - API 24)" -- and they are available on all versions of Android: https://developer.android.com/studio/write/java8-support.html#supported_features. Or, create a class that handles the delete logic and have both `ScheduleDeleteService` and `ScheduleDeleteReceiver` create an instance of that class and use it. Or, use a plain static method somewhere. – CommonsWare Mar 28 '18 at 15:58
  • @CommonsWare Thanks, I will use an Interface. – Ricardo Faria Mar 28 '18 at 16:12

2 Answers2

1

There is one more option option: you may follow the idea with the interface and put the implementation in an anonymous class. So, you need both a separate interface and implementing class, but only one extra file. Of course, the solution with default method/multiple inheritance would look more elegant if it were possible.

OldEntriesCleaner.java

interface OldEntriesCleaner {
    void deleteOldEntries();
}

Main activity

@Override
public void onCreate() {
    super.onCreate();

    OldEntriesCleaner cleaner = new OldEntriesCleaner() {
        @Override
        public void deleteOldEntries() {
            // Do the work here
        }
    };
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        scheduleDeleteJobScheduler(..., cleaner)
    } else {
        scheduleDeleteAlarmManager(..., cleaner)
    }
}

Service

public class ScheduleDeleteReceiver extends BroadcastReceiver {

    private OldEntriesCleaner cleaner;

    public ScheduleDeleteReceiver(OldEntriesCleaner cleaner) {
        this.cleaner = cleaner;
    }

    @Override
    public void onReceive(Context context, Intent intent) {
        cleaner.deleteOldEntries();
    }

}
ekaerovets
  • 1,158
  • 10
  • 18
0

As we can find in Abstract Methods and Classes:

Consider using abstract classes if any of these statements apply to your situation:

  • You want to share code among several closely related classes.
  • ...

First, I implemented the ScheduleDelete Abstract Class:

abstract class ScheduleDelete {
    public void deleteOldEntries(){ ... }
}

After, inside ScheduleDeleteService class I called the ScheduleDelete#deleteOldEntries() method:

public class ScheduleDeleteService extends JobService {

    @Override
    public boolean onStartJob(JobParameters params) {
        (new ScheduleDelete(){}).deleteOldEntries();
        jobFinished(params, false);
        return false;
    }

    @Override
    public boolean onStopJob(JobParameters params) {
        return false;
    }
}

And inside the ScheduleDeleteReceiver class I called the ScheduleDelete#deleteOldEntries() method:

public class ScheduleDeleteReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        (new ScheduleDelete(){}).deleteOldEntries();
    }
}
Community
  • 1
  • 1
Ricardo Faria
  • 764
  • 13
  • 30