您的位置:首页 > 产品设计 > UI/UE

Android 播放视频UI的功耗优化 && 动态增加view小结

2016-07-28 21:15 567 查看
背景:优化前播放视频的UI是直接用XML文件描述,这样确实方便调试和绘图。

但是如果不是动态添加surafaceview到activity的话,dumpsys sufaceFlinger会发现有一层activity的view一直存在。

但是如果我们是动态增加view到activity的话,播放视频的时候只会显示surfaceview,从而达到功耗优化的目的。

动态增加view的话,主要使用了以下重要的接口:

(1)LayoutInflater类,用起来其实和findVIewById配合很多。

主要有两个view的初始化

前者,LayoutInflater + findViewById

后者,setContentView + findViewById

最明显的区别是,前者是直接使用R.layout.XXX来找到实例目标所在的XML文件,而后者则是通过setContentView(R.layout.XXX);

所以前者比较灵活,在程序中想到就用;但是后者一般只能初始化一次。

初始化LayoutInflater的方法有三种,直接拿来主义:

LayoutInflater inflater=(LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);或

LayoutInflater inflater = LayoutInflater.from(Activity.this);或

LayoutInflater inflater = getLayoutInflater();


使用则是inflater.inflate(R.layout.XXX,null).findViewById(R.id.XXX);

(2)addView的两个方法

addView
public void addView(View child,
int width,
int height)Adds a child view with this ViewGroup's default layout parameters and the specified width and height.

参数:
child - the child view to add

addView
public void addView(View child,
ViewGroup.LayoutParams params)Adds a child view with the specified layout parameters.

指定者:
接口 ViewManager 中的 addView
参数:
child - the child view to add
params - the layout parameters to set on the child


我用的比较多的是后者。其实就是在某个view或者viewGroup下面增加一个子view,这个子view的布局就是params.

这里所说的布局就是XML文件里面,该view或者该viewGroup的排版属性而不是父布局的排版属性。

(3)setLayoutParams

setLayoutParams
public void setLayoutParams(ViewGroup.LayoutParams params)

Set the layout parameters associated with this view. These supply
parameters to the parent of this view specifying how it should be
arranged. There are many subclasses of ViewGroup.LayoutParams, and these
correspond to the different subclasses of ViewGroup that are responsible
for arranging their children.

参数:params - the layout parameters for this view


多用来重新设置该view或者viewGroup的布局。

(4)bringToFront

bringToFront
public void bringToFront()

Change the view's z order in the tree, so it's on top of other sibling
views
字面理解就是把这个view放在其他兄弟姐妹view的最上面.

注意的是要在addView(A),然后再使用A.bringToFront();

这是由其源码决定

public void bringChildToFront(View child) {
int index = indexOfChild(child);
if (index >= 0) {
removeFromArray(index);
addInArray(child, mChildrenCount);
child.mParent = this;
}
}


因为要先把这个A 从队列里面remove掉再从新add到队尾。

(5)setZOrderMediaOverlay

public void setZOrderMediaOverlay
(boolean isMediaOverlay)
Control whether the surface view's surface is placed on top of another regular surface view in the window (but still behind the window itself). This is typically used to place overlays on top of an underlying media surface view.

Note that this must be set before the surface view's containing window is attached to the window manager.


Android.Views.SurfaceView.SetZOrderMediaOverlay Method
Control whether the surface view's surface is placed on top of another regular surface view in the window (but still behind the window itself).
Syntax
[Android.Runtime.Register("setZOrderMediaOverlay", "(Z)V", "GetSetZOrderMediaOverlay_ZHandler")]
public virtual void SetZOrderMediaOverlay (bool isMediaOverlay)
Parameters
isMediaOverlay
Documentation for this section has not yet been entered.
Remarks
Control whether the surface view's surface is placed on top of another regular surface view in the window (but still behind the window itself). This is typically used to place overlays on top of an underlying media surface view.
Note that this must be set before the surface view's containing window is attached to the window manager.
Calling this overrides any previous call to SurfaceView.SetZOrderOnTop(bool).


使用于surfaceview的Z order排序,要在addView之前使用

(6)setZOrderOnTop

Android.Views.SurfaceView.SetZOrderOnTop Method
Control whether the surface view's surface is placed on top of its window.
Syntax
[Android.Runtime.Register("setZOrderOnTop", "(Z)V", "GetSetZOrderOnTop_ZHandler")]
public virtual void SetZOrderOnTop (bool onTop)
Parameters
onTop
Documentation for this section has not yet been entered.
Remarks
Control whether the surface view's surface is placed on top of its window. Normally it is placed behind the window, to allow it to (for the most part) appear to composite with the views in the hierarchy. By setting this, you cause it to be placed above the window. This means that none of the contents of the window this SurfaceView is in will be visible on top of its surface.
Note that this must be set before the surface view's containing window is attached to the window manager.
Calling this overrides any previous call to SurfaceView.SetZOrderMediaOverlay(bool).

(7)增加一个常识


android:layout_gravity 只在 LinearLayout 和 FrameLayout 中有效:
①对于 LinearLayout :
当 android:orientation="vertical"  时, 只有水平方向的设置才起作用,垂直方向的设置不起作用。即:left,right,center_horizontal 是生效的。
当 android:orientation="horizontal" 时, 只有垂直方向的设置才起作用,水平方向的设置不起作用。即:top,bottom,center_vertical 是生效的。
②对于 FrameLayout :
任意android:layout_gravity属性都有效,可以非常方便实现对组件的布局。


有了这些接口,动态增加View就是一个一个addview进去。该隐藏的隐藏的,该removeView的remove。

最后说下今天debug的一个怪异的问题:一个LinearLayout 的子view: imageview 被其兄弟一个LinearLayout的子view : textview给盖住了,但怪异的是

这个imageview不可见确能够点击。

因为是动态增加的view,一开始找不到有效地debug方法,只能想到dumpsys surfaceFlinger或者dumpsys window来看,但是看了感觉没有一一对应我的view,QAQ。

没办法,我只好一个一个把可能对盖住的imageview的嫌疑犯 一一排除。

首先我检测的是sufaceview,surfaceview调整了确实没盖住。

所以嫌疑犯在surfaceview和焦点框videoFocusLayout,后来确实是videoFocusLayout出了问题,但是没找到原因。。

解决的办法是隔离这个videoFocusLayout.

就是给他一个爹(父布局),让他和我们的imageview的老爸(LinearLayout)做不成兄弟。这样应该降低其影响面积...

最后真的ok了。。

感觉这个solution有点懵对的感觉,明天找下sufaceFlinger的大神请教下吧。。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息