Renderscript ScriptC编译阻塞主线程

时间:2017-02-22 23:26:42

标签: android multithreading renderscript android-7.0-nougat android-renderscript

我正在开发一个使用自定义RenderScript脚本进行图像处理的应用。现在,由于我有很多这些脚本在使用,我首先在应用程序上预加载它们。通过“预加载”我的意思是我实例化每个脚本,以便它可以在设备上编译。 Bellow是此操作的代码片段。大约有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。

感谢任何帮助。

1 个答案:

答案 0 :(得分:2)

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

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

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

希望这有助于某人。