如何使用后台任务/异步任务编写更线性可读的Java代码

huangapple go评论83阅读模式
英文:

How to make linear/more readable Java code with background/asynctask

问题

以下是翻译好的代码部分:

此刻我有如下代码

public class SomeActivity {
 void onCreate() {
  doSomething();
  if (weNeedToDoSomeAsncTask()) {
   new SomeAsyncTask(afterSomeAsyncTask).execute();
  } else {
   new DifferentAsyncTask(afterAnotherAsyncTask).execute();
  }
 }

 PostExecute afterSomeAsyncTask = new PostExecute() {
  void Callback(String response) {
   doSomethingElse(response);
   new DifferentAsyncTask(afterAnotherAsyncTask).execute();
  }
 }
}

这个代码在表面上看起来还不错,但我已经大大简化了代码,你可以想象当你有多个调用并且出现一些分支情况时,它会变得多么复杂。

为了帮助理解,实际用例通常是这样的:

  • 使用SDK获取一些设备/用户信息
  • 使用返回的信息进行Web服务身份验证
  • 将一些日志信息发送到Web服务
  • 从Web服务获取一些数据
  • 从Web服务获取一些其他数据
  • 使用这些数据生成UI

我希望我的代码看起来更像这样:

public class SomeActivity {
 void onCreate() {
  doSomething();
  if (weNeedToDoSomeAsncTask()) {
   new SomeAsyncTask().execute();
   doSomethingElse(response);
  } 
  new DifferentAsyncTask().execute();
  afterAnotherAsyncTask();
 }
}

我以前尝试过使用.get(),但遇到了问题,但从来没有搞清楚为什么(可能是因为我试图在一个AsyncTask内部调用另一个,我听说这是不推荐的,但那是很久以前,所以不能确定)。虽然我知道.get在某种程度上违反了AsyncTask的初衷,但我之所以使用它,是因为Java强制我这样做(用于网络通信等)。我的应用程序依赖于结果才能继续,直到它返回为止,无法执行其他任何操作。

我应该再试一次.get()技术吗?还是这是一个非常糟糕的主意?

我应该只是接受代码变得更难阅读,然后需要跳转到回调方法以尝试理解代码流程吗?

还是有其他选择?

我也刚刚了解到了一个很不错的库 Needle,看起来像是这样的:

NetworkService networkService = new NetworkService();
Needle.onBackgroundThread().serially().execute(networkService);
String result = doSomethingWithResponse(networkService.response);
AnotherNetworkService anotherNetworkService = new AnotherNetworkService(result);
Needle.onBackgroundThread().serially().execute(anotherNetworkService);

但也许这与AsyncTask.get()方法是一样的?


<details>
<summary>英文:</summary>

At the moment I have something like;

public class SomeActivity {
void onCreate() {
doSomething();
if (weNeedToDoSomeAsncTask()) {
new SomeAsyncTask(afterSomeAsyncTask).execute();
} else {
new DifferentAsyncTask(afterAnotherAsyncTask).execute();
}
}

PostExecute afterSomeAsyncTask = new PostExecute() {
void Callback(String response) {
doSomethingElse(response);
new DifferentAsyncTask(afterAnotherAsyncTask).execute();
}
}
}


This doesn&#39;t look too bad on the face of it, but I have hugely simplified the code and you can imagine how complex it becomes when you have more than a few calls going on and some branching starts to happen.

To help with context, the actual use case is normally something like;

 - use an sdk to get some device/user information
 - use the returned information to authenticate with a web service
 - send some logging info to the web service
 - get some data from the web service
 - get some other data from the web service
 - use that data to generate the UI

I would prefer my code to look a bit more like;

public class SomeActivity {
void onCreate() {
doSomething();
if (weNeedToDoSomeAsncTask()) {
new SomeAsyncTask().execute();
doSomethingElse(response);
}
new DifferentAsyncTask().execute();
afterAnotherAsyncTask();
}
}


I have tried used `.get()` in the past and had issues but never got to the bottom of why (potentially I was trying to call one `AsyncTask` inside another, which I&#39;ve read is a no go- but it was a long time ago so can&#39;t be sure). Whilst I realise `.get` somewhat defeats the object of `AsyncTask`, I am only using it because Java forces me to (for network communication etc). My application is relying on the result to continue and can&#39;t do anything else till it returns anyway.

Should I try the `.get()` technique again? Or is it a really bad idea?

Should I just suck it up and realise the code is harder to read and I will need to jump to the callback methods to try and understand the code flow?

Or is there a different option?

I have also just learnt of Needle which looks like quite a nice library https://zsoltsafrany.github.io/needle/ and I think I could do more like;

NetworkService networkService = new NetworkService();
Needle.onBackgroundThread().serially().execute(networkService);
String result = doSomethingWithResponse(networkService.response);
AnotherNetworkService anotherNetworkService = new AnotherNetworkService(result);
Needle.onBackgroundThread().serially().execute(anotherNetworkService);


But perhaps this is exactly the same as the `AsyncTask.get()` approach?

</details>


# 答案1
**得分**: 1

Kotlin协程。

<details>
<summary>英文:</summary>

The TL;DR of any answer really will be: Kotlin coroutines.

</details>



# 答案2
**得分**: 1

以下是翻译好的部分:

看一下[ScheduledThreadPoolExecutor](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ScheduledExecutorService.html),你可以这样获取它:

```java
ExecutorService executor = Executors.newScheduledThreadPool(8);

有多种方法用于调度未来的任务。

你的第一个示例可能会像这样:

public class SomeActivity {
 void onCreate() {
  doSomething();
  if (weNeedToDoSomeAsncTask()) {
   executor.submit(() -&gt; /* 异步任务 */);
   doSomethingElse(response);
  } 
  executor.submit(() -&gt; /* 不同的异步任务 */)
  afterAnotherAsyncTask();
 }
}

(尽管你需要查看替代阻塞/加入的具体方法。)

英文:

Take a look at ScheduledThreadPoolExecutor which you can obtain like:

ExecutorService executor = Executors.newScheduledThreadPool(8);

There are numerous methods for scheduling futures.

Your first example might look like:

public class SomeActivity {
 void onCreate() {
  doSomething();
  if (weNeedToDoSomeAsncTask()) {
   executor.submit(() -&gt; /* async task */);
   doSomethingElse(response);
  } 
  executor.submit(() -&gt; /* different async task */)
  afterAnotherAsyncTask();
 }
}

(Although you'll need to look at the specific methods for alternatives to block/join.)

huangapple
  • 本文由 发表于 2020年7月29日 12:50:20
  • 转载请务必保留本文链接:https://go.coder-hub.com/63146545.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定