ilovecomputer66 发表于 2023-10-30 15:31

一个安卓开发的小白问题,怎么写代码实现新线程请求网络API成功后,才让主UI线程继续

本帖最后由 ilovecomputer66 于 2023-10-30 16:22 编辑

临时被征调安排去用java安卓开发一个小app,没做过这个。之前都是写C#,C#中用 await async就直接能实现了。搜了半天,都是用kotlin协程。但我这个项目是用java不是kotlin

问下开发过安卓的朋友。怎么实现呢。 就是UI主线程,需要请求新线程服务器(我看到安卓不允许主线程请求网络),拿到服务器返回数据后才能处理,展示UI

(不能是简单在新线程中,收到服务器response后,runPnUiThread做事情。我要求的是,等待服务器响应,也就是等待新线程执行完之前,主UI线程不能执行代码)

可能我上面说的不够明确,使得下面回复的朋友全都误解了(都不是我想要的)

我重新说一下

我要这么一个函数,private String reqAndGetResultUsername(xxxx一些参数)   在这个函数里面,请求服务器,并且拿到返回的userName(该函数里面不要有任何掺杂了runInUiThread的东西,就是单纯的逻辑,请求服务器,把结果返回)
而主UI线程中,假如用C#代码写就是写为await 上面函数,拿到结果后,继续执行下面的代码


所以,我想问的其实是:在这个reqAndGetResultUsername中,如何实现,等待服务器返回结果后,才return结果。

Nettos 发表于 2023-10-30 15:44

使用AsyncTask配合同步等待

蓝莲花 发表于 2023-10-30 15:57

本帖最后由 蓝莲花 于 2023-10-30 16:01 编辑

【替你问了下 chatgpt】

在 Android 开发中,你可以使用 Java 来实现在 UI 主线程中请求服务器并等待服务器响应的功能,而不是简单地在新线程中请求服务器然后使用 `runOnUiThread` 来处理响应。这可以通过使用 `AsyncTask` 或 `Handler` 来实现。以下是两种常见的方法:

### 使用 AsyncTask:

AsyncTask 是 Android 提供的一个用于在后台线程执行异步任务的工具,它可以很方便地在后台线程中执行网络请求等操作,然后将结果传递回主线程以更新 UI。以下是一个示例:

public class MyAsyncTask extends AsyncTask<Void, Void, String> {
    @Override
    protected String doInBackground(Void... params) {
      // 在后台线程中进行网络请求
      String result = performNetworkRequest();
      return result;
    }

    @Override
    protected void onPostExecute(String result) {
      super.onPostExecute(result);
      // 在主线程中更新 UI,result 包含了服务器响应数据
      updateUI(result);
    }
}

// 启动 AsyncTask
MyAsyncTask myAsyncTask = new MyAsyncTask();
myAsyncTask.execute();


在这个示例中,doInBackground 方法用于在后台线程中执行网络请求,然后 onPostExecute 方法用于在主线程中更新 UI。

### 使用 Handler:

你也可以使用 Handler 来实现在主线程中等待服务器响应的功能。你可以创建一个 Handler 对象,并将它用于在后台线程中发送消息给主线程,以触发 UI 更新操作。以下是一个示例:

Handler handler = new Handler(Looper.getMainLooper());

// 在后台线程中执行网络请求
new Thread(() -> {
    String result = performNetworkRequest();

    // 发送消息给主线程
    handler.post(() -> {
      // 在主线程中更新 UI,result 包含了服务器响应数据
      updateUI(result);
    });
}).start();


在这个示例中,我们创建了一个新的线程来执行网络请求,然后使用 Handler 将结果发送到主线程以进行 UI 更新。

这两种方法都允许你在主线程中等待服务器响应,然后再执行 UI 更新操作,而不需要使用 Kotlin 协程。请选择适合你的需求和项目的方法。

fengxi 发表于 2023-10-30 15:57

安卓不是不允许主线程(UI线程)请求网络,只是会因为网络延迟问题堵塞从而导致可能会卡死或者带来不好的体验。

我可以给个思路你结合实际使用:

1. 开启线程来发起网络请求;
2. 将网络请求响应数据更新到UI上。

下面是示例代码。
```java
new Thread(new Runnable() {
    @Override
    public void run() {
      // 1、写网络请求代码
                               
      // 2、(如需要将响应数据显示到UI就执行这个)网络请求响应后需要调用runOnUiThread才能再子线程更新UI。
      runOnUiThread(new Runnable() {
            @Override
            public void run() {
                // 我是更新UI代码...
            }
      });
    }
});
```
大体是这样的思路,你可以解一下耦,便以后期维护。


fengxi 发表于 2023-10-30 16:05

本帖最后由 fengxi 于 2023-10-30 16:11 编辑

fengxi 发表于 2023-10-30 15:57
安卓不是不允许主线程(UI线程)请求网络,只是会因为网络延迟问题堵塞从而导致可能会卡死或者带来不好 ...
你发起请求之后就弹出ProgressDialog 并且屏蔽返回键让它转圈圈,等数据响应了在调用runOnUiThread,在里面把ProgressDialog 关掉不就好了。
示例代码
```
ProgressDialog waitingDialog = new ProgressDialog(MainDialogActivity.this);
waitingDialog.setTitle("这是一个等待Dialog");
waitingDialog.setMessage("请等待...");
waitingDialog.setIndeterminate(true);
waitingDialog.setCancelable(false);//为false时屏幕不可点击,设置为不可取消
waitingDialog.show();
```

ilovecomputer66 发表于 2023-10-30 16:13

fengxi 发表于 2023-10-30 15:57
安卓不是不允许主线程(UI线程)请求网络,只是会因为网络延迟问题堵塞从而导致可能会卡死或者带来不好 ...

这就是我1楼括号里说的不要这样的

fengxi 发表于 2023-10-30 16:22

ilovecomputer66 发表于 2023-10-30 16:13
这就是我1楼括号里说的不要这样的

你这个结果返回到哪里?返回到UI上?

ilovecomputer66 发表于 2023-10-30 16:23

————————————————————————————————————————————

不好意思,我之前没说清楚。上面不要我想问的意思和想要的。重新进行说明了

ilovecomputer66 发表于 2023-10-30 16:41

fengxi 发表于 2023-10-30 16:22
你这个结果返回到哪里?返回到UI上?

就是我1楼红字补充的

补补23456 发表于 2023-10-30 16:52

同4楼,我的第一想法也是加个dialog挡一下,毕竟人家安卓都不让你在UIthread做耗时操作了

如果非要的话,可以试试

Executors.newSingleThreadExecutor().submit(()->{
//网络操作
}).get();

拉姆达表达式里写网络请求,这个会运行在一个新的线程里,然后 .get()是一直等到线程函数返回结果为止(文档说明:Waits if necessary for the computation to complete, and then retrieves its result.)
页: [1] 2
查看完整版本: 一个安卓开发的小白问题,怎么写代码实现新线程请求网络API成功后,才让主UI线程继续