1

In Java, I have a class that has many SQLite CRUD functions, all belonging to the same class, SQLiteCrudHelper.

Is the only way to make all these functions run outside the UI thread is to write a wrapper function for each CRUD function, something that starts a new thread, runs the CRUD function, and then returns a callback so you can implement what happens after it's done?

Or is there a way to make a generic threaded/callback function that will take any function you give it and treat it this way?

AJJ
  • 2,004
  • 4
  • 28
  • 42

2 Answers2

0

The problem is: java doesn't have a mean that would allow you to take any function.

So, pre-java 8, you would normally pass some instance of Runnable or using ExecutorService to pass Callables.

With Java8, you can have a look into functional interfaces together with method references.

Long story short. You can just create code that takes some "void*" pointer as in the good bad days of C; but you have several options on how to get closer to that.

Finally: my "personal" choice would be to look into ExecutorServices instead of using "bare metal threads" (or thread pools); as those can be easily replaced with a "same thread executor service" which makes it very easy to turn your multi-threaded code back to "single-threaded" for unit testing.

Community
  • 1
  • 1
GhostCat
  • 137,827
  • 25
  • 176
  • 248
  • That is why I pointed to functional interfaces: It might be reasonable to use BiFunction for example; and allow for code that takes that interface, refined with some of your own interfaces. – GhostCat Aug 22 '16 at 04:49
  • I am working in pre-Java 8 so I don't think I can use any of that, but I'll accept the answer anyway and just accept that I probably can't do this in Java 7 – AJJ Aug 22 '16 at 04:50
0

You can use Proxy.

If you have an interface like this:

public interface ICL1 {

    public String foo();

    public String bar(String x);
}

and a class like this:

public class CL1 implements ICL1 {

    @Override
    public String foo() {
        return "foo";
    }

    @Override
    public String bar(String foo) {
        return foo + "bar";
    }

}

you can proxy it like this:

public class TProxy<T> implements InvocationHandler {

    private final ExecutorService exe = Executors.newCachedThreadPool();

    public final Object object;

    private TProxy(T object) {
        this.object = object;
    }

    public static <U> U getProxy(Class<U> intf, U target) {
        return (U) Proxy.newProxyInstance(target.getClass().getClassLoader(), new Class[]{intf}, new TProxy(target));
    }

    @Override
    public Object invoke(Object target, Method method, Object[] args) throws Throwable {
        Future f = exe.submit(() -> method.invoke(object, args));
        return f.get();
    }

}

and then you can use the proxy like this:

System.out.println(TProxy.getProxy(ICL1.class, new CL1()).foo());

Spring does it all the time ;). Enjoy.

Note: this does not take care of the callback. My suggestion would be to annotate your methods with your own home cooked annotation containing some reference to a callback, possibly another Runnable, or the name of a method in your interface. You can then use the annotation in the invoke method of the Proxy. Make sure your annotation has retention Runtime.

Deroude
  • 1,052
  • 9
  • 24