Discuz! BBS

 找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 183|回复: 1

在我调用了BackgroundService.doBackgroundWork()之后,手机界面显...

[复制链接]

394

主题

559

帖子

3303

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
3303
发表于 2025-9-12 16:10:34 | 显示全部楼层 |阅读模式
在我调用了BackgroundService.doBackgroundWork()之后,手机界面显示程序没有响应,怎么办

当您调用 doBackgroundWork() 后出现"程序没有响应"(ANR)的问题,主要原因是 Translate() 方法在主线程中执行了耗时操作。

问题分析
从代码可以看出:
1、doBackgroundWork() 中调用了 Translate()
2、Translate() 中调用了 llm.MyLlmDeal(text),这是一个网络请求操作
3、虽然 BackgroundService 在 onStartCommand() 中创建了线程,但您从 IatDemo 调用 doBackgroundWork() 时是在主线程中执行的


解决方案
方案一:修改 doBackgroundWork() 为异步执行


doBackgroundWork() 方法改为总是异步执行:
  1. public void doBackgroundWork() {
  2.     // 创建新线程执行耗时操作
  3.     new Thread(new Runnable() {
  4.         @Override
  5.         public void run() {
  6.             String textToLlm = getDataToLlm();
  7.             String resultTranslate = Translate(textToLlm);
  8.             Log.d("BackgroundService", "resultTranslate: " + resultTranslate);
  9.             // 如果需要更新UI,使用Handler或Broadcast发送消息
  10.         }
  11.     }).start();
  12. }
复制代码

方案二:在 IatDemo 中异步调用

修改 IatDemo 中的 callLlm2() 方法:
  1. private void callLlm2(String text, String caller) {
  2.     Log.i(TAG, caller + ", before call bkground service.");
  3.     mService.setDataToLlm(text);
  4.    
  5.     // 异步执行,避免阻塞主线程
  6.     new Thread(new Runnable() {
  7.         @Override
  8.         public void run() {
  9.             mService.doBackgroundWork();
  10.         }
  11.     }).start();
  12. }
复制代码


方案三:使用现成的 backgroundThread

修改 BackgroundService 中添加一个公共方法:
  1. // 在 BackgroundService 中添加
  2. public void startTranslationWork() {
  3.     if (backgroundThread == null || !backgroundThread.isAlive()) {
  4.         backgroundThread = new Thread(new Runnable() {
  5.             @Override
  6.             public void run() {
  7.                 doBackgroundWork();
  8.             }
  9.         });
  10.         backgroundThread.start();
  11.     }
  12. }
复制代码
然后在 IatDemo 中调用:
  1. private void callLlm2(String text, String caller) {
  2.     Log.i(TAG, caller + ", before call bkground service.");
  3.     mService.setDataToLlm(text);
  4.     mService.startTranslationWork(); // 使用专门的线程执行
  5. }
复制代码


推荐方案
推荐使用方案一,因为它确保了 doBackgroundWork() 总是在后台线程执行,无论从哪里调用都不会阻塞主线程。
这样修改后,就不会再出现ANR问题了。

回复

使用道具 举报

394

主题

559

帖子

3303

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
3303
 楼主| 发表于 2025-9-12 16:58:09 | 显示全部楼层
在callLlm2 中想获得mService.getResultTranslate(), 但是doBackgroundWork()可能还没有运行完毕,尚未给mResultTranslate赋值,这里可以引入回调函数吗

是的,您的分析完全正确。由于 doBackgroundWork() 是异步执行的,直接在 callLlm2() 中获取结果会导致获取到旧值或空值。引入回调机制是解决这个问题的最佳方案。

