Android6.0 由PDK-TestingCamera 学习apk布局

一、场景

今天研究android 6.0 pdk目录下testingcamera时遇到了一个布局文件的问题,本人是做底层的,研究了1个多小时才搞明白,特记录下笔记。如果有理解不到位的地方,欢迎指正,大家一起学习。

在一开始打开TestingCamera应用进行preview时,屏幕上只有一个preview预览界面。如下图所示。pdk的源码在链接

当我打开CallbackProcess时,屏幕上出现了2个预览界面,但是它是怎么重新布局的呢。在查看了布局xml文件之后,更是疑惑,下面我们结合代码来学习一下。

二、代码分析

1.SurfaceHolder.Callback接口介绍

我们知道如果activity实现了SurfaceHolder.Callback接口那么就会响应SurfaceCreated,SurfaceChanged,SurfaceDestroyed消息处理函数。他们触发的时机如下所示

SurfaceCreated:字面意思说的很明白,就是surface创建的时候触发

SurfaceChanged:同上面一行好理解,当surface的一些属性改变时触发,比如布局属性,size等

SurfaceDestroyed:当surface销毁时触发。

下面是每一个接口的官方解释,我就不细说了。

/**
     * A client may implement this interface to receive information about
     * changes to the surface.  When used with a {@link SurfaceView}, the
     * Surface being held is only available between calls to
     * {@link #surfaceCreated(SurfaceHolder)} and
     * {@link #surfaceDestroyed(SurfaceHolder)}.  The Callback is set with
     * {@link SurfaceHolder#addCallback SurfaceHolder.addCallback} method.
     */
    public interface Callback {
        /**
         * This is called immediately after the surface is first created.
         * Implementations of this should start up whatever rendering code
         * they desire.  Note that only one thread can ever draw into
         * a {@link Surface}, so you should not draw into the Surface here
         * if your normal rendering will be in another thread.
         * 
         * @param holder The SurfaceHolder whose surface is being created.
         */
        public void surfaceCreated(SurfaceHolder holder);

        /**
         * This is called immediately after any structural changes (format or
         * size) have been made to the surface.  You should at this point update
         * the imagery in the surface.  This method is always called at least
         * once, after {@link #surfaceCreated}.
         * 
         * @param holder The SurfaceHolder whose surface has changed.
         * @param format The new PixelFormat of the surface.
         * @param width The new width of the surface.
         * @param height The new height of the surface.
         */
        public void surfaceChanged(SurfaceHolder holder, int format, int width,
                int height);

        /**
         * This is called immediately before a surface is being destroyed. After
         * returning from this call, you should no longer try to access this
         * surface.  If you have a rendering thread that directly accesses
         * the surface, you must ensure that thread is no longer touching the 
         * Surface before returning from this function.
         * 
         * @param holder The SurfaceHolder whose surface is being destroyed.
         */
        public void surfaceDestroyed(SurfaceHolder holder);
    }

2.激发SurfaceChanged消息

针对TestingCamera 应用来说,当我使能callbackstream时,由于要显示callback 帧数据,所有总共有2个surfaceiew需要显示。如下当我点击CallbackOn按钮时响应的消息处理函数。

    private View.OnClickListener mCallbackToggleListener =
                new View.OnClickListener() {
        public void onClick(View v) {
            if (mCallbacksEnabled) { /*默认为false*/
                log("Disabling preview callbacks");
                stopCallbacks();
                mCallbacksEnabled = false;
                resizePreview();
                mCallbackView.setVisibility(View.GONE);

            } else {
                log("Enabling preview callbacks");
                mCallbacksEnabled = true;
                resizePreview(); /*字面意思看,它会重新设置preview的大小,这就激发了SurfaceChanged方法*/
                mCallbackView.setVisibility(View.VISIBLE);
            }
        }
    };
很意外的是在resizePreview方法中,将CallbackSurfaceView的资源布局对象赋给了previewSurfaceView对象,这会触发SurfaceChanged消息。在SurfaceChanged方法中又会调用layoutPreview方法,重新设置preview和callbackSurface对象的布局参数。

    void resizePreview() {
        // Reset preview layout parameters, to trigger layout pass
        // This will eventually call layoutPreview below
        Resources res = getResources();
        mPreviewView.setLayoutParams(
                new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, 0,
                        mCallbacksEnabled ? /*因为这里我已经使能了callback功能,这里为true*/
                        res.getInteger(R.integer.preview_with_callback_weight):
                        res.getInteger(R.integer.preview_only_weight) ));
    }
