UI 效果(9):merge 的点点滴滴

android 布局中经常会用到 <merge></merge> 标签,来优化 ui 布局。

具体如何优化,可以借助 android sdk 提供的 tools/hierarchyviewer 工具。


这个工具,并不是万能的,你需要自己去根据实际情况分析和优化自己的布局。

该工具的使用可以查阅资料,这里不赘述。


关于  <merge></merge> 使用,推荐一篇文章,简单明了

http://www.bangchui.org/simple/?t17479.html


其实这里面还有其他标签的介绍如 include、viewstub 等。


另外,http://developer.android.com/training/improving-layouts/reusing-layouts.html

也介绍了 merge 以及merge 的好处(可以用来优化布局)。



这里总结一下 merge 注意事项


1. merge 只可以是一个布局文件中的根节点,不可以有父节点。


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/ssb"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content" 
    android:orientation="vertical">

    <merge>
        <!-- 省略 -->
    </merge>

</LinearLayout>

这个就是错误的,错误报告内容如下:



2.  merge 可以包含 include 标签,反之不行


<?xml version="1.0" encoding="utf-8"?> 
<merge xmlns:android="http://schemas.android.com/apk/res/android"

    <include 
		android:id="@+id/newone"layout="@layout/share">
    </include> 
   
	<include 
		android:id="@+id/newtwo"layout="@layout/share">
	</include>
	
</merge>

上面的用法是正确的。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/ssb"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content" 
    android:orientation="vertical">

    <include>
        
        <merge>
            <!-- 省略 -->
        </merge>
        
    </include>
    
</LinearLayout>

这种用法是错误的(也是类似 1 的错误)。


3. include 可以间接包含 merge


mergedemo.xml 文件

<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" >

    <ImageView
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:contentDescription="@null"
        android:scaleType="centerInside" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom|center"
        android:background="@drawable/sb_msg_count"
        android:gravity="center"
        android:textColor="@android:color/white" />


</merge>

main.xml 文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content" 
    android:orientation="vertical">

    <include layout="@layout/mergedemo" />

</LinearLayout>

注意这种情况下,include 进来的 xml 文件,merge 就会被忽略,没有任何作用。

也就是说,main.xml 相当于

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical" >

    <ImageView
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:contentDescription="@null"
        android:scaleType="centerInside" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom|center"
        android:gravity="center"
        android:textColor="@android:color/white" />

</LinearLayout>

这一点要注意!


4. 使用 inflate 加载 merge 布局文件


main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/ssb"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical" >

</LinearLayout>

mergedemo.xml

<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" >

    <ImageView
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:contentDescription="@null"
        android:scaleType="centerInside" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom|center"
        android:gravity="center"
        android:textColor="@android:color/white" />

</merge>

activity.java

public class MainActivity extends Activity {

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

		setContentView(R.layout.main);

		// 找到父节点
		LinearLayout superlayout = (LinearLayout) findViewById(R.id.ssb);
		// 实例化 LayoutInflater
		LayoutInflater inflater = LayoutInflater.from(getApplicationContext());
		// inflate
		View view = inflater.inflate(R.layout.mergedemo, superlayout, true);
		// 显示
		setContentView(superlayout);
	}

这里需要注意几个问题


(a). inflater.inflate(R.layout.mergedemo, superlayout, true);

必须指定 superlayout 和 true,否则报错。


(b). 不需要再次 addview

// 找到父节点
		LinearLayout superlayout = (LinearLayout) findViewById(R.id.ssb);
		// 实例化 LayoutInflater
		LayoutInflater inflater = LayoutInflater.from(getApplicationContext());
		// inflate
		View view = inflater.inflate(R.layout.mergedemo, superlayout, true);
		superlayout.addView(view);
		// 显示
		setContentView(superlayout);

代码 superlayout.addView(view); 是多余的。

具体可以查看 LayoutInflater.java 源码





5. merge 并不是一定可以取代 FrameLayout 标签。


这个需要视具体情况而定,merge 被 include 之后,是被忽略的。








