Most concise way to run a simple background task?

2019-06-24 08:40发布

问题:

I've seen at least five patterns through which you can have some code to run in a worker thread. Most simple:

new Thread(new Runnable() {
    public void run() {
      //
    }
}).start();

We can extend AsyncTask; we have AsyncTaskLoader and other Loaders for data, Services and so on.

I assume each one of those has some advantages which I'm not discussing here. What I'm wondering is: which is the most appropriate, concise way to run a simple action?

Defining simple:

  • Quite short action, <1s;
  • No need to deal with UI elements;
  • One line command or such, so it looks inappropriate to extend AsyncTask with a new class;
  • No need to be notified about the success of the task in an Activity or Fragment;
  • No need to display progress;
  • Just need to have some kind of return.

What I thought at first was:

boolean myReturn;

new Thread(new Runnable() {
    public void run() {
      myReturn = myExtensiveTask();
    }
}).start();

public boolean myExtensiveTask() { ... }

Would this be correct (or even possible)? How should this be done?

回答1:

Using the bolts utility framework (used by Facebook and parse.com), it is simple as that:

Task.callInBackground(new Callable<MyReturnType>() {
    @Override
    public MyReturnType call() {
        MyReturnType obj = doWork();
        return obj;
    }
});


回答2:

The best solution would probably involve some library code.

I've implemented something in my current project that allows me to write a method like this:

@QSchedule("0 * * * * ?")
public void runsEveryMinute()
{
    System.out.println("It ran!");
}

We use these all over the place now. The scheduler works on top of QuartzScheduler. I believe spring allows syntax a lot like this just by importing Quartz support.

If you are creative, a lot of solutions can work this way. For instance if you had a class that built menus then you could abstract all the menu-building syntax and drive it with annotations. I've done this as well. The structure might be something like this:

@MenuItem("File","Save")
public void fileSave() {
    // This is executed when file save is selected
}
@MenuItem("File","Load")
public void fileLoad() {
    // Executed when file load is seleclted
}

These annotations provide all the information you need to build your entire menu system, so another class just walks through your annotated class and builds the menu for it. Somewhere you have code that looks like this:

 Menu mainMenu = new MenuBuilder().buildMenu(MenuDefinition.class);

Where MenuDefinition.class contains annotations like above. The nicest thing about this solution? 100% reusable--just drop it into any project and you never have to manually build a menu again (Or a button, or whatever other redundant task is bothering you).

I'm not saying this will directly solve your problem, what I'm saying is you may want to code a little infrastructure to make your future calls simpler. Annotations are a pretty cool way to indicate what code you want to run since Java has such ugly anonymous inner class syntax.

Oh also Java 8 should make what you want to do trivial. In Groovy (Which has closures much like Java 8) you can use something very close to this:

new Thread() {
    println "this will run in another thread"
}

(I cant guarantee that's the exact syntax, but it's really close)