編輯:關於android開發
3 RenderScript運行時層與反射層
3.1 RenderScript運行時層
RenderScript運行時層是指.rs代碼運行時所在的層級。當對安卓項目進行編譯的時候,.rs或者.rsh中編寫的代碼都會被llvm編譯器編譯成字節碼。當該安卓應用在設備上運行的時候,這些字節碼將會被設備上另外一個llvm編譯(just-in-time)成機器碼。這些機器碼是針對該設備進行了優化的,且緩存在設備上,等到下次被應用的時候就不需要重新編譯了,以加快速度。雖然RenderScript運行時層很像NDK,但是由於NDK中的C函數只針對CPU設計,與RenderScript還能夠在GPU和DSP上運行的目標不同,因此在RenderScript中不能使用NDK中的C函數。
RenderScript運行時庫的特性包括:
3.2 反射層
反射層由安卓編譯工具基於開發者編寫的.rs/.rsh文件自動生成的,反射層的作用就是給Android framework層提供對RenderScript運行時層操作的Java接口,包括內存分配、計算任務啟動、數據交互等。
每一個.rs文件都會被映射成繼承於ScriptC的類:ScriptC_RenderScript_filename,該類被生成在gen目錄下與.rs文件相同的包下。該類就是.rs文件的Java版本。該類主要包含.rs中的如下內容:
Struct映射的詳細解釋
反射層生成的Struct主要包括:
可以使用或操作符來指定在多個內存區分配該內存,這樣做表示向RenderScript表明:我想在多個內存區來訪問該數據。
代碼舉例:
.rs文件,文件名:script.rs
#pragma version(1) #pragma rs java_package_name(com.example.renderscripttest) #pragma rs_fp_relaxed uint32_t width; uint32_t height; rs_allocation inBitmap; rs_allocation rgbBitmap; rs_allocation yuvBitmap; //multipliers to convert a RGB colors to black and white const static float3 gMonoMult = {0.299f, 0.587f, 0.114f}; typedef struct Point_2D{ int x; int y; }Point; static Point *spPoint; static Point sPoint; Point point; Point *pPoint; //google sample void root(const uchar4 *v_in, uchar4 *v_out) { //unpack a color to a float4 float4 f4 = rsUnpackColor8888(*v_in); //take the dot product of the color and the multiplier float3 mono = dot(f4.rgb, gMonoMult); //repack the float to a color *v_out = rsPackColorTo8888(mono); } void __attribute((kernel)) setPoint(const uint2 in, uint32_t x, uint32_t y){ rsDebug("lyh", point.x); point.x = 9; //struct is used point.y = 12; rsSendToClient(0, &point, 1); rsDebug("willhua", point.x); } uchar4 __attribute__((kernel)) halveBitmap(uchar4 in){ uchar4 out = in; out.r = in.r / 2; out.r = in.r / 2; out.r = in.r / 2; return out; } uchar4 __attribute__((kernel)) averageBitmap(uchar4 in, uint32_t x, uint32_t y){ uchar4 out = in; uchar4 left = in; uchar4 top = in; uchar4 right = in; uchar4 bottom = in; if(x - 1 > -1){ //access other element left = rsGetElementAt_uchar4(inBitmap, x - 1, y); } if(y - 1 > -1){ top = rsGetElementAt_uchar4(inBitmap, x , y - 1); } if(x + 1 < width){ right = rsGetElementAt_uchar4(inBitmap, x + 1, y); } if(y + 1 < height){ bottom = rsGetElementAt_uchar4(inBitmap, x, y + 1); } out.r = (left.r + top.r + right.r + bottom.r) / 4; out.g = (left.g + top.g + right.g + bottom.g) / 4; out.b = (left.b + top.b + right.b + bottom.b) / 4; return out; } View Code反射層生成的ScriptC子類:
/* * Copyright (C) 2011-2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * This file is auto-generated. DO NOT MODIFY! * The source Renderscript file: G:\\Files\\EclipseWorkSpace\\RenderScriptTest\\src\\com\\example\\renderscripttest\\script.rs */ package com.example.renderscripttest; import android.support.v8.renderscript.*; import android.content.res.Resources; /** * @hide */ public class ScriptC_script extends ScriptC { private static final String __rs_resource_name = "script"; // Constructor public ScriptC_script(RenderScript rs) { this(rs, rs.getApplicationContext().getResources(), rs.getApplicationContext().getResources().getIdentifier( __rs_resource_name, "raw", rs.getApplicationContext().getPackageName())); } public ScriptC_script(RenderScript rs, Resources resources, int id) { super(rs, resources, id); __U32 = Element.U32(rs); __ALLOCATION = Element.ALLOCATION(rs); __ScriptField_Point_2D = ScriptField_Point_2D.createElement(rs); __U8_4 = Element.U8_4(rs); __U32_2 = Element.U32_2(rs); } private Element __ALLOCATION; private Element __ScriptField_Point_2D; private Element __U32; private Element __U32_2; private Element __U8_4; private FieldPacker __rs_fp_ALLOCATION; private FieldPacker __rs_fp_ScriptField_Point_2D; private FieldPacker __rs_fp_U32; private final static int mExportVarIdx_width = 0; private long mExportVar_width; public synchronized void set_width(long v) { if (__rs_fp_U32!= null) { __rs_fp_U32.reset(); } else { __rs_fp_U32 = new FieldPacker(4); } __rs_fp_U32.addU32(v); setVar(mExportVarIdx_width, __rs_fp_U32); mExportVar_width = v; } public long get_width() { return mExportVar_width; } public Script.FieldID getFieldID_width() { return createFieldID(mExportVarIdx_width, null); } private final static int mExportVarIdx_height = 1; private long mExportVar_height; public synchronized void set_height(long v) { if (__rs_fp_U32!= null) { __rs_fp_U32.reset(); } else { __rs_fp_U32 = new FieldPacker(4); } __rs_fp_U32.addU32(v); setVar(mExportVarIdx_height, __rs_fp_U32); mExportVar_height = v; } public long get_height() { return mExportVar_height; } public Script.FieldID getFieldID_height() { return createFieldID(mExportVarIdx_height, null); } private final static int mExportVarIdx_inBitmap = 2; private Allocation mExportVar_inBitmap; public synchronized void set_inBitmap(Allocation v) { setVar(mExportVarIdx_inBitmap, v); mExportVar_inBitmap = v; } public Allocation get_inBitmap() { return mExportVar_inBitmap; } public Script.FieldID getFieldID_inBitmap() { return createFieldID(mExportVarIdx_inBitmap, null); } private final static int mExportVarIdx_rgbBitmap = 3; private Allocation mExportVar_rgbBitmap; public synchronized void set_rgbBitmap(Allocation v) { setVar(mExportVarIdx_rgbBitmap, v); mExportVar_rgbBitmap = v; } public Allocation get_rgbBitmap() { return mExportVar_rgbBitmap; } public Script.FieldID getFieldID_rgbBitmap() { return createFieldID(mExportVarIdx_rgbBitmap, null); } private final static int mExportVarIdx_yuvBitmap = 4; private Allocation mExportVar_yuvBitmap; public synchronized void set_yuvBitmap(Allocation v) { setVar(mExportVarIdx_yuvBitmap, v); mExportVar_yuvBitmap = v; } public Allocation get_yuvBitmap() { return mExportVar_yuvBitmap; } public Script.FieldID getFieldID_yuvBitmap() { return createFieldID(mExportVarIdx_yuvBitmap, null); } private final static int mExportVarIdx_point = 5; private ScriptField_Point_2D.Item mExportVar_point; public synchronized void set_point(ScriptField_Point_2D.Item v) { mExportVar_point = v; FieldPacker fp = new FieldPacker(8); fp.addI32(v.x); fp.addI32(v.y); int []__dimArr = new int[1]; __dimArr[0] = 1; setVar(mExportVarIdx_point, fp, __ScriptField_Point_2D, __dimArr); } public ScriptField_Point_2D.Item get_point() { return mExportVar_point; } public Script.FieldID getFieldID_point() { return createFieldID(mExportVarIdx_point, null); } private final static int mExportVarIdx_pPoint = 6; private ScriptField_Point_2D mExportVar_pPoint; public void bind_pPoint(ScriptField_Point_2D v) { mExportVar_pPoint = v; if (v == null) bindAllocation(null, mExportVarIdx_pPoint); else bindAllocation(v.getAllocation(), mExportVarIdx_pPoint); } public ScriptField_Point_2D get_pPoint() { return mExportVar_pPoint; } private final static int mExportForEachIdx_root = 0; public Script.KernelID getKernelID_root() { return createKernelID(mExportForEachIdx_root, 3, null, null); } public void forEach_root(Allocation ain, Allocation aout) { forEach_root(ain, aout, null); } public void forEach_root(Allocation ain, Allocation aout, Script.LaunchOptions sc) { // check ain if (!ain.getType().getElement().isCompatible(__U8_4)) { throw new RSRuntimeException("Type mismatch with U8_4!"); } // check aout if (!aout.getType().getElement().isCompatible(__U8_4)) { throw new RSRuntimeException("Type mismatch with U8_4!"); } Type t0, t1; // Verify dimensions t0 = ain.getType(); t1 = aout.getType(); if ((t0.getCount() != t1.getCount()) || (t0.getX() != t1.getX()) || (t0.getY() != t1.getY()) || (t0.getZ() != t1.getZ()) || (t0.hasFaces() != t1.hasFaces()) || (t0.hasMipmaps() != t1.hasMipmaps())) { throw new RSRuntimeException("Dimension mismatch between parameters ain and aout!"); } forEach(mExportForEachIdx_root, ain, aout, null, sc); } private final static int mExportForEachIdx_setPoint = 1; public Script.KernelID getKernelID_setPoint() { return createKernelID(mExportForEachIdx_setPoint, 57, null, null); } public void forEach_setPoint(Allocation ain) { forEach_setPoint(ain, null); } public void forEach_setPoint(Allocation ain, Script.LaunchOptions sc) { // check ain if (!ain.getType().getElement().isCompatible(__U32_2)) { throw new RSRuntimeException("Type mismatch with U32_2!"); } forEach(mExportForEachIdx_setPoint, ain, null, null, sc); } private final static int mExportForEachIdx_halveBitmap = 2; public Script.KernelID getKernelID_halveBitmap() { return createKernelID(mExportForEachIdx_halveBitmap, 35, null, null); } public void forEach_halveBitmap(Allocation ain, Allocation aout) { forEach_halveBitmap(ain, aout, null); } public void forEach_halveBitmap(Allocation ain, Allocation aout, Script.LaunchOptions sc) { // check ain if (!ain.getType().getElement().isCompatible(__U8_4)) { throw new RSRuntimeException("Type mismatch with U8_4!"); } // check aout if (!aout.getType().getElement().isCompatible(__U8_4)) { throw new RSRuntimeException("Type mismatch with U8_4!"); } Type t0, t1; // Verify dimensions t0 = ain.getType(); t1 = aout.getType(); if ((t0.getCount() != t1.getCount()) || (t0.getX() != t1.getX()) || (t0.getY() != t1.getY()) || (t0.getZ() != t1.getZ()) || (t0.hasFaces() != t1.hasFaces()) || (t0.hasMipmaps() != t1.hasMipmaps())) { throw new RSRuntimeException("Dimension mismatch between parameters ain and aout!"); } forEach(mExportForEachIdx_halveBitmap, ain, aout, null, sc); } private final static int mExportForEachIdx_averageBitmap = 3; public Script.KernelID getKernelID_averageBitmap() { return createKernelID(mExportForEachIdx_averageBitmap, 59, null, null); } public void forEach_averageBitmap(Allocation ain, Allocation aout) { forEach_averageBitmap(ain, aout, null); } public void forEach_averageBitmap(Allocation ain, Allocation aout, Script.LaunchOptions sc) { // check ain if (!ain.getType().getElement().isCompatible(__U8_4)) { throw new RSRuntimeException("Type mismatch with U8_4!"); } // check aout if (!aout.getType().getElement().isCompatible(__U8_4)) { throw new RSRuntimeException("Type mismatch with U8_4!"); } Type t0, t1; // Verify dimensions t0 = ain.getType(); t1 = aout.getType(); if ((t0.getCount() != t1.getCount()) || (t0.getX() != t1.getX()) || (t0.getY() != t1.getY()) || (t0.getZ() != t1.getZ()) || (t0.hasFaces() != t1.hasFaces()) || (t0.hasMipmaps() != t1.hasMipmaps())) { throw new RSRuntimeException("Dimension mismatch between parameters ain and aout!"); } forEach(mExportForEachIdx_averageBitmap, ain, aout, null, sc); } } View Code反射層生成的struct,Point_2D, 對應的類:
/* * Copyright (C) 2011-2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * This file is auto-generated. DO NOT MODIFY! * The source Renderscript file: G:\\Files\\EclipseWorkSpace\\RenderScriptTest\\src\\com\\example\\renderscripttest\\script.rs */ package com.example.renderscripttest; import android.support.v8.renderscript.*; import android.content.res.Resources; /** * @hide */ public class ScriptField_Point_2D extends android.support.v8.renderscript.Script.FieldBase { static public class Item { public static final int sizeof = 8; int x; int y; Item() { } } private Item mItemArray[]; private FieldPacker mIOBuffer; private static java.lang.ref.WeakReference<Element> mElementCache = new java.lang.ref.WeakReference<Element>(null); public static Element createElement(RenderScript rs) { Element.Builder eb = new Element.Builder(rs); eb.add(Element.I32(rs), "x"); eb.add(Element.I32(rs), "y"); return eb.create(); } private ScriptField_Point_2D(RenderScript rs) { mItemArray = null; mIOBuffer = null; mElement = createElement(rs); } public ScriptField_Point_2D(RenderScript rs, int count) { mItemArray = null; mIOBuffer = null; mElement = createElement(rs); init(rs, count); } public ScriptField_Point_2D(RenderScript rs, int count, int usages) { mItemArray = null; mIOBuffer = null; mElement = createElement(rs); init(rs, count, usages); } public static ScriptField_Point_2D create1D(RenderScript rs, int dimX, int usages) { ScriptField_Point_2D obj = new ScriptField_Point_2D(rs); obj.mAllocation = Allocation.createSized(rs, obj.mElement, dimX, usages); return obj; } public static ScriptField_Point_2D create1D(RenderScript rs, int dimX) { return create1D(rs, dimX, Allocation.USAGE_SCRIPT); } public static ScriptField_Point_2D create2D(RenderScript rs, int dimX, int dimY) { return create2D(rs, dimX, dimY, Allocation.USAGE_SCRIPT); } public static ScriptField_Point_2D create2D(RenderScript rs, int dimX, int dimY, int usages) { ScriptField_Point_2D obj = new ScriptField_Point_2D(rs); Type.Builder b = new Type.Builder(rs, obj.mElement); b.setX(dimX); b.setY(dimY); Type t = b.create(); obj.mAllocation = Allocation.createTyped(rs, t, usages); return obj; } public static Type.Builder createTypeBuilder(RenderScript rs) { Element e = createElement(rs); return new Type.Builder(rs, e); } public static ScriptField_Point_2D createCustom(RenderScript rs, Type.Builder tb, int usages) { ScriptField_Point_2D obj = new ScriptField_Point_2D(rs); Type t = tb.create(); if (t.getElement() != obj.mElement) { throw new RSIllegalArgumentException("Type.Builder did not match expected element type."); } obj.mAllocation = Allocation.createTyped(rs, t, usages); return obj; } private void copyToArrayLocal(Item i, FieldPacker fp) { fp.addI32(i.x); fp.addI32(i.y); } private void copyToArray(Item i, int index) { if (mIOBuffer == null) mIOBuffer = new FieldPacker(mElement.getBytesSize() * getType().getX()/* count */); mIOBuffer.reset(index * mElement.getBytesSize()); copyToArrayLocal(i, mIOBuffer); } public synchronized void set(Item i, int index, boolean copyNow) { if (mItemArray == null) mItemArray = new Item[getType().getX() /* count */]; mItemArray[index] = i; if (copyNow) { copyToArray(i, index); FieldPacker fp = new FieldPacker(mElement.getBytesSize()); copyToArrayLocal(i, fp); mAllocation.setFromFieldPacker(index, fp); } } public synchronized Item get(int index) { if (mItemArray == null) return null; return mItemArray[index]; } public synchronized void set_x(int index, int v, boolean copyNow) { if (mIOBuffer == null) mIOBuffer = new FieldPacker(mElement.getBytesSize() * getType().getX()/* count */); if (mItemArray == null) mItemArray = new Item[getType().getX() /* count */]; if (mItemArray[index] == null) mItemArray[index] = new Item(); mItemArray[index].x = v; if (copyNow) { mIOBuffer.reset(index * mElement.getBytesSize()); mIOBuffer.addI32(v); FieldPacker fp = new FieldPacker(4); fp.addI32(v); mAllocation.setFromFieldPacker(index, 0, fp); } } public synchronized void set_y(int index, int v, boolean copyNow) { if (mIOBuffer == null) mIOBuffer = new FieldPacker(mElement.getBytesSize() * getType().getX()/* count */); if (mItemArray == null) mItemArray = new Item[getType().getX() /* count */]; if (mItemArray[index] == null) mItemArray[index] = new Item(); mItemArray[index].y = v; if (copyNow) { mIOBuffer.reset(index * mElement.getBytesSize() + 4); mIOBuffer.addI32(v); FieldPacker fp = new FieldPacker(4); fp.addI32(v); mAllocation.setFromFieldPacker(index, 1, fp); } } public synchronized int get_x(int index) { if (mItemArray == null) return 0; return mItemArray[index].x; } public synchronized int get_y(int index) { if (mItemArray == null) return 0; return mItemArray[index].y; } public synchronized void copyAll() { for (int ct = 0; ct < mItemArray.length; ct++) copyToArray(mItemArray[ct], ct); mAllocation.setFromFieldPacker(0, mIOBuffer); } } View Code
4 內存
我們已經知道,應用自身運行在安卓VM中,而RenderScript部分代碼則運行在本地,且其內存是由上層的應用分配的。
4.1 內存分配API
內存API主要包含三個類:Element,Type與Allocation。他們三者對應的關系能用malloc函數的使用來很好的說明,例如:
int *array = (int *)malloc(sizeof(int) * 10);
malloc函數的參數可以分成兩個部分:第一個就是sizeof(int),該過程指定每個內存單元需要多個內存;第二個就是*10,該過程指定需要分配多個這樣的內存單元。對應的內存分配APIs就是Element類,表示的是一個內存單元,就像一個float或者一個struct所表示的內存。而Type表示的就是“*10”部分,就像一個Element序列一樣。Allocation則用來執行由Type所描述的內存分配,且最終代表分配得到的內存。
大部分情況下都不需要直接使用這些API,因為系統在自動生成反射層的時候已經做好了封裝,需要做的就是調用對應類的構造函數並把分配的內存綁定到RenderScript而已。但是比如當你加載一張圖片到RenderScript層或者給一個指針分配內存時,就需要應用到這些API。
4.2 靜態內存
4.2.1 靜態內存的分配
這裡的靜態內存指的是在RenderScript中聲明的非靜態的全局變量(靜態的或者局部的變量就無法在Android framework層訪問,也就不討論),他們在編譯時就分配了內存,在RenderScript代碼中可以直接使用它們而不需要在Android Framework層給他們分配內存。在Android Framework層也可以通過反射層生成的函數來訪問他們。如果這些變量在RenderScript中被初始化,那麼他們也將在Android Framework層中被進行同樣的初始化。
注意:如果在RenderScript中使用到了RenderScript中預定義了的一些含有指針的結構體,比如rs_program_fragment和rs_allocation,那麼就需要先在Android Framework層構造一個該結構對應類的實例,然後調用set方法把內存綁定到RenderScript運行時,而不能直接在RenderScript層操作。但是這個對於用戶自定義的包含指針的結果無效,因為根本就無法自定義包含指針的結構。
4.2.2 靜態內存的讀寫
在RenderScript層對靜態分配的內存的寫操作是單向的。當你在RenderScript層修改了某個變量的值,出於性能方面的考慮,這個變化不會反應給安卓層。在安卓層調用get方法獲得的是安卓層最後一次通過set方法設置的值,除非通過rsSendToClient()等手段,否則安卓層是永遠獲取不到RenderScript對靜態分配的內存的修改的。但是,當安卓層修改了某個變量的值後,該值的變化隨後就會自動同步到RenderScript層。
下面是讀寫示例。假如在rsfile.rs中定義了全局變量point:
typedef struct Point { int x; int y; } Point_t; Point_t point;
那麼在RenderScript中可以如下直接給變量賦值:
point.x = 1; point.y = 1;
在Android framework層中可以這樣修改該變量的值,且修改的值會通知到RenderScript層:
ScriptC_rsfile mScript; ... Item i = new ScriptField_Point.Item(); i.x = 1; i.y = 1; mScript.set_point(i);
在RenderScript中讀取變量的值:
rsDebug("Printing out a Point", point.x, point.y);
在Android framework中讀取變量的值。再一次強調:讀取到的永遠是Android framework層最後一次調用set方法給該變量賦的值,而如果在Android framework層沒有用set方法給變量賦過值的話,那麼讀取的將是null,下面代碼也會報空指針錯誤
Log.i("TAGNAME", "Printing out a Point: " + mScript.get_point().x + " " + mScript.get_point().y); System.out.println(point.get_x() + " " + point.get_y());
4.3 動態內存
4.3.1 動態內存的分配
對於動態內存,比如指針,就必須在Android Framework層中給它分配內存。需要兩個過程:分配內存與綁定內存。這樣做的好處在於:安卓VM能夠完全掌握RenderScript內存的分配與回收。
無論在Android Framework層還是RenderScript中,都可以通過該指針來訪問分配的內存。
為了給RenderScript動態分配內存,最常見的做法是調用Script.FieldBase的構造函數,當然好也可以手動創建Allocation來實現,為了簡單起見,應該使用Script.FieldBase.當獲取分配的內存對象後,就可以通過反射層的bind方法把該內存綁定到RenderScript。下面代碼是兩種實現方式的例子:
private RenderScript myRenderScript; private ScriptC_example mScript; private Resources resources;
public void init(RenderScript rs, Resources res) { myRenderScript = rs; resources = res; //使用反射層生成的類分配內存 ScriptField_Point touchPoints = new ScriptField_Point(myRenderScript, 2); //自己使用API分配內存 intPointer = Allocation.createSized(myRenderScript, Element.I32(myRenderScript), 2); mScript = new ScriptC_example(myRenderScript, resources, R.raw.example); //綁定內存 mScript.bind_touchPoints(touchPoints); mScript.bind_intPointer(intPointer); ... }
4.3.2 動態內存的讀寫
對於動態內存,在Android framework層可以通過反射層的set/get方法來讀/寫內存,在RenderScript中也可以像往常一樣讀/寫,且任意一方的寫操作都會通知到另外一方。
下面是示例。假設在rsfile.rs定義了如下全局指針:
typedef struct Point { int x; int y; } Point_t; Point_t *point;
只要你已經在Android framework層給分配了內存,那麼就可以像往常一樣使用它,且任何的修改都會通知到Android framework層。
point[index].x = 1; point[index].y = 1;
在Android framework 層通過反射層提供的方法讀寫:
ScriptField_Point p = new ScriptField_Point(mRS, 1); Item i = new ScriptField_Point.Item(); i.x=100; i.y = 100; p.set(i, 0, true); mScript.bind_point(p); points.get_x(0); //read x and y from index 0 points.get_x(0);
內存只需要綁定一次就可以了,不需要每次修改值的時候再次綁定
5 基本應用場景
5.1 RenderScript層回調Android framework層
前面我們提到過,RenderScript中的invokable不能有返回值,以及對於靜態內存,RenderScript層對其修改不會通知到Android framework層。對於這兩種情況,配套使用RSMessageHandler和rsSendToClient是很好的解決方案。對於二者的關系,從命名就可以看出一二,RSMessageHandler相當於常用的handleMessage函數,而rsSendToClient則相當於Handler.sendMessage,只是RSMessageHandler運行在Android framework層,而rsSendToClient運行在RenderScript層。
RenderScript.RSMessageHandler它implements Runnable,在使用過程中只需要重寫run函數即可。其有三個重要的字段:
使用范例:
mRenderScript.setMessageHandler(new RSMessageHandler(){ @Override public void run(){ switch (mID) { case type: //do something break; default: break; } } });
注意:run函數不是運行在主線程,所以在run函數中不能直接做操作主界面UI的操作。
5.2 在RenderScript kernel中訪問更多的元素
我們提到過,對於一個kernel,最多只能有一個輸入Allocation,假如需要在kernel中訪問更多的Allocation,那怎麼辦呢?
在kernel中,僅容許對當前元素進行操作,即當前坐標(x,y)表示的元素,如果想訪問其他元素,則需要定義一個全局的輸入allocation,然後使用rsGetElementAt_type()來獲取其他元素,比如:下面的averageBitmap就訪問了全局變量inBitmap的數據:
rs_allocation inBitmap; uchar4 __attribute__((kernel)) averageBitmap(uchar4 in, uint32_t x, uint32_t y){ uchar4 out = in; uchar4 left = in; uchar4 top = in; uchar4 right = in; uchar4 bottom = in; if(x - 1 > -1){ //access other element left = rsGetElementAt_uchar4(inBitmap, x - 1, y); } if(y - 1 > -1){ top = rsGetElementAt_uchar4(inBitmap, x , y - 1); } if(x + 1 < width){ right = rsGetElementAt_uchar4(inBitmap, x + 1, y); } if(y + 1 < height){ bottom = rsGetElementAt_uchar4(inBitmap, x, y + 1); } out.r = (left.r + top.r + right.r + bottom.r) / 4; out.g = (left.g + top.g + right.g + bottom.g) / 4; out.b = (left.b + top.b + right.b + bottom.b) / 4; return out; }
安卓開發之RecyclerView,安卓recyclerviewRecyclerView是一個非常好用的控件,它的效果和ListView很相似,甚至可以說Recycler
Android事件分發 Android 中與 Touch 事件相關的方法包括:dispatchTouchEvent(MotionEvent ev)、onInterce
安卓 應用程序修改圖標不更新,安卓圖標自己在做項目時,真機測試時想更換應用程序的圖標(虛擬機更換後可以更新),但是更換後重新運行並沒有更新圖標。經過嘗試,最終通過重啟手機
Activity詳解二 activity數據傳遞,activity詳解首先看效果圖: 1.Bundle類的作用 Bundle類用作攜帶數據,它類似於M