/*SurfaceCahnged消息处理方法中,会调用layoutPreview方法,重新设置previewSurfaceView和CallbackSurfaceView对象的布局参数*/
    void layoutPreview() {
        int width = mPreviewSizes.get(mPreviewSize).width;
        int height = mPreviewSizes.get(mPreviewSize).height;
        float previewAspect = ((float) width) / height;

        int viewHeight = mPreviewView.getHeight();
        int viewWidth = mPreviewView.getWidth();
        float viewAspect = ((float) viewWidth) / viewHeight;
        if ( previewAspect > viewAspect) {
            viewHeight = (int) (viewWidth / previewAspect);
        } else {
            viewWidth = (int) (viewHeight * previewAspect);
        }
        mPreviewView.setLayoutParams(
                new LayoutParams(viewWidth, viewHeight));

        if (mCallbacksEnabled) {
            int callbackHeight = mCallbackView.getHeight();
            int callbackWidth = mCallbackView.getWidth();
            float callbackAspect = ((float) callbackWidth) / callbackHeight;
            if ( previewAspect > callbackAspect) {
                callbackHeight = (int) (callbackWidth / previewAspect);
            } else {
                callbackWidth = (int) (callbackHeight * previewAspect);
            }
            mCallbackView.setLayoutParams(
                    new LayoutParams(callbackWidth, callbackHeight));
            configureCallbacks(callbackWidth, callbackHeight);
        }
    }

3.布局文件main.xml介绍

首先要介绍几个宏

1)fill_parent

设置一个构件的布局为fill_parent将强制性地使构件扩展,以填充布局单元内尽可能多的空间。这跟Windows控件的dockstyle属性大体一致。设置一个顶部布局或控件为fill_parent将强制性让它布满整个屏幕。

2) wrap_content

设置一个视图的尺寸为wrap_content将强制性地使视图扩展以显示全部内容。以TextView和ImageView控件为例,设置为wrap_content将完整显示其内部的文本和图像。布局元素将根据内容更改大小。设置一个视图的尺寸为wrap_content大体等同于设置Windows控件的Autosize属性为True。

3)match_parent
   Android2.2中match_parent和fill_parent是一个意思 .两个参数意思一样,match_parent更贴切,于是从2.2开始两个词都可以用。那么如果考虑低版本的使用情况你就需要用fill_parent了

<!--第一层LinearLayout控件
如文章开始时,看到的图片中,可以发现第一层LinearLayout控件是填满名屏幕的
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"            
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="horizontal" >
 
<!--第二层LinearLayout控件-->
<LinearLayout
        android:id="@+id/preview_column"
        android:layout_width="0dp"
        android:layout_height="fill_parent"
        android:layout_weight="6"
        android:animateLayoutChanges="false"
        android:orientation="vertical"
        android:visibility="visible" >

        <SurfaceView
            android:id="@+id/preview"
            android:layout_width="fill_parent"
            android:layout_height="0dp"
            android:layout_weight="@integer/preview_only_weight"
            tools:ignore="NestedWeights" />

        <SurfaceView
            android:id="@+id/callback_view"
            android:layout_width="fill_parent"
            android:layout_height="0dp"
            android:layout_weight="@integer/preview_with_callback_weight"
            android:visibility="gone" />

        <TextView
            android:id="@+id/log"
            android:layout_width="fill_parent"
            android:layout_height="10dp"
            android:layout_weight="1"
            android:freezesText="true"
            android:minLines="3"
            android:typeface="normal" />

    </LinearLayout>
  <ScrollView    
<!--    这一部分就是下图中3部分的,控件的布局文件,这里就不贴上来了,感兴趣可以自己查看源代码    
--></ScrollView>
</LinearLayout>
下图就是上图xml文件的效果,其中控件布局如下
标号1:该层第2个LinearLayout控件,包含其中的控件2和控件3是水平排列的。
标号2:该层是第2个LinearLayout控件,包含其中的控件4,5,6是垂直排列的。
标号4:previewSurceView控件
标号5:CallbackSurceView控件
标号6:TextView控件所在区域
为何是“android:layout_width="0dp" “
如果我们想按着空间的权值来分配宽度或者高度时,需设置对应的宽,高为0dp,如果为水平方向按比例分配的话,需设置android:layout_width="0dp",如果为竖直方向的设置android:layout_height="0dp"。在这种情况下某子个控件占用LinearLayout的比例为:本控件weight值 / LinearLayout内所有控件的weight值的和。下图中的4,5,6控件是垂直排列的,但是控件6的高度是10dp,控件4和控件5的高度都设置的是0dp,那这该怎么按比例分呢。我这里猜想如果有一个控件已经指定了宽或高,那么剩下的设置宽或高为0dp的控件会按比例分配宽高,那么控件4,5的高度就是(LCD_height - 控件6_height) / 2.

后续会细致学习一下android app
可以查看博客了解更多:http://blog.csdn.net/chy800/article/details/46397927









  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值