解决方案:使用回调函数
1. 在 BackgroundService 中添加回调支持
首先修改 BackgroundService 类:
  1. public class BackgroundService extends android.app.Service {
  2.     private Thread backgroundThread;
  3.     private String dataToLlm = "";
  4.     private String resultTranslate = ""; // 添加结果存储字段
  5.     private MyJavaOpenAIAPI llm;

  6.     // 定义回调接口
  7.     public interface TranslationCallback {
  8.         void onTranslationComplete(String result);
  9.     }

  10.     public void setDataToLlm(String data) {
  11.         this.dataToLlm = data;
  12.     }
  13.    
  14.     public String getDataToLlm() {
  15.         return this.dataToLlm;
  16.     }
  17.    
  18.     // 提供获取翻译结果的方法
  19.     public String getResultTranslate() {
  20.         return this.resultTranslate;
  21.     }

  22.     private String Translate(String text) {
  23.         // TODO: do your translation work here
  24.         Log.d("BackgroundService", "ToTranslate:" + text);
  25.         if (llm != null){
  26.             if (text.length() == 0) {
  27.                 text = "Now : Llm ready to Translate";
  28.             }
  29.             String llmResult = llm.MyLlmDeal(text);
  30.             return MainActivityKt.wash(llmResult);
  31.         }
  32.         return "Notice : Llm not ready";
  33.     }
  34.    
  35.     // 修改 doBackgroundWork 方法,支持回调
  36.     public void doBackgroundWork(TranslationCallback callback) {
  37.         new Thread(new Runnable() {
  38.             @Override
  39.             public void run() {
  40.                 String textToLlm = getDataToLlm();
  41.                 resultTranslate = Translate(textToLlm); // 保存结果
  42.                 Log.d("BackgroundService", "resultTranslate: " + resultTranslate);
  43.                
  44.                 // 通过回调返回结果
  45.                 if (callback != null) {
  46.                     runOnUiThread(new Runnable() {
  47.                         @Override
  48.                         public void run() {
  49.                             callback.onTranslationComplete(resultTranslate);
  50.                         }
  51.                     });
  52.                 }
  53.             }
  54.         }).start();
  55.     }
  56.    
  57.     // 保留原有的 doBackgroundWork 方法以保持向后兼容
  58.     public void doBackgroundWork() {
  59.         doBackgroundWork(null);
  60.     }
  61.    
  62.     // 辅助方法:在服务中执行UI线程操作
  63.     private void runOnUiThread(Runnable runnable) {
  64.         new Handler(Looper.getMainLooper()).post(runnable);
  65.     }
  66.    
  67.     // ... 其他现有代码保持不变
  68. }
复制代码


2. 修改 IatDemo 中的 callLlm2 方法
  1. private void callLlm2(String text, String caller) {
  2.     Log.i(TAG, caller + ", before call bkground service.");
  3.     mService.setDataToLlm(text);
  4.    
  5.     // 使用回调获取翻译结果
  6.     mService.doBackgroundWork(new BackgroundService.TranslationCallback() {
  7.         @Override
  8.         public void onTranslationComplete(String result) {
  9.             // 在主线程中更新UI
  10.             runOnUiThread(new Runnable() {
  11.                 @Override
  12.                 public void run() {
  13.                     mResultText.append("\n翻译结果: " + result);
  14.                     mResultText.setSelection(mResultText.length());
  15.                 }
  16.             });
  17.         }
  18.     });
  19. }
复制代码

3. 或者使用更简洁的 Lambda 表达式(如果支持 Java 8+)
  1. private void callLlm2(String text, String caller) {
  2.     Log.i(TAG, caller + ", before call bkground service.");
  3.     mService.setDataToLlm(text);
  4.    
  5.     // 使用 Lambda 表达式
  6.     mService.doBackgroundWork(result -> {
  7.         runOnUiThread(() -> {
  8.             mResultText.append("\n翻译结果: " + result);
  9.             mResultText.setSelection(mResultText.length());
  10.         });
  11.     });
  12. }
复制代码


另一种方案:使用 Handler 或 BroadcastReceiver
如果您不想修改 BackgroundService 的接口,也可以使用 BroadcastReceiverHandler 来实现回调机制。
推荐
推荐使用第一种方案(回调接口),因为它提供了清晰的接口定义,代码可读性好,且易于维护。




回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|DiscuzX

GMT+8, 2025-10-25 19:48 , Processed in 0.012721 second(s), 18 queries .

Powered by Discuz! X3.4

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表