标签:super 问题 屏幕 int and 清理 ble XML 窗口
最近做项目遇到一个问题,需要在屏幕上实时的显示手的坐标,这样话就涉及到一个实时画图的问题了。对于实时更新UI这个问题,懂点android的都知道,android的UI更新都需要在主线程中更新,但是如果将一个实时绘图的操作放在主线程,必定会出现阻塞主线程的问题,即便是不阻塞主线程,也会降低程序运行的速度。因此,我就想到android的一个控件,surfaceView。这个控件在官网上是这样描述的:
SurfaceView是视图(View)的继承类,这个视图里内嵌了一个专门用于绘制的Surface。你可以控制这个Surface的格式和尺寸。Surfaceview控制这个Surface的绘制位置。
surface是纵深排序(Z-ordered)的,这表明它总在自己所在窗口的后面。surfaceview提供了一个可见区域,只有在这个可见区域内 的surface部分内容才可见,可见区域外的部分不可见。surface的排版显示受到视图层级关系的影响,它的兄弟视图结点会在顶端显示。这意味者 surface的内容会被它的兄弟视图遮挡,这一特性可以用来放置遮盖物(overlays)(例如,文本和按钮等控件)。注意,如果surface上面 有透明控件,那么它的每次变化都会引起框架重新计算它和顶层控件的透明效果,这会影响性能。
你可以通过SurfaceHolder接口访问这个surface,getHolder()方法可以得到这个接口。
surfaceview变得可见时,surface被创建;surfaceview隐藏前,surface被销毁。这样能节省资源。如果你要查看 surface被创建和销毁的时机,可以重载surfaceCreated(SurfaceHolder)和 surfaceDestroyed(SurfaceHolder)。
surfaceview的核心在于提供了两个线程:UI线程和渲染线程。这里应注意:
1> 所有SurfaceView和SurfaceHolder.Callback的方法都应该在UI线程里调用,一般来说就是应用程序主线程。渲染线程所要访问的各种变量应该作同步处理。
2> 由于surface可能被销毁,它只在SurfaceHolder.Callback.surfaceCreated()和 SurfaceHolder.Callback.surfaceDestroyed()之间有效,所以要确保渲染线程访问的是合法有效的surface。
通过这段话,我们可以知道,surfaceView提供了UI线程。可以自己更新UI,因此,这样我们在surfaceView中进行实时的绘画,然后通过更改其中的绘画的数据,既可以实现我们想要的实时的更新UI的这个问题了,并且消耗较小的资源。那么接下来我们来具体谈下实现的问题。
那么如何使用surfaceView实现我们的需求呢?首先我们需要自定义一个控件,并且继承surfaceView这个类。并且要在其中实现SurfaceHolder.Callback的接口。之所以实现接口,是因为我们要确保我们所做的操作需要在surfaceView创建后才能开始。然后我们来具体看下这个函数需要实现的三个函数。
new SurfaceHolder.Callback() {
@Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
//创建时需要执行的操作
}
@Override
public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {
//surfaceView大小改变时需要执行的操作
}
@Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
//销毁时进行的操作。
}
}
然后我们如果要绘制内容,并且实时的更新,需要在surfaceCreated中开一个线程,然后实时的进行绘制。这样即完成我们所需要的需求了。但是在绘制的时候需要有一些注意的地方。这个在接下来呈现出代码后我们来具体分析和具体的看,接下来是自定义view的具体的代码。我们来具体的看下。
public class MyView extends SurfaceView {
private final String TAG = "acmTest";
private SurfaceHolder mSurfaceHolder;
private Canvas mCanvas;//画布
public boolean isRunning;//用来标识是否开启绘画的线程。
Context context;
int positionX;//所绘制图形的x坐标
int positionY;//所绘制图形的y坐标
public MyView(Context context) {
super(context);
init();
}
public MyView(Context context, AttributeSet attributeSet)
{
super(context,attributeSet);
this.context = context;
init();
}
//初始化surfaceView,在这个函数中,实现surfaceHolder.Callback
public void init()
{
setBackgroundColor(Color.parseColor("#6A14b7f5"));//设置surfaceView的背景颜色
setZOrderOnTop(true);//使surfaceview放到最顶层
getHolder().setFormat(PixelFormat.TRANSLUCENT);//使窗口支持透明度
mSurfaceHolder = getHolder(); mSurfaceHolder.addCallback(new SurfaceHolder.Callback() { @Override public void surfaceCreated(SurfaceHolder surfaceHolder) {
//启动开始绘画的线程,这个线程中的函数不需要再在主线程中执行,可以直接执行并更新UI。
new Thread(new Runnable() {
@Override
public void run() {
while (isRunning)
{
drawPoint();
}
}
}).start();
}
@Override
public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {
}
@Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
}
});
}
//具体绘画的操作
public void drawPoint()
{
//需要注意这里需要通过这个方式获得canvas,不能够自己申明,为了保证从始至终用的一个canvas。
mCanvas = mSurfaceHolder.lockCanvas();
if (mCanvas != null) {
try {
mCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);//是清理上次画的内容,这个根据需求选择是否添加。因为我的需求是跟踪位置,如果不加,会将上次所画的内容保留。
Paint paint = new Paint();//声明画笔,在此基础上进行绘制
paint.setColor(Color.RED);//为红色画笔
mCanvas.drawCircle(positionX,positionY,10,paint);
} catch (Exception e) {
e.printStackTrace();
} finally {
mSurfaceHolder.unlockCanvasAndPost(mCanvas);//提交后会将提交的画布更新,然后显示
}
}
}
public void setPosition(int positionX,int positionY) {
this.positionX = positionX;
this.positionY = positionY;
}
}
这是通过继承surfaceView来进行实现实时的更新UI,然后占用少量内存。值得注意的时候,我们在初始化的时候需要考虑啊init的前三行代码,第一个设置背景颜色,不要再xml中设置,需要在这设置,否则默认背景为纯黑的。然后后两句是支持为透明的颜色,和保持能够在布局的最上方。
还有一点就是在获取画布这,需要严格的按照规定,先获取,再提交更新,在其中不可重新声明,并且提交和获取的需要为同一个canvas。
标签:super 问题 屏幕 int and 清理 ble XML 窗口
原文地址:http://www.cnblogs.com/cmai/p/7667276.html