1

我正在开发一个使用自定义 RenderScript 脚本进行图像处理的应用程序。现在,因为我有很多这些脚本在使用,所以我在应用程序第一次启动时预加载它们。“预加载”是指我实例化每个脚本,以便它可以在设备上编译。下面是这个操作的代码片段。大约有 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());
    }
}

如您所见,我在后台线程上执行此操作。问题是脚本似乎无论如何都在主线程上编译。问题是他们阻止了用户界面。我已经用 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。

任何帮助表示赞赏。

4

1 回答 1

3

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

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

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

希望这可以帮助某人。

于 2017-02-23T13:40:30.060 回答