<think>好的,我现在要回答用户关于OpenCV中cv::merge函数是否会重新分配内存的问题。首先,我需要回忆一下cv::merge的作用。根据用户提供的引用内容,cv::merge用于将多个单通道矩阵合并成一个多通道矩阵。比如将两个灰度图合并成一个双通道图像,或者三个单通道合并成三通道的BGR图像。 接下来,用户的问题是,这个函数在合并时是否会重新申请内存。这涉及到函数的内存管理机制。根据我的知识,当合并操作的目标矩阵(即输出矩阵)的尺寸、数据类型或通道数与输入不匹配时,OpenCV的函数通常会重新分配内存。例如,cv::merge需要将多个单通道合并,输出矩阵的通道数增加,所以必须分配新的内存来容纳这些数据。 查看用户提供的示例代码,比如引用[1]中的mergedImage,在调用cv::merge之前并没有被初始化或分配内存,因此函数内部必须为其分配新的内存。而在引用[2]中,将削弱后的通道重新合并到result,同样result之前可能没有合适的内存空间,所以需要重新分配。 此外,OpenCV的文档指出,像merge这样的函数,如果输出数组的大小或类型与输入不匹配,函数会自动重新分配内存。但如果输出数组已经具有正确的尺寸、类型和通道数,并且是连续存储的,可能会直接使用现有内存,避免重新分配。不过,这种情况在merge中比较少见,因为输入是多个单通道矩阵,而输出是多通道,通常输出矩阵的结构与输入不同,所以大部分情况下需要重新分配内存。 总结起来,cv::merge在大多数情况下会重新分配内存,特别是在输出矩阵未预先分配或结构不匹配时。如果用户想避免重复分配,可以预先创建一个正确尺寸和类型的矩阵,但需要确保其结构与合并后的结果一致,这可能比较复杂,所以通常让函数自行处理内存分配更为方便。</think>在OpenCV中,`cv::merge`函数在合并通道时会根据输出矩阵的当前状态决定是否重新分配内存。具体行为如下: --- ### 1. **内存分配规则** - **若输出矩阵尺寸/类型不匹配**:当目标矩阵(`mergedImage`)的尺寸、数据类型或通道数与输入的单通道矩阵组合后的特征不一致时,`cv::merge`会**自动重新分配内存**。例如: - 输入为2个$256 \times 256$的单通道`CV_8UC1`矩阵,合并后的输出应为$256 \times 256$的双通道`CV_8UC2`矩阵。若目标矩阵未初始化或类型不匹配,则会触发内存分配[^1][^2]。 - **若输出矩阵已匹配**:若目标矩阵已预先创建且尺寸、数据类型、通道数与预期一致,则函数会直接复用现有内存空间,避免重新分配。但这种情况需要手动精确控制,实际使用中较少见。 --- ### 2. **示例验证** 参考用户提供的代码片段[^1][^2]: ```cpp // 示例1:未预先分配内存,函数自动分配 cv::Mat mergedImage; cv::merge(images, mergedImage); // 必然重新分配内存 // 示例2:若result已创建且与合并后的结构一致,可能复用内存 cv::Mat result; cv::merge(channels, result); // 若result尺寸/类型不匹配,仍会重新分配 ``` --- ### 3. **性能建议** - **避免重复分配**:若需频繁调用`cv::merge`,可预先创建目标矩阵并通过`cv::Mat::create()`明确指定尺寸和类型,例如: ```cpp cv::Mat mergedImage; mergedImage.create(image1.rows, image1.cols, CV_8UC2); // 明确分配双通道内存 cv::merge(images, mergedImage); // 直接使用已分配的内存 ``` - **内存连续性**:OpenCV函数会优先使用连续内存块。若输入矩阵内存连续且输出矩阵已匹配,可减少内存操作开销。 --- ### 4. **原理补充** `cv::merge`的本质是通过**重构矩阵头信息**(如通道数、步长)并**复制数据**实现通道合并。当目标矩阵无法容纳新数据时,底层会调用`cv::Mat::allocate`重新申请内存[^2]。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值