在后台Android中进行繁重处理时UI冻结

Posted

技术标签:

【中文标题】在后台Android中进行繁重处理时UI冻结【英文标题】:UI Freezing while doing heavy processing in background Android 【发布时间】:2019-07-03 09:19:53 【问题描述】:

在 UI 线程上:

   AsyncCaller asyncCaller = new AsyncCaller();
                           asyncCaller.doInBackground();

在异步任务中: @覆盖 protected Void doInBackground(Void... params)

       Mat orignal = new Mat(image1.getHeight(), image1.getWidth(), CvType.CV_8UC3);
       Mat v_blur = new Mat(image1.getHeight(), image1.getWidth(), CvType.CV_8UC3);
       Utils.bitmapToMat(image1, orignal);
       Imgproc.GaussianBlur(orignal, v_blur, new Size(3, 3), 0);
       // blur completed
       Mat to_zero = new Mat(image1.getHeight(), image1.getWidth(), CvType.CV_8UC4);
       Imgproc.threshold(v_blur, to_zero, 100, 100, Imgproc.THRESH_TOZERO);
       Bitmap bmp = image1;
       Log.e("background", "in bg");
       Utils.bitmapToMat(bmp, to_zero);
       for (int j = 0; j < bmp.getWidth(); j++) 
           for (int i = 0; i < bmp.getHeight(); i++) 
               int pixelValue = bmp.getPixel(j, i);
               int red = Color.red(pixelValue);
               int green = Color.green(pixelValue);
               int blue = Color.blue(pixelValue);

               if (red > 10 && blue > 10 && green > 10) 
                   int led_bulb = checkForAlreadyExistance(j, i);
                   if (led_bulb == -1) 
                       int start_x = getMinValue(j);
                       int start_y = getMinValue(i);
                       int end_x = getMaxValue(j, bmp.getWidth());
                       int end_y = getMaxValue(i, bmp.getHeight());
                       Log.e("crop_values", start_x + " " + end_x + " " + start_y + " " + end_y);
                       LEDs.add(new LedBoundingBox(LED++, end_x, start_x, end_y, start_y, 0, 0, 0.0));
                    else 
                       if (j > LEDs.get(led_bulb).inner_x_max) 
                           LEDs.get(led_bulb).inner_x_max = j;
                       
                       if (j < LEDs.get(led_bulb).inner_x_min) 
                           LEDs.get(led_bulb).inner_x_min = j;
                       
                       if (i > LEDs.get(led_bulb).inner_y_max) 
                           LEDs.get(led_bulb).inner_y_max = i;
                       
                       if (i < LEDs.get(led_bulb).inner_y_min) 
                           LEDs.get(led_bulb).inner_y_min = i;
                       

                   

               
           
       
       Log.e("bgComplete", "complete");
       return null;
   

我正在使用 android OpenCV 库进行图像处理。首先,我在 UI 线程上完成了所有这些工作,但遇到了 UI 挂起问题。所以我把它转移到后台线程。但我仍然面临 UI 挂起问题。谁能解释为什么会发生这种情况以及任何可能的解决方案? 谢谢

【问题讨论】:

【参考方案1】:

使用asyncCaller.execute():,不要直接调用doInBackground()

现在您在 UI 线程上调用此方法,而不是启动 AsyncTask 并让任务自行调用线程。

AsyncTask 任务 = new AsyncTask(); task.execute(paramsForDoInBackground);

应该怎么称呼

【讨论】:

非常感谢兄弟.. 像魅力一样工作:)。【参考方案2】:

为您的工作使用 Java 线程而不是异步任务! 异步任务仅适用于小型操作。

请在此处查看: https://***.com/a/18480297/4632620

【讨论】:

感谢您的回复。让我试试这种线程方法,很快就会得到你的认可。 我尝试了这种方法,但在访问 UI 元素时出错。这可能是一个好方法,但就我而言,需要对以前的代码进行许多更改。我尝试了布兰登的答案,这对我有用,无需做任何更改。顺便说一句,感谢您的回复。 您可以通过 Handlers 和 Loppers 传递 UI 元素来访问它们。因为如果是主线程,则无法在外部更改 UI 元素。【参考方案3】:

如果您不想冻结 UI,最简单、最好和直观的示例会演示它应该是怎样的。每个面临这个问题的人或不知道如何为 android 项目编写代码的人都应该看到并遵循这种风格:

Video Demonstration of Avoiding UI freezing

【讨论】:

以上是关于在后台Android中进行繁重处理时UI冻结的主要内容,如果未能解决你的问题,请参考以下文章

如何在使用 WebAssembly 进行大量计算时保持反应式 UI?

来自后台时iOS App UI冻结

使用 FirestoreDecoder 解码 Firestore 文档时 UI 冻结

后台工作人员仍然冻结 ui

Android RecyclerView 在 notifyDataSetChanged 调用上冻结 UI

wpf 动态更新 UI 而不会冻结 UI