Как реализовать функцию .get с помощью FutureTask или BackgroundTask с помощью Android?
Я делаю одну андроидную библиотеку. И в моей библиотеке я хочу разрешить пользователю выполнять конкретную задачу либо в фоновом режиме, либо в основном потоке.
Я хочу сделать что-то вроде этого.
1-й сценарий
MyLibabry.with(context)
.performSomeTask(<params>)
.execute();
Когда пользователь записывает вышеуказанный код фрагмента. задача должна выполняться в фоновом режиме. Поэтому я верну результат задачи с помощью любых слушателей.
Теперь рассмотрим приведенный ниже фрагмент кода.
2-й сценарий
Result result = MyLibabry.with(context)
.performSomeTask(<params>)
.get();
Теперь, когда пользователь присоединяет get() в конце инструкции. Задача должна выполняться в основном потоке и блокировать другие потоки. Поэтому результат инициализируется немедленно.
Итак, мой вопрос заключается в том, как я могу реализовать функцию, которая, если пользователь прикрепляет файл .get(), этот поток в performSomeTask()
должен запускаться в основном потоке. иначе в фоновом режиме.
Примечание. Не фокусируйтесь на возвращении результата. Я буду реализовывать его в Java Generics. Я хочу знать, как сделать код повторно используемым, чтобы при подключении пользователя .get()
он запускался в основном потоке. В противном случае этот же код должен работать на фоне. Я не хочу писать повторяющийся код.
Вы можете ссылаться на существующую библиотеку.
- AsyncTask - официальный представитель Android для выполнения фоновой задачи.
- ION - для загрузки/выгрузки файла
Итак, у двух библиотек есть одна и та же функция, и есть много другой библиотеки, которая делает то же самое, и я хочу сделать то же самое.
Будет здорово, если кто-нибудь предоставит мне небольшой пример для этого.
Ответы
Ответ 1
(Надеюсь, вы уточните с возвращаемыми значениями в приведенных выше примерах). Это несколько типов решения для вашей задачи. Посмотрите внимательно на выполнение задачи в новом потоке. Вам нужно начать действие в фоновом режиме ThreadPool....
Примечание! (Также надеюсь, что вы уточните с использованием фоновых потоков. Например, используя ваш код выше с функцией .execute() - не запускает новый поток, а просто ставит новую задачу для выполнение из BlockingQueue в статическом ThreadPool)
Так что же дальше?
Используя функцию .get() для выполнения задачи в MainThread, вам нужно опубликовать эту задачу в текущем цикле действий. И вы поможете Хендлеру и Луперу. И, отвечая на вопрос, вы должны знать, что у вас есть только один способ решения этой задачи. Запуск действия в фоновом потоке с использованием метода .execute() и запуск новой задачи обработчику с помощью метода .get(). Это все!
Если вы хотите узнать о некоторых примерах реализации, существует много видов решений. Я просто размещаю сингл с помощью Handler и HandlerThread для занижения работы этого примера.
public class MyLibrary extend HandlerThread {
private static Handler backgroundHandler;
private static Handler foregroundHandler;
private static MyLibrary myLibrary
private MyLibrary () {
super(MyLibrary.class.getSimpleName());
start();
}
public static MyLibrary getInstance() {
if (myLibrary == null) {
synchronized (MyLibrary.class) {
if (myLibrary == null) {
myLibrary = new MyLibrary();
}
}
}
return myLibrary;
}
public static WorkingTask with (Context context) {
//Just update, if there are null
if (foregroundHandler == null) {
foregroundHandler = new Handler(context.getMainLooper);
}
if (backgroundHandler == null) {
backgroundHandler = new Handler(getLooper);
}
return new WorkingTask();
}
public void getBackgroundHandler () {
return backgroundHandler;
}
public void getForegroundHandler () {
return foregroundHandler;
}
}
// ..........
public class WorkingTask {
private Runnable workingRunnable;
public performTask (Runnable run) {
this.workingRunnable = run;
return this;
}
public void execute () {
MyLibrary.getInstance().getBackgoundHandler()
.postRunnable(workingRunnable)
}
public void get () {
MyLibrary.getInstance().getForegroundHanlder()
.postRunnable(workingRunnable)
}
}
Ответ 2
Вы должны использовать Будущая задача для выполнения задачи в фоновом режиме.
1-й сценарий
Если задача находится в фоновом режиме, вы вернетесь с использованием метода интерфейса результата.
2-й сценарий
Если задача находится на переднем плане, вы вернете вывод непосредственно в вызывающий класс.
Пример кода для выполнения()
public void execute() {
new Thread(new Runnable() {
@Override
public void run() {
Future future = mExecutorService.submit(mCursorBinderTask);
Log.d("asd", "onCreate: started ");
while (true) {
if (future.isDone()) {
if (mResultListener != null) {
try {
mResultListener.onResult(future.get());
} catch (InterruptedException e) {
mResultListener.onResult(null);
} catch (ExecutionException e) {
mResultListener.onResult(null);
}
}
break;
}
}
}
}).start();
}
Пример кода для get()
public ArrayList<T> get() throws ExecutionException, InterruptedException {
return mCursorBinderTask.call();
}
Ответ 3
Не означает, что здесь всплывают пузырьки, но мы просто не воссоздаем java.util.concurrent.Executors
. Это уже самая эффективная практика Android для использования для гибких параллельных задач (т.е. управления потоками и обработчиками)
От: android.os.AsyncTask
AsyncTask предназначен для вспомогательного класса вокруг Thread and Handler и не представляет собой общую структуру потоков. AsyncTasks в идеале следует использовать для коротких операций (несколько секунд на большинство.) Если вам нужно поддерживать потоки в течение длительного времени, настоятельно рекомендуется использовать различные API-интерфейсы, предоставляемые пакет java.util.concurrent, такой как Исполнитель, ThreadPoolExecutor и FutureTask.
От: java.util.concurrent.Executors
Factory и утилиты для Executor, ExecutorService, Определены классы ScheduledExecutorService, ThreadFactory и Callable в этом пакете. Этот класс поддерживает следующие методы:
- Способы создания и возврата службы ExecutorService с использованием обычно полезных настроек конфигурации.
- Способы создания и возврата ScheduledExecutorService с использованием обычно полезных настроек конфигурации.
- Способы создания и возврата "завернутого" ExecutorService, который отключает реконфигурацию, применяя методы, специфичные для реализации недоступны.
- Методы, которые создают и возвращают ThreadFactory, который устанавливает новые созданные потоки в известное состояние.
- Методы, которые создают и возвращают Callable из других закрывающих форм, поэтому их можно использовать в методах выполнения, требующих Callable.
Для примера (и то, что я считаю, Fildor пытался получить):
//An Executor and a set of RunnableTasks to be executed
Executor executor = anExecutor();
executor.execute(new RunnableTask1());
executor.execute(new RunnableTask2());
Самый простой способ прямого выполнения в потоке вызывающего:
class DirectExecutor implements Executor {
public void execute(Runnable r) {
r.run();
}
}
Это не асинхронный вызов, но может быть легко выполнен как один, а не только фоновый поток, вот версия, которая порождает новый поток для каждой задачи:
class ThreadPerTaskExecutor implements Executor {
public void execute(Runnable r) {
new Thread(r).start();
}
}
И вы можете навязывать любые ограничения, такие как серийное исполнение:
class SerialExecutor implements Executor {
final Queue<Runnable> tasks = new ArrayDeque<>();
final Executor executor;
Runnable active;
SerialExecutor(Executor executor) {
this.executor = executor;
}
public synchronized void execute(final Runnable r) {
tasks.add(new Runnable() {
public void run() {
try {
r.run();
} finally {
scheduleNext();
}
}
});
if (active == null) {
scheduleNext();
}
}
protected synchronized void scheduleNext() {
if ((active = tasks.poll()) != null) {
executor.execute(active);
}
}
}
Это все примеры текстовых книг, но легко видеть, что, поскольку он уже там, нам не нужно воссоздавать колесо, особенно когда оно уже поддерживает тип упаковки, которую MoinKah пытается достичь и уже лучше практика.
Думаю, я добавлю ссылку на страницу Oracle Executor Interface, для получения дополнительной информации о правильной обработке concurrency и обертке служб Executor.
Edit: Кроме того, здесь представлен действительно хороший пример FutureTask с помощью ThreadPoolExecutor для углубленного ответа от Gray об этом.