首页 > 代码库 > SurfaceView源码以及崩溃剖析
SurfaceView源码以及崩溃剖析
1 在eclipse中查看Android源代码
假设我们想参看Activity类的源代码,按着Ctrl键,左击它,现实的结果却看不到代码的,提示的信息便是“找不到Activity.class文件”。下载好Android源码之后,点击Attached Source,选择External location
External Folder文件夹菜单,选择Android所在的目录即可
http://jingyan.baidu.com/article/5d368d1e01df803f60c057f8.html
2 SurfaceView的继承关系
public class android.view.SurfaceView extendsandroid.view.View
3 如何知道Activity控件渲染完毕,可以监听事件Activity是否获得焦点
当activity获得焦点之后,activity是加载完毕的了,这个方法的技巧性比较强,很难想到。
1. @Override
2. publicvoid onWindowFocusChanged(boolean hasFocus) {
3. // TODOAuto-generated method stub
4. super.onWindowFocusChanged(hasFocus);
5. if(hasFocus){
6. showPopupWindow(getApplicationContext());
7. }
8. }
4 Surface的创建与有效性
当SurfaceView被实例化时,Surface并没有立即创建。相反,它是异步创建的。每当活动暂停或再次恢复而重新创建时,该Surface都将被销毁
只要Surface没有生效,我们就不能从SurfaceHolder中获取Canvas。不过,我们可以通过下面的语句来查看Surface是否已被创建:
boolean isCreated =surfaceHolder.getSurface().isValid();
如果该方法返回true,我们就可安全的锁定该Surface并通过接收到的Canvas来在其上进行绘制。我们必须绝对确保在调用SurfaceHolder.lockCanvas()之后再次解锁Surface,否则我们的活动可能会锁定手机。
参考
http://www.2cto.com/kf/201302/188341.html
5 Thread与SurfaceView
View组件由UI线程(主线程)所执行。如果需要迅速更新UI画面或UI画图需要较长时间,则需要使用SurfaceView。它可由后台线程(background thread)来执行,而View只能由UI(主)线程执行。SurfaceView内有高效的rendering机制,可以让后台线程快速刷新Surface的内容。
View ---> UI(主)线程
SurfaceView ---> 后台线程
参考
http://blog.csdn.net/myarrow/article/details/14223493
7 在找findViewById的过程中,由于开始忽略子类ViewGroup对View方法的重写,导致在View.class万行代码中陷入死循环
http://www.2cto.com/kf/201506/410705.html
8 viewRoot 的目的,实际上在什么地方渲染控件
每个activity有个window,window被windowmanager管理.
每个window都有decorview.
每个window都有ViewRoot.
绘制发起从ViewRoot.
事件传递发起冲ViewRoot.
绘制传递canvas, canvas来自surface.
http://blog.csdn.net/jacklam200/article/details/50038989
9 SurfaceView传递给底层NDK出错提示如下:
E/ExtMediaPlayer-JNI: env->IsInstanceOffails
E/MediaPlayer-JNI: JNIMediaPlayerFactory:bIsQCMediaPlayerPresent 0
private SurfaceHolder holder;
在查看的例子当中都是使用holder = this.getHolder();获取SurfaceHolder,
而没有通过参数的传递获取到SurfaceHolder变量
public void surfaceCreated(SurfaceHolder holder) {
// TODO Auto-generated method stub
holder = this.getHolder();
}
10 使用SurfaceView出现的崩溃信息
java.lang.RuntimeException: Could not read input channel file descriptors from parcel.
at android.view.InputChannel.nativeReadFromParcel(Native Method)
at android.view.InputChannel.readFromParcel(InputChannel.java:148)
at android.view.InputChannel$1.createFromParcel(InputChannel.java:39)
at android.view.InputChannel$1.createFromParcel(InputChannel.java:36)
at com.android.internal.view.InputBindResult.<init>(InputBindResult.java:68)
at com.android.internal.view.InputBindResult$1.createFromParcel(InputBindResult.java:112)
at com.android.internal.view.InputBindResult$1.createFromParcel(InputBindResult.java:109)
at com.android.internal.view.IInputMethodManager$Stub$Proxy.windowGainedFocus(IInputMethodManager.java:735)
at android.view.inputmethod.InputMethodManager.startInputInner(InputMethodManager.java:1232)
at android.view.inputmethod.InputMethodManager.onPostWindowFocus(InputMethodManager.java:1456)
at android.view.ViewRootImpl$ViewRootHandler.handleMessage(ViewRootImpl.java:3410)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5438)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:739)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:629)
11 创建简单Surface测试例子
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.os.Handler;
import android.os.Looper;
import android.os.MessageQueue;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.Display;
import android.view.Surface;
import android.view.GestureDetector.OnGestureListener;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceHolder.Callback;
import android.view.SurfaceView;
import android.view.View;
public class MySurfaceView extends SurfaceView implements Callback{
int m_nWidth = 0;
int m_nHeight = 0;
static boolean m_isInitial = false;
static boolean m_Initialend = false;
public static boolean canTouch = true;
SurfaceHolder holder = null;
Surface m_surface = null;
Context m_context = null;
@SuppressWarnings("deprecation")
public MySurfaceView(Context context) {
super(context);
init(context);
}
public MySurfaceView(Context context, AttributeSet sets) {
super(context, sets);
init(context);
}
private void init(Context context)
{
m_context = context;
Display d = ((Activity) context).getWindowManager().getDefaultDisplay();
m_nWidth = d.getWidth();
m_nHeight = d.getHeight();
holder = getHolder();
holder.addCallback(this);
setZOrderOnTop(false);
}
@Override
public void surfaceChanged(SurfaceHolder surfaceholder, int arg1, int arg2,
int arg3) {
// TODO Auto-generated method stub
}
@Override
public void surfaceCreated(SurfaceHolder surfaceholder)
{
m_surface = surfaceholder.getSurface();
Thread newThread = new Thread(new Runnable()
{
@Override
public void run()
{
Canvas c = null;
try
{
synchronized (holder)
{
c = holder.lockCanvas();//锁定画布,一般在锁定后就可以通过其返回的画布对象Canvas,在其上面画图等操作了。
c.drawColor(Color.BLUE);//设置画布背景颜色
Paint p = new Paint(); //创建画笔
p.setColor(Color.WHITE);
Rect r = new Rect(100, 50, 300, 250);
c.drawRect(r, p);
}
}
catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
finally
{
if(c!= null)
{
holder.unlockCanvasAndPost(c);//结束锁定画图,并提交改变。
}
}
}
});
newThread.start();
}
@Override
public void surfaceDestroyed(SurfaceHolder surfaceholder)
{
}
}
12 Surface渲染的时候黑屏一下,然后才显示界面
主要是Surface的背景是黑色的,如果渲染的时间过长,就可以明显的看到没有渲染完成的过程,其实这个时候可以设置一下Surface的背景,可以设置为柔和的颜色
SurfaceView源码以及崩溃剖析