在OnClick期间显示多个TextView更改

问题描述 投票:-1回答:3

我目前正在开发一款使用蓝牙,GPS并将数据上传到远程服务器的应用程序。我有一个简单的按钮,它启动一系列事件和线程,以便让一切工作在一起。

我现在在屏幕上添加TextView组件,向用户显示正在发生的更详细的过程。 GPS正在运行吗?我的蓝牙设备是否已连接?等等。这个过程可能需要10秒钟,这就是为什么我要添加更多关于后台发生的事情的信息。

但是,当我单击我的按钮时,只会显示最后一个更改。我想TextView组件是在Onclick之后呈现的?

一个例子:

 @Override
 public void onClick(View view) {
     textView.setText(R.string.launching_text);
     // start a thread
     textView.setText(R.string.start_new_thread);
     // start another thread
     textView.setText(R.string.almost_there);
     // start last thread
     textView.setText(R.string.done);
 }

想象一下这个过程大约需要10秒钟。它看起来像应用程序“冻结”,但直到OnClick完成后才能看到更改。

如何在OnClick活动期间实时显示我的信息?是否有更好的做法?是否有可能采取某种方式异步推动TextView变化?

android
3个回答
1
投票

我建议你先检查一下this Android Performance Patterns video,看看你可以使用的一些选项。我还建议不要在生命周期环境中执行多线程(例如ActivitiesFragments),因为这只是在寻找麻烦。

在你的onClick例子中,R.string.done可以(并且很可能会)在第一个线程完成其工作之前显示。我假设那不是你想要的。

我不知道你正在处理的问题,你正在使用的工具或你正在关注的架构,所以这里有一个稍微通用的方法来使它工作。你的Thread实现中的每个onClick都具有各种状态。您可以使用简单的抽象在代码中表示:

class Holder {
  @StringRes int status;
  Runnable runnable;

  Holder(@StringRes int status, @NonNull Runnable runnable) {
    this.status = status;
    this.runnable = runnable;
  }
}

注意使用Runnable而不是Thread

你也在按顺序执行事情。您可以使用简单的ListQueue在代码中表示这一点,从而提供流畅,富有表现力的API,例如:

class StatusRunnableBuilder {
  private final WeakReference<TextView> viewRef;
  private final Queue<Holder> queue;
  @StringRes private int finalStatus;

  StatusRunnableBuilder(@NonNull TextView view) {
    viewRef = new WeakReference<>(view);
    queue = new ArrayDeque<>();
  }

  StatusRunnableBuilder addStep(@StringRes int status,
                                @NonNull Runnable runnable) {
    queue.add(new Holder(status, runnable));
    return this;
  }

  StatusRunnableBuilder withFinalStatus(@StringRes int status) {
    finalStatus = status;
    return this;
  }

  Runnable build() {
    return new Runnable() {
      @Override
      public void run() {
        for (Holder item: queue) {
          updateStatus(item.status);
          item.runnable.run();
        }
        if (finalStatus != 0) {
          updateStatus(finalStatus);
        }
      }
    };
  }

  private void updateStatus(@StringRes final int status) {
    final TextView view = viewRef.get();
    if (view != null) {
      view.post(new Runnable() {
        @Override
        public void run() {
          // As this has been posted to a queue,
          // it could have been processed with some delay,
          // so there is no guarantee the view is still present.
          // Let's check again.
          final TextView v = viewRef.get();
          if (v != null) {
            v.setText(status);
          }
        }
      });
    }
  }
}

然后你的onClick变成了:

@Override
public void onClick(View v) {
  final Runnable runnable = new StatusRunnableBuilder(view)
    .addStep(R.string.launching_text, launchingRunnable)
    .addStep(R.string.almost_done, almostDoneRunnable)
    .withFinalStatus(R.string.finally_done)
    .build();
  service.execute(runnable);
}

其中service是一个ExecutorService,它允许你在任何生命周期事件上创建/关闭,例如:

@Override
protected void onStart() {
  super.onStart();
  service = Executors.newSingleThreadExecutor();
}

@Override
protected void onStop() {
  super.onStop();
  service.shutdownNow();
}

0
投票

你可以使用RunnableHandlerHandler将在一定时间间隔后向Runnable发布更新。

对于蓝牙连接,您也可以使用广播接收器。


0
投票

您可以尝试使用AsyncTask。它非常简单,它可以处理所有后台线程以及线程间通信。有几个注意事项,为避免内存泄漏,您可以使用EventBus或类似的机制。这是我发现非常有用的文章:

http://simonvt.net/2014/04/17/asynctask-is-bad-and-you-should-feel-bad/

© www.soinside.com 2019 - 2024. All rights reserved.