UI线程

时间:2016-07-22 10:05:09

标签: java design-patterns

我正在设计一个大量使用异步代码完成块的API。

public interface IResult<T extends Result.I> {
    void onResult(T);
}

public void doXYZ(IResult<Result.TypeA> iResult) { ... }

用户将调用我的API的doXYZ(),然后单独的网络工作线程将调用iResult.onResult()。有时他并不关心onResult()被调用哪个线程,有时他可能只想更新UI - 只是想找到一种方法来无形地减轻用户的负担,这样他们就可以保留他们的匿名内部类整洁而小巧。

此API适用于Android,其中许多(但不是全部)用户可能希望在影响UI元素的onResult()回调中执行某些操作,因此必须在UI线程上运行其代码。用户不必为使用runOnUIThread(...)调用弄脏代码而负担,我想知道人们是否知道在doXYZ()调用时,设计模式会变得简单,供用户指定是否在其UI线程上调用回调。

  1. 出于性能原因,我不要强迫我的API始终在UI线程上调用onResult()。

  2. 我见过的一种模式是添加一个方法参数:doXYZ(...,boolean callOnUIThread)。但是,由于API已经过记录,因此我不会通过使用所有这些额外的布尔值来弄脏文档(和方法签名)。

  3. 另一个想法是重载每个doXYZ(),有一个有一个没有callOnUIThread参数,但由于膨胀,这对于文档来说非常糟糕。

  4. 我的另一个想法是在onResult()之外向IResult添加一个onResultUI()方法,但这会让用户必须始终在匿名中定义这两个代码。类。

  5. 有关实现这一目标的干净方法的任何建议:  一世。简洁  II。非常适合代码可读性  III。简单的文档 ?

1 个答案:

答案 0 :(得分:2)

IResult使用装饰器模式。

E.g。如果你有一个接口IResult(我只是让演示的通用类型T更容易)

interface IResult<T> {
  void onResult(T result);
}

和像这样的结果回调实现

class PrintCurrentThreadAndResult implements IResult<String> {
   @Override
   public void onResult(String result) {
   Thread thread = Thread.currentThread();
    System.out.print(thread.getName());
    System.out.print(" - ");
    System.out.println(result);
   }
}

你可以创建一个装饰器,确保在特殊线程(例如ui线程)上调用装饰结果。我在这里使用swing的事件调度程序线程,这样每个人都可以轻松地编译和测试它。

class UIThreadAwareResult<T> implements IResult<T> {

  private IResult<T> delegate;

  public UIThreadAwareResult(IResult<T> delegate) {
    this.delegate = delegate;
  }

  @Override
  public void onResult(T result) {
    invokeOnUIThread(result);
  }

  private void invokeOnUIThread(final T result) {
    try {
      EventQueue.invokeAndWait(new Runnable() {
        @Override
        public void run() {
          delegate.onResult(result);
        }
      });
    } catch (Exception e) {
      throw new RuntimeException(e);
    }
  }
}

客户端代码然后可以通过装饰原始结果来选择要运行的线程。

public class Main {

  public static void main(String[] args) {
    Main main = new Main();

    IResult<String> result = new PrintCurrentThreadAndResult();
    main.doXYZ(result);

    IResult<String> uiThreadAwareResult = new UIThreadAwareResult<String>(result);
    main.doXYZ(uiThreadAwareResult);
  }

  public void doXYZ(IResult<String> iResult) {
    iResult.onResult("Hello");
  }
}

输出

main - Hello
AWT-EventQueue-0 - Hello