如何实现.get功能与FutureTask或BackgroundTask使用android



我正在制作一个android库。在我的库中,我想允许用户在后台或主线程中执行特定的任务。

我想做这样的事情。

<

1场景/strong>

MyLibabry.with(context)
     .performSomeTask(<params>)
     .execute();

当用户编写上面的代码片段时。任务应该在后台执行。因此,我将返回使用任何侦听器的任务结果。

现在考虑下面的代码片段:

<

第二场景/strong>

Result result = MyLibabry.with(context)
     .performSomeTask(<params>)
     .get();

现在,当用户在语句末尾附加get()时。任务应该在主线程上执行,并阻塞其他线程。这就是为什么result被立即初始化的原因。

所以我的问题是我如何实现的功能,如果用户附加。get(),该线程在performSomeTask()应该运行在主线程上。否则在后台。

注意:不要关注返回结果。我将在Java泛型中实现它。我想知道的是如何使代码可重用,以便当用户只附加.get()时,它将在主线程上运行。否则,相同的代码应该在后台运行。我不想写重复的代码

您可以参考现有的库。

  • AsyncTask - Android官方执行后台任务。
  • ION -用于下载/上传文件

所以两个库有相同的功能,还有很多库有相同的功能,我也想这样做。

如果有人为我提供一个小例子,那将是伟大的。

(我希望,您在上面的例子中明确了返回值)所以这是您的任务的几种类型的单一解决方案。仔细观察在新线程中运行任务。你需要在后台ThreadPool....

启动你的动作

注意!(我也希望你澄清使用后台线程。例如,使用上面的代码与函数。execute() -不启动新线程,而只是将新任务从BlockingQueue中执行到静态ThreadPool)

那么下一步是什么?使用function .get()在主线程中执行任务,您需要在当前动作循环中发布此任务。你要帮助汉德勒和环形使者。回答你的问题,你应该知道,你只有一种方法来完成这个任务。使用。execute()方法在后台线程中启动操作,并使用。get()方法在Handler中启动新任务。就这些!


如果你想知道一些实现的例子,有很多种解决方案。我只是发布了一个使用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)
    }
}

您必须使用Future Task类在后台执行任务。

<

1场景/strong>如果任务在后台,那么您将使用结果接口方法返回。

<

第二场景/strong>如果任务在前台,那么您将直接向调用类返回输出。

execute()

示例代码
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();
    }

这里不是要打破任何泡沫,但我们不只是重新创建java.util.concurrent.Executors,这已经是android的最佳实践,用于灵活的并发任务(即线程"处理程序管理)

源自:android.os.AsyncTask

AsyncTask被设计成一个围绕Thread和Handler的helper类并且不构成一个通用的线程框架。asynctask理想情况下,应该将其用于短期操作(在大多数)。如果你需要让线程长时间运行,强烈建议您使用java.util.concurrent包,如Executor, ThreadPoolExecutor和FutureTask .

From: java.util.concurrent.Executors

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);
     }
   }
 }

这些都是课本上的例子,但很容易看出,因为它已经在那里了,我们不需要重新创建轮子,特别是当它已经支持MoinKahn正在努力实现的那种包装,并且已经是最佳实践。

我想我应该添加一个链接到Oracle的Executor Interface页面,以获得更多关于正确并发处理和包装Executor服务的信息。

编辑:此外,这里有一个非常好的FutureTask示例,使用ThreadPoolExecutor在Gray的深入回答中。

相关内容

  • 没有找到相关文章

最新更新