`
jandroid
  • 浏览: 1933773 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

Android深入浅出之Surface[1]

 
阅读更多

Android深入浅出之Surface

目的

本节的目的就是为了讲清楚Android中的Surface系统,大家耳熟能详的SurfaceFlinger到底是个什么东西,它的工作流程又是怎样的。当然,鉴于SurfaceFlinger的复杂性,我们依然将采用情景分析的办法,找到合适的切入点。

一个Activity是怎么在屏幕上显示出来的呢?我将首先把这个说清楚。

接着我们把其中的关键调用抽象在Native层,以这些函数调用为切入点来研究SurfaceFlinger。好了,开始我们的征途吧。

Activity是如何显示的

最初的想法就是,Activity获得一块显存,然后在上面绘图,最后交给设备去显示。这个道理是没错,但是AndroidSurfaceFlinger是在System Server进程中创建的,Activity一般另有线程,这之间是如何...如何挂上关系的呢?我可以先提前告诉大家,这个过程还比较复杂。呵呵。

好吧,我们从Activity最初的启动开始。代码在

framework/base/core/java/android/app/ActivityThread.java中,这里有个函数叫handleLaunchActivity

[---->ActivityThread:: handleLaunchActivity()]

private final void handleLaunchActivity(ActivityRecord r, Intent customIntent) {

Activity a = performLaunchActivity(r, customIntent);

if (a != null) {

r.createdConfig = new Configuration(mConfiguration);

Bundle oldState = r.state;

handleResumeActivity(r.token, false, r.isForward);

---->调用handleResumeActivity

}

handleLaunchActivity中会调用handleResumeActivity

[--->ActivityThread:: handleResumeActivity]

final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward) {

boolean willBeVisible = !a.mStartedActivity;

if (r.window == null && !a.mFinished && willBeVisible) {

r.window = r.activity.getWindow();

View decor = r.window.getDecorView();

decor.setVisibility(View.INVISIBLE);

ViewManager wm = a.getWindowManager();

WindowManager.LayoutParams l = r.window.getAttributes();

a.mDecor = decor;

l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;

if (a.mVisibleFromClient) {

a.mWindowAdded = true;

wm.addView(decor, l); //这个很关键。

}

上面addView那几行非常关键,它关系到咱们在ActivitysetContentView后,整个Window到底都包含了些什么。我先告诉大家。所有你创建的View之上,还有一个DecorView,这是一个FrameLayout,另外还有一个PhoneWindow。上面这些东西的代码在

framework/Policies/Base/Phone/com/android/Internal/policy/impl。这些隐藏的View的创建都是由你在AcitivtyonCreate中调用setContentView导致的。

[---->PhoneWindow:: addContentView]

public void addContentView(View view, ViewGroup.LayoutParams params) {

if (mContentParent == null) { //刚创建的时候mContentParent为空

installDecor();

}

mContentParent.addView(view, params);

final Callback cb = getCallback();

if (cb != null) {

cb.onContentChanged();

}

}

installDecor将创建mDecormContentParentmDecorDecorView类型,

mContentParentViewGroup类型

private void installDecor() {

if (mDecor == null) {

mDecor = generateDecor();

mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);

mDecor.setIsRootNamespace(true);

}

if (mContentParent == null) {

mContentParent = generateLayout(mDecor);

那么,ViewManager wm = a.getWindowManager()又返回什么呢?

PhoneWindowWindow中派生,Acitivity创建的时候会调用它的setWindowManager。而这个函数由Window类实现。

代码在framework/base/core/java/android/view/Window.java

public void setWindowManager(WindowManager wm,IBinder appToken, String appName) {

mAppToken = appToken;

mAppName = appName;

if (wm == null) {

wm = WindowManagerImpl.getDefault();

}

mWindowManager = new LocalWindowManager(wm);

}

你看见没,分析JAVA代码这个东西真的很复杂。mWindowManager的实现是LocalWindowManager,但由通过Bridge模式把功能交给WindowManagerImpl去实现了。

真的很复杂!

好了,罗里罗嗦的,我们回到wm.addView(decor, l)。最终会由WindowManagerImpl来完成

addView操作,我们直接看它的实现好了。

代码在framework/base/core/java/android/view/WindowManagerImpl.java

[---->addView]

private void addView(View view, ViewGroup.LayoutParams params, boolean nest)

{

ViewRoot root; //ViewRoot,我们的主人公终于登场!

synchronized (this) {

root = new ViewRoot(view.getContext());

root.mAddNesting = 1;

view.setLayoutParams(wparams);

if (mViews == null) {

index = 1;

mViews = new View[1];

mRoots = new ViewRoot[1];

mParams = new WindowManager.LayoutParams[1];

} else {

}

index--;

mViews[index] = view;

mRoots[index] = root;

mParams[index] = wparams;

}

root.setView(view, wparams, panelParentView);

}

ViewRoot是整个显示系统中最为关键的东西,看起来这个东西好像和View有那么点关系,其实它根本和ViewUI关系不大,它不过是一个Handler罢了,唯一有关系的就是它其中有一个变量为Surface类型。我们看看它的定义。ViewRoot代码在

framework/base/core/java/android/view/ViewRoot.java

public final class ViewRoot extends Handler implements ViewParent,

View.AttachInfo.Callbacks

{

private final Surface mSurface = new Surface();

}

它竟然从handler派生,而ViewParent不过定义了一些接口函数罢了。

看到Surface直觉上感到它和SurfaceFlinger有点关系。要不先去看看?

Surface代码在framework/base/core/java/android/view/Surface.java中,我们调用的是无参构造函数。

public Surface() {

mCanvas = new CompatibleCanvas(); //就是创建一个Canvas

}

如果你有兴趣的话,看看Surface其他构造函数,最终都会调用native的实现,而这些native的实现将和SurfaceFlinger建立关系,但我们这里ViewRoot中的mSurface显然还没有到这一步。那它到底是怎么和SurfaceFlinger搞上的呢?这一切待会就会水落石出的。

另外,为什么ViewRoot是主人公呢?因为ViewRoot建立了客户端和SystemServer的关系。我们看看它的构造函数。

public ViewRoot(Context context) {

super();

....

getWindowSession(context.getMainLooper());

}

getWindowsession将建立和WindowManagerService的关系。

ublic static IWindowSession getWindowSession(Looper mainLooper) {

synchronized (mStaticInit) {

if (!mInitialized) {

try {

//sWindowSession是通过Binder机制创建的。终于让我们看到点希望了

InputMethodManager imm = InputMethodManager.getInstance(mainLooper);

sWindowSession = IWindowManager.Stub.asInterface(

ServiceManager.getService("window"))

.openSession(imm.getClient(), imm.getInputContext());

mInitialized = true;

} catch (RemoteException e) {

}

}

return sWindowSession;

}

}

上面跨Binder的进程调用另一端是WindowManagerService,代码在

framework/base/services/java/com/android/server/WindowManagerService.java中。我们先不说这个。

回过头来看看ViewRoot接下来的调用。

[-->ViewRoot::setView()],这个函数很复杂,我们看其中关键几句。

public void setView(View view, WindowManager.LayoutParams attrs,

View panelParentView) {

synchronized (this) {

requestLayout();

try {

res = sWindowSession.add(mWindow, mWindowAttributes,

getHostVisibility(), mAttachInfo.mContentInsets);

}

}

requestLayout实现很简单,就是往handler中发送了一个消息。

public void requestLayout() {

checkThread();

mLayoutRequested = true;

scheduleTraversals(); //发送DO_TRAVERSAL消息

}

public void scheduleTraversals() {

if (!mTraversalScheduled) {

mTraversalScheduled = true;

sendEmptyMessage(DO_TRAVERSAL);

}

}

我们看看跨进程的那个调用。sWindowSession.add。它的最终实现在WindowManagerService中。

[--->WindowSession::add()]

public int add(IWindow window, WindowManager.LayoutParams attrs,

int viewVisibility, Rect outContentInsets) {

return addWindow(this, window, attrs, viewVisibility, outContentInsets);

}

WindowSession是个内部类,会调用外部类的addWindow

这个函数巨复杂无比,但是我们的核心目标是找到创建显示相关的部分。所以,最后精简的话就简单了。

[--->WindowManagerService:: addWindow]

public int addWindow(Session session, IWindow client,

WindowManager.LayoutParams attrs, int viewVisibility,

Rect outContentInsets) {

//创建一个WindowState,这个又是什么玩意儿呢?

win = new WindowState(session, client, token,

attachedWindow, attrs, viewVisibility);

win.attach();

return res;

}

WindowState类中有一个和Surface相关的成员变量,叫SurfaceSession。它会在

attach函数中被创建。SurfaceSession嘛,就和SurfaceFlinger有关系了。我们待会看。

好,我们知道ViewRoot创建及调用add后,我们客户端的View系统就和WindowManagerService建立了牢不可破的关系。

另外,我们知道ViewRoot是一个handler,而且刚才我们调用了requestLayout,所以接下来消息循环下一个将调用的就是ViewRoothandleMessage

public void handleMessage(Message msg) {

switch (msg.what) {

case DO_TRAVERSAL:

performTraversals();

performTraversals更加复杂无比,经过我仔细挑选,目标锁定为下面几个函数。当然,后面我们还会回到performTraversals,不过我们现在更感兴趣的是Surface是如何创建的。

private void performTraversals() {

// cache mView since it is used so much below...

final View host = mView;

boolean initialized = false;

boolean contentInsetsChanged = false;

boolean visibleInsetsChanged;

try {

//ViewRoot也有一个Surface成员变量,叫mSurface,这个就是代表SurfaceFlinger的客户端

//ViewRoot在这个Surface上作画,最后将由SurfaceFlinger来合成显示。刚才说了mSurface还没有什么内容。

relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);

[---->ViewRoot:: relayoutWindow()]

private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility,

boolean insetsPending) throws RemoteException {

//relayOut是跨进程调用,mSurface做为参数传进去了,看来离真相越来越近了呀!

int relayoutResult = sWindowSession.relayout(

mWindow, params,

(int) (mView.mMeasuredWidth * appScale + 0.5f),

(int) (mView.mMeasuredHeight * appScale + 0.5f),

viewVisibility, insetsPending, mWinFrame,

mPendingContentInsets, mPendingVisibleInsets,

mPendingConfiguration, mSurface); mSurface做为参数传进去了。

}

我们赶紧转到WindowManagerService去看看吧。、

public int relayoutWindow(Session session, IWindow client,

WindowManager.LayoutParams attrs, int requestedWidth,

int requestedHeight, int viewVisibility, boolean insetsPending,

Rect outFrame, Rect outContentInsets, Rect outVisibleInsets,

Configuration outConfig, Surface outSurface){

.....

try {

//看到这里,我内心一阵狂喜,有戏,太有戏了!

//其中win是我们最初创建的WindowState

Surface surface = win.createSurfaceLocked();

if (surface != null) {

//先创建一个本地surface,然后把传入的参数outSurface copyFrom一下

outSurface.copyFrom(surface);

win.mReportDestroySurface = false;

win.mSurfacePendingDestroy = false;

} else {

outSurface.release();

}

}

}

[--->WindowState::createSurfaceLocked]

Surface createSurfaceLocked() {

try {

mSurface = new Surface(

mSession.mSurfaceSession, mSession.mPid,

mAttrs.getTitle().toString(),

0, w, h, mAttrs.format, flags);

}

Surface.openTransaction();

这里使用了Surface的另外一个构造函数。

public Surface(SurfaceSession s,

int pid, String name, int display, int w, int h, int format, int flags)

throws OutOfResourcesException {

mCanvas = new CompatibleCanvas();

init(s,pid,name,display,w,h,format,flags); ---->调用了nativeinit函数。

mName = name;

}

到这里,不进入JNI是不可能说清楚了。不过我们要先回顾下之前的关键步骤。

l add中,new了一个SurfaceSession

l 创建new了一个Surface

l 调用copyFrom,把本地Surface信息传到outSurface

JNI

上面两个类的JNI实现都在framework/base/core/jni/android_view_Surface.cpp中。

[---->SurfaceSession:: SurfaceSession()]

public class SurfaceSession {

/** Create a new connection with the surface flinger. */

public SurfaceSession() {

init();

}

它的init函数对应为:

[--->SurfaceSession_init]

static void SurfaceSession_init(JNIEnv* env, jobject clazz)

{

//SurfaceSession对应为SurfaceComposerClient

sp<SurfaceComposerClient> client = new SurfaceComposerClient;

client->incStrong(clazz);

//Google常用做法,在JAVA对象中保存C++对象的指针。

env->SetIntField(clazz, sso.client, (int)client.get());

}

Surfaceinit对应为:

[--->Surface_init]

static void Surface_init(

JNIEnv* env, jobject clazz,

jobject session,

jint pid, jstring jname, jint dpy, jint w, jint h, jint format, jint flags)

{

SurfaceComposerClient* client =

(SurfaceComposerClient*)env->GetIntField(session, sso.client);

sp<SurfaceControl> surface;

if (jname == NULL) {

//clientSurfaceComposerClient,返回的surface是一个SurfaceControl

//真得很复杂!

surface = client->createSurface(pid, dpy, w, h, format, flags);

} else {

const jchar* str = env->GetStringCritical(jname, 0);

const String8 name(str, env->GetStringLength(jname));

env->ReleaseStringCritical(jname, str);

surface = client->createSurface(pid, name, dpy, w, h, format, flags);

}

//surfaceControl信息设置到Surface对象中

setSurfaceControl(env, clazz, surface);

}

static void setSurfaceControl(JNIEnv* env, jobject clazz,

const sp<SurfaceControl>& surface)

{

SurfaceControl* const p =

(SurfaceControl*)env->GetIntField(clazz, so.surfaceControl);

if (surface.get()) {

surface->incStrong(clazz);

}

if (p) {

p->decStrong(clazz);

}

env->SetIntField(clazz, so.surfaceControl, (int)surface.get());

}

[--->Surface_copyFrom]

static void Surface_copyFrom(

JNIEnv* env, jobject clazz, jobject other)

{

const sp<SurfaceControl>& surface = getSurfaceControl(env, clazz);

const sp<SurfaceControl>& rhs = getSurfaceControl(env, other);

if (!SurfaceControl::isSameSurface(surface, rhs)) {

setSurfaceControl(env, clazz, rhs);

//把本地那个surfacesurfaceControl对象转移到outSurface

}

}

这里仅仅是surfaceControl的转移,但是并没有看到Surface相关的信息。

那么Surface在哪里创建的呢?为了解释这个问题,我使用了终极武器,aidl

1 终极武器AIDL

aidl可以把XXX.aidl文件转换成对应的java文件。我们刚才调用的是WindowSession

relayOut函数。如下:

sWindowSession.relayout(

mWindow, params,

(int) (mView.mMeasuredWidth * appScale + 0.5f),

(int) (mView.mMeasuredHeight * appScale + 0.5f),

viewVisibility, insetsPending, mWinFrame,

mPendingContentInsets, mPendingVisibleInsets,

mPendingConfiguration, mSurface);

它的aidl文件在framework/base/core/java/android/view/IWindowSession.aidl

interface IWindowSession {

int add(IWindow window, in WindowManager.LayoutParams attrs,

in int viewVisibility, out Rect outContentInsets);

void remove(IWindow window);

//注意喔,这个outSurface前面的是out,表示输出参数,这个类似于C++的引用。

int relayout(IWindow window, in WindowManager.LayoutParams attrs,

int requestedWidth, int requestedHeight, int viewVisibility,

boolean insetsPending, out Rect outFrame, out Rect outContentInsets,

out Rect outVisibleInsets, out Configuration outConfig,

out Surface outSurface);

刚才说了,JNI及其JAVA调用只是copyFromSurfaceControl对象到outSurface中,但是没看到哪里创建Surface。这其中的奥秘就在aidl文件编译后生成的java文件中。

你在命令行下可以输入:

aidl-Id:/android-2.2-froyo-20100625-source/source/frameworks/base/core/java/-Id:/android-2.2-froyo-20100625-source/source/frameworks/base/Graphics/javad:/android-2.2-froyo-20100625-source/source/frameworks/base/core/java/android/view/IWindowSession.aidl test.java

以生成test.java文件。-I参数指定include目录,例如aidl有些参数是在别的java文件中指定的,那么这个-I就需要把这些目录包含进来。

先看看ViewRoot这个客户端生成的代码是什么。

public int relayout(

android.view.IWindow window,

android.view.WindowManager.LayoutParams attrs,

int requestedWidth, int requestedHeight,

int viewVisibility, boolean insetsPending,

android.graphics.Rect outFrame,

android.graphics.Rect outContentInsets,

android.graphics.Rect outVisibleInsets,

android.content.res.Configuration outConfig,

android.view.Surface outSurface) ---->outSurface是第11个参数

throws android.os.RemoteException

{

android.os.Parcel _data = android.os.Parcel.obtain();

android.os.Parcel _reply = android.os.Parcel.obtain();

int _result;

try {

_data.writeInterfaceToken(DESCRIPTOR);

_data.writeStrongBinder((((window!=null))?(window.asBinder()):(null)));

if ((attrs!=null)) {

_data.writeInt(1);

attrs.writeToParcel(_data, 0);

}

else {

_data.writeInt(0);

}

_data.writeInt(requestedWidth);

_data.writeInt(requestedHeight);

_data.writeInt(viewVisibility);

_data.writeInt(((insetsPending)?(1):(0)));

//奇怪,outSurface的信息没有写到_data中。那.....

mRemote.transact(Stub.TRANSACTION_relayout, _data, _reply, 0);

_reply.readException();

_result = _reply.readInt();

if ((0!=_reply.readInt())) {

outFrame.readFromParcel(_reply);

}

....

if ((0!=_reply.readInt())) {

outSurface.readFromParcel(_reply); //Parcel中读取信息来填充outSurface

}

}

finally {

_reply.recycle();

_data.recycle();

}

return _result;

}

真奇怪啊,Binder客户端这头竟然没有把outSurface的信息发过去。我们赶紧看看服务端。

服务端这边处理是在onTranscat函数中。

@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException

{

switch (code)

{

case TRANSACTION_relayout:

{

data.enforceInterface(DESCRIPTOR);

android.view.IWindow _arg0;

android.view.Surface _arg10;

//刚才说了,Surface信息并没有传过来,那么我们在relayOut中看到的outSurface是怎么

//出来的呢?看下面这句,原来在服务端这边竟然new了一个新的Surface!!!

_arg10 = new android.view.Surface();

int _result = this.relayout(_arg0, _arg1, _arg2, _arg3, _arg4, _arg5, _arg6, _arg7, _arg8, _arg9, _arg10);

reply.writeNoException();

reply.writeInt(_result);

//_arg10copyFrom了,那怎么传到客户端呢?

if ((_arg10!=null)) {

reply.writeInt(1);//调用SurfacewriteToParcel,把信息加入reply

_arg10.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);

}

return true;

}

太诡异了!竟然有这么多花花肠子。我相信如果没有aidl的帮助,我无论如何也不会知道这其中的奥妙。

那好,我们的流程明白了。

l 客户端虽然传了一个surface,但其实没传递给服务端

l 服务端调用writeToParcel,把信息写到Parcel中,然后数据传回客户端

l 客户端调用SurfacereadFromParcel,获得surface信息。

那就去看看writeToParcel吧。

[---->Surface_writeToParcel]

static void Surface_writeToParcel(

JNIEnv* env, jobject clazz, jobject argParcel, jint flags)

{

Parcel* parcel = (Parcel*)env->GetIntField(

argParcel, no.native_parcel);

const sp<SurfaceControl>& control(getSurfaceControl(env, clazz));

//还好,只是把数据序列化到Parcel

SurfaceControl::writeSurfaceToParcel(control, parcel);

if (flags & PARCELABLE_WRITE_RETURN_VALUE) {

setSurfaceControl(env, clazz, 0);

}

}

那看看客户端的Surface_readFromParcel吧。

[----->Surface_readFromParcel]

static void Surface_readFromParcel(

JNIEnv* env, jobject clazz, jobject argParcel)

{

Parcel* parcel = (Parcel*)env->GetIntField( argParcel, no.native_parcel);

//客户端这边还没有surface

const sp<Surface>& control(getSurface(env, clazz));

//不过我们看到希望了,根据服务端那边Parcel信息来构造一个新的surface

sp<Surface> rhs = new Surface(*parcel);

if (!Surface::isSameSurface(control, rhs)) {

setSurface(env, clazz, rhs); //把这个新surface赋给客户端。终于我们有了surface

}

}

到此,我们终于七拐八绕的得到了surface,这其中经历太多曲折了。下一节,我们将精简这其中复杂的操作,统一归到Native层,以这样为切入点来了解Surface的工作流程和原理。

好,反正你知道ViewRoot调用了relayout后,Surface就真正从WindowManagerService那得到了。继续回到ViewRoot,其中还有一个重要地方是我们知道却不了解的。

private void performTraversals() {

// cache mView since it is used so much below...

final View host = mView;

boolean initialized = false;

boolean contentInsetsChanged = false;

boolean visibleInsetsChanged;

try {

relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);

// relayoutWindow完后,我们得到了一个无比宝贵的Surface

//那我们画界面的地方在哪里?就在这个函数中,离relayoutWindow不远处。

....

boolean cancelDraw = attachInfo.mTreeObserver.dispatchOnPreDraw();

if (!cancelDraw && !newSurface) {

mFullRedrawNeeded = false;

draw(fullRedrawNeeded); //draw?draw什么呀?

}

[--->ViewRoot::draw()]

private void draw(boolean fullRedrawNeeded) {

Surface surface = mSurface; //嘿嘿,不担心了,surface资源都齐全了

if (surface == null || !surface.isValid()) {

return;

}

if (mAttachInfo.mViewScrollChanged) {

mAttachInfo.mViewScrollChanged = false;

mAttachInfo.mTreeObserver.dispatchOnScrollChanged();

}

int yoff;

final boolean scrolling = mScroller != null && mScroller.computeScrollOffset();

if (scrolling) {

yoff = mScroller.getCurrY();

} else {

yoff = mScrollY;

}

if (mCurScrollY != yoff) {

mCurScrollY = yoff;

fullRedrawNeeded = true;

}

float appScale = mAttachInfo.mApplicationScale;

boolean scalingRequired = mAttachInfo.mScalingRequired;

Rect dirty = mDirty;

if (mUseGL) { //我们不用OPENGL

...

}

Canvas canvas;

try {

int left = dirty.left;

int top = dirty.top;

int right = dirty.right;

int bottom = dirty.bottom;

//Surface中锁定一块区域,这块区域是我们认为的需要重绘的区域

canvas = surface.lockCanvas(dirty);

// TODO: Do this in native

canvas.setDensity(mDensity);

}

try {

if (!dirty.isEmpty() || mIsAnimating) {

long startTime = 0L;

try {

canvas.translate(0, -yoff);

if (mTranslator != null) {

mTranslator.translateCanvas(canvas);

}

canvas.setScreenDensity(scalingRequired

? DisplayMetrics.DENSITY_DEVICE : 0);

//mView就是之前的decoreView,

mView.draw(canvas);

}

} finally {

//我们的图画完了,告诉surface释放这块区域

surface.unlockCanvasAndPost(canvas);

}

if (scrolling) {

mFullRedrawNeeded = true;

scheduleTraversals();

}

}

看起来,这个surface的用法很简单嘛:

l lockSurface,得到一个画布Canvas

l 调用Viewdraw,让他们在这个Canvas上尽情绘图才。另外,这个View会调用所有它的子View来画图,最终会进入到ViewonDraw函数中,在这里我们可以做定制化的界面美化工作。当然,如果你想定制化整个系统画图的话,完全可以把performTranvsal看懂,然后再修改。

l unlockCanvasAndPost,告诉Surface释放这块画布

当然,这几个重要函数调用干了具体的活。这些重要函数,我们最终会精简到Native层的。

2 总结

到这里,你应该知道了一个Activity中,调用setContentView后它如何从系统中获取一块Surface,以及它是如何使用这个Surface的了。不得不说,关于UI这块,Android绝对是够复杂的。难怪2.3UI这块代码基本重写一遍,希望能够简单精炼点。

分享到:
评论

相关推荐

    Android深入浅出之Surface.pdf

    ### Android深入浅出之Surface详解 #### 一、引言 在深入了解Android系统中的Surface机制之前,我们需要明确几个核心概念。在Android系统中,Surface是一个关键的概念,它主要用于描述一个可以绘制图像的区域,...

    android JNI video工程(surface显示输出)

    1. **JNI基础**:JNI是Android系统提供的一种接口,用于Java代码与本地(C/C++)代码之间的通信。开发者可以通过JNI调用C/C++库,提高性能或利用已有的C/C++库资源。在Android应用中,JNI通常用于处理计算密集型任务,...

    Android中使用SurfaceTexture自定义相机

    本教程将深入探讨如何使用SurfaceTexture来实现自定义相机预览,并在PictureCallback回调中保存图片。 首先,了解SurfaceTexture的基本概念。SurfaceTexture是一个抽象接口,它与OpenGL ES纹理绑定,允许将硬件图形...

    android 通过surfacetexture绘制Bitmap

    android 通过surfacetexture绘制Bitmap,使用ISurfaceComposerClient创建新图层

    Android-Surface-.rar_android surface_surface

    这个压缩包“Android-Surface-.rar”包含了对Android Surface的深入学习资料,非常适合开发者进行参考学习。让我们一起深入了解Surface及其在Android开发中的作用。 首先,Surface是Android系统中的一个抽象接口,...

    android C使用surface实现画图功能

    在Android系统中,Surface是用来处理图形绘制的核心组件,它提供了硬件加速的图形渲染接口,使得开发者可以在不阻塞用户界面的情况下进行高效的图像处理。在这个项目中,我们将关注如何使用C语言来调用Surface来实现...

    详解AndroidSurface

    在深入学习Surface时,可以参考提供的资源,如《详解Android Surface系统 - OPhoneAndroid技术讨论区 - 中国移动MM论坛.html》和《Android深入浅出之Surface.pdf》,这些资料将详细介绍Surface的原理、最佳实践以及...

    android glsurface example

    1. **初始化GLSurfaceView**:在Android应用中,首先需要创建一个GLSurfaceView实例,并设置其渲染器(Renderer)。渲染器负责所有OpenGL ES的绘制操作。通常,我们会在Activity的onCreate()方法中进行这些设置。 2...

    Android平台OpenGLES3将GL-TEXTURE-2D纹理id渲染到ImageReader提供的Surface上

    Android平台 将 GL_TEXTURE_2D纹理 渲染到 Surface 上 案例实现文章介绍: https://xiaxl.blog.csdn.net/article/details/131682521 技术实现流程大致如下: 1、OpenGLES3中加载GL_TEXTURE_2D纹理,生成纹理ID; 2...

    android surface 背景透明,图片拖拉

    在Android开发中,实现"android surface 背景透明,图片拖拉"的功能涉及到多个关键知识点,这将为用户提供一种交互式的地图编辑体验。以下是对这些技术要点的详细解释: 1. **SurfaceView**: SurfaceView是Android...

    深入理解Android卷1全

    深入理解Android 卷1 不是扫描版的,是全版电子书的,非PDF,可编辑,各种阅览器以打开!包括书签和同步目录! 第1章 阅读前的准备工作 / 1 1.1 系统架构 / 2 1.1.1 Android系统架构 / 2 1.1.2 本书的架构 / 3 1.2 ...

    Android Surface

    1. frameworks/base/graphics/java/android/graphics/Surface.java:提供 Surface 的接口定义。 2. frameworks/base/core/java/android/view/Surface.java:提供 Surface 的实现。 3. frameworks/base/services/java...

    深入理解Android 卷1.pdf

    第8章深入讲解了Surface系统的实现原理,分析了Surface与Activity之间以及Surface与SurfaceFlinger之间的关系、SurfaceFlinger的工作原理、Surface系统中的帧数据传输以及LayerBuffer的工作流程。第9章对Vold和Rild...

    Android_Surface系统的实现

    图1展示了Android应用和Surface系统之间的交互过程,通过这一系列步骤,我们可以更清晰地理解Activity、WMS以及SurfaceFlinger之间的关联。 1. **系统启动新的Activity:**当用户触发某个事件导致系统需要启动一个...

    surface pro运行android x86 4.4 r1启动文件

    让surface pro1、2、3代平板从U盘运行最新android-x86-4.4-r1的启动文件,安装方法:复制压缩包内所有文件夹到U盘,网上下载android-x86-4.4-r1.iso后解压所有文件到U盘即可;进入android系统方法:关机状态下按住...

    Android Surface画图游戏 示例代码

    "Android Surface画图游戏 示例代码"提供了一个完整的工程实例,可以帮助开发者深入理解如何利用SurfaceView及其相关组件来实现游戏的图形渲染。下面我们将详细探讨这个示例项目中的关键知识点。 1. **Android ...

    《深入理解Android(卷1)》

    总之,《深入理解Android(卷1)》是一本全面而深入的Android技术指南,无论你是初学者还是有经验的开发者,都能从中获益匪浅。结合书中详尽的解释和实际案例,你可以逐步建立起对Android系统深层运作的深刻认识。

    深入理解Android卷1

    第8章深入讲解了Surface系统的实现原理,分析了Surface与Activity之间以及Surface与SurfaceFlinger之间的关系、SurfaceFlinger的工作原理、Surface系统中的帧数据传输以及LayerBuffer的工作流程。第9章对Vold和Rild...

    android mediacodec surface sample

    1. **MediaCodec**:Android系统提供的原生API,用于处理媒体编码和解码任务。它可以处理多种不同的编码格式,包括H264、AAC等。MediaCodec工作在硬件级别,因此它能够高效地处理多媒体数据,减少CPU占用。 2. **H...

    android socket surface视频流播放器

    本文将详细解析"android socket surface mediacodec h264"这个主题,涵盖如何通过Socket接收视频流数据,并利用Surface和MediaCodec进行解码与播放。 首先,Socket是网络通信的基础,它提供了进程间的数据传输通道...

Global site tag (gtag.js) - Google Analytics