Renderscript ScriptC 编译阻塞主线程

Renderscript ScriptC compile blocking main thread

我正在开发一个使用自定义 RenderScript 脚本进行图像处理的应用程序。现在,因为我有很多这些脚本在使用中,所以我在应用程序首次启动时预加载它们。 "preload" 我的意思是我实例化每个脚本,以便它可以在设备上编译。下面是这个操作的代码片段。大约有60个脚本,但我认为这足以说明操作。

public class Load extends Thread {

    public Load() {
        super();
        setPriority(Thread.MIN_PRIORITY);
    }

    @Override
    public void run() {
        new ScriptC_first(RenderScriptHelper.getInstance());
        new ScriptC_second(RenderScriptHelper.getInstance());
        new ScriptC_third(RenderScriptHelper.getInstance());
    }
}

如您所见,我是在后台线程上执行此操作的。问题是脚本似乎在主线程上编译,不管这个。问题是他们正在阻止 UI。我用 AsyncTask 和 Service 试过这个,结果相同。我怀疑 RenderScript 在内部跳到主线程来编译它们。

现在,在 Android Nougat (7.0) 之前,预加载相同数量的脚本需要不到 10 秒,具体取决于设备速度。在 Nougat 上,这需要将近一分钟的时间,考虑到它会阻止 UI,这是一个大问题,尽管只是在第一次应用程序启动时。在随后的每次启动中,它都会在几秒钟内预加载(因为脚本已经编译)。

我需要预加载,因为按需实例化脚本不是一种选择,因为一旦用户开始使用应用程序,所有脚本都必须准备好并编译。

logcat的相关部分:

E/RenderScript: Unable to open shared library (/data/user/0/com.company.myapp/cache/librs.contrast_v001.so): undefined symbol: .rs.dtor
V/RenderScript: Invoking /system/bin/bcc with args '/system/bin/bcc -unroll-runtime -scalarize-load-store -rs-global-info -rs-global-info-skip-constant -o contrast_v001 -output_path /data/user/0/com.company.myapp/cache -bclib /system/lib/libclcore.bc -mtriple armv7-none-linux-gnueabi -O 3 -load libbccQTI.so -fPIC -embedRSInfo /data/user/0/com.company.myapp/cache/contrast_v001.bc -build-checksum abadcafe'
V/RenderScript: Invoking /system/bin/ld.mc with args '/system/bin/ld.mc -shared -nostdlib /system/lib/libcompiler_rt.so -mtriple=armv7-none-linux-gnueabi --library-path=/system/vendor/lib --library-path=/system/lib -lRSDriver_adreno -lm -lc /data/user/0/com.company.myapp/cache/contrast_v001.o -o /data/user/0/com.company.myapp/cache/librs.contrast_v001.so'

此外,如果相关的话,我在第一次启动应用程序时使用 RenderScript.ContextType.PROFILE,在随后的每次启动时使用 RenderScript.ContextType.NORMAL。使用 RenderScript.ContextType.DEBUG 会导致脚本在每次应用程序启动时编译,所用时间与其他上下文相同,并且 logcat 输出略有不同:

V/RenderScript: Invoking /system/bin/bcc with args '/system/bin/bcc -unroll-runtime -scalarize-load-store -rs-global-info -rs-global-info-skip-constant -o contrast_v001 -output_path /data/user/0/com.company.myapp/cache -bclib /system/lib/libclcore_debug.bc -mtriple armv7-none-linux-gnueabi -O 3 -rs-debug-ctx -fPIC -embedRSInfo /data/user/0/com.company.myapp/cache/contrast_v001.bc -build-checksum abadcafe'
V/RenderScript: Invoking /system/bin/ld.mc with args '/system/bin/ld.mc -shared -nostdlib /system/lib/libcompiler_rt.so -mtriple=armv7-none-linux-gnueabi --library-path=/system/vendor/lib --library-path=/system/lib -lRSDriver_adreno -lm -lc /data/user/0/com.company.myapp/cache/contrast_v001.o -o /data/user/0/com.company.myapp/cache/librs.contrast_v001.so'

build.gradle的相关部分:

renderscriptTargetApi 23
renderscriptSupportModeEnabled true

我搜索了有关 RenderScript 内部工作原理的文档和信息,但它确实很少,因为大多数内部工作原理都留给设备供应商自行决定。

所以我的问题是:是否可以强制 RenderScript 在后台线程上编译脚本,而不阻塞 UI。

感谢任何帮助。

对于遇到此问题的任何人:我设法在应用程序的私有进程中通过服务 运行 解决了这个问题,声明如下:

<service
    android:name="com.company.LoadService"
    android:process=":loadService"
    android:exported="false" />

我在服务中实例化了 ScriptC_something.class-es,因为它是一个单独的进程,所以我的 UI 线程再次空闲。

希望这对某人有所帮助。