在Android开发中,解析XML数据和实现表情弹出框是两类非常实用的功能,DOM解析适合处理结构明确的XML文件,表情弹出框则能提升聊天类应用的交互体验,下面分别讲解两种功能的实现方案。

一、Android中使用DOM解析XML
DOM解析的核心是将整个XML文档加载到内存中,构建成节点树,之后通过遍历节点树获取需要的数据,适合XML文件较小、需要频繁操作节点的场景。
1. 准备XML测试文件
首先在项目的assets目录下创建emoji_config.xml文件,用于存储表情的基础配置信息,内容如下:
<?xml version="1.0" encoding="utf-8"?>
<emoji_list>
<emoji>
<id>1</id>
<name>微笑</name>
<icon>emoji_smile</icon>
</emoji>
<emoji>
<id>2</id>
<name>大笑</name>
<icon>emoji_laugh</icon>
</emoji>
<emoji>
<id>3</id>
<name>难过</name>
<icon>emoji_sad</icon>
</emoji>
</emoji_list>2. DOM解析实现步骤
解析流程主要分为获取XML输入流、构建Document对象、遍历节点获取内容三个步骤,具体代码如下:
import android.content.Context;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
public class XmlParser {
// 表情数据实体类
public static class Emoji {
public int id;
public String name;
public String icon;
}
// DOM解析XML方法
public static List<Emoji> parseEmojiXml(Context context) {
List<Emoji> emojiList = new ArrayList<>();
try {
// 1. 获取assets目录下的XML输入流
InputStream is = context.getAssets().open("emoji_config.xml");
// 2. 获取DocumentBuilderFactory实例
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
// 3. 获取DocumentBuilder实例
DocumentBuilder builder = factory.newDocumentBuilder();
// 4. 解析输入流得到Document对象
Document document = builder.parse(is);
// 5. 获取根节点
Element rootElement = document.getDocumentElement();
// 6. 获取所有emoji节点
NodeList emojiNodeList = rootElement.getElementsByTagName("emoji");
// 7. 遍历emoji节点
for (int i = 0; i < emojiNodeList.getLength(); i++) {
Node emojiNode = emojiNodeList.item(i);
if (emojiNode.getNodeType() == Node.ELEMENT_NODE) {
Element emojiElement = (Element) emojiNode;
Emoji emoji = new Emoji();
// 获取id节点内容
NodeList idNodeList = emojiElement.getElementsByTagName("id");
if (idNodeList.getLength() > 0) {
emoji.id = Integer.parseInt(idNodeList.item(0).getTextContent());
}
// 获取name节点内容
NodeList nameNodeList = emojiElement.getElementsByTagName("name");
if (nameNodeList.getLength() > 0) {
emoji.name = nameNodeList.item(0).getTextContent();
}
// 获取icon节点内容
NodeList iconNodeList = emojiElement.getElementsByTagName("icon");
if (iconNodeList.getLength() > 0) {
emoji.icon = iconNodeList.item(0).getTextContent();
}
emojiList.add(emoji);
}
}
// 关闭输入流
is.close();
} catch (Exception e) {
e.printStackTrace();
}
return emojiList;
}
}3. 解析结果使用
在Activity中调用解析方法即可获取表情列表:
import android.os.Bundle;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import java.util.List;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 解析XML获取表情列表
List<XmlParser.Emoji> emojiList = XmlParser.parseEmojiXml(this);
Toast.makeText(this, "解析到" + emojiList.size() + "个表情", Toast.LENGTH_SHORT).show();
}
}二、实现表情弹出框
表情弹出框通常使用PopupWindow实现,点击触发按钮时弹出,内部展示表情网格,点击表情后回调选择结果。
1. 弹出框布局文件
创建popup_emoji.xml作为弹出框的布局,内部使用GridView展示表情:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:background="@android:color/white">
<GridView
android:id="@+id/gv_emoji"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:numColumns="4"
android:verticalSpacing="10dp"
android:horizontalSpacing="10dp"
android:padding="10dp"
android:gravity="center"/>
</LinearLayout>2. 表情网格适配器
创建适配器绑定表情数据到GridView:
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import java.util.List;
public class EmojiAdapter extends BaseAdapter {
private Context context;
private List<XmlParser.Emoji> emojiList;
private LayoutInflater inflater;
public EmojiAdapter(Context context, List<XmlParser.Emoji> emojiList) {
this.context = context;
this.emojiList = emojiList;
inflater = LayoutInflater.from(context);
}
@Override
public int getCount() {
return emojiList.size();
}
@Override
public Object getItem(int position) {
return emojiList.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
convertView = inflater.inflate(R.layout.item_emoji, parent, false);
holder = new ViewHolder();
holder.ivEmoji = convertView.findViewById(R.id.iv_emoji);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
// 这里假设表情图标放在res/drawable目录下,根据icon名称获取资源id
XmlParser.Emoji emoji = emojiList.get(position);
int resId = context.getResources().getIdentifier(emoji.icon, "drawable", context.getPackageName());
holder.ivEmoji.setImageResource(resId);
return convertView;
}
static class ViewHolder {
ImageView ivEmoji;
}
}对应的单个表情布局item_emoji.xml内容:
<?xml version="1.0" encoding="utf-8"?>
<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/iv_emoji"
android:layout_width="50dp"
android:layout_height="50dp"
android:scaleType="centerInside"/>3. PopupWindow实现逻辑
在Activity中初始化PopupWindow,绑定数据和点击事件:
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.GridView;
import android.widget.PopupWindow;
import androidx.appcompat.app.AppCompatActivity;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private PopupWindow emojiPopup;
private Button btnShowEmoji;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btnShowEmoji = findViewById(R.id.btn_show_emoji);
// 点击按钮弹出表情框
btnShowEmoji.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
showEmojiPopup();
}
});
}
private void showEmojiPopup() {
if (emojiPopup == null) {
// 解析XML获取表情数据
List<XmlParser.Emoji> emojiList = XmlParser.parseEmojiXml(this);
// 加载弹出框布局
View popupView = LayoutInflater.from(this).inflate(R.layout.popup_emoji, null);
GridView gvEmoji = popupView.findViewById(R.id.gv_emoji);
EmojiAdapter adapter = new EmojiAdapter(this, emojiList);
gvEmoji.setAdapter(adapter);
// 设置GridView点击事件
gvEmoji.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
XmlParser.Emoji selectedEmoji = emojiList.get(position);
// 这里可以处理表情选择后的逻辑,比如插入输入框
btnShowEmoji.setText("选择了:" + selectedEmoji.name);
emojiPopup.dismiss();
}
});
// 初始化PopupWindow
emojiPopup = new PopupWindow(popupView, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT, true);
// 设置背景,点击外部可关闭
emojiPopup.setBackgroundDrawable(new ColorDrawable());
// 设置动画
emojiPopup.setAnimationStyle(android.R.style.Animation_InputMethod);
}
// 显示PopupWindow,在按钮下方弹出
emojiPopup.showAsDropDown(btnShowEmoji, 0, 10);
}
}4. 主界面布局
主界面activity_main.xml只需要一个触发按钮:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="20dp"
android:gravity="center_horizontal">
<Button
android:id="@+id/btn_show_emoji"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="显示表情框"/>
</LinearLayout>三、注意事项
- DOM解析会将整个XML加载到内存,如果XML文件过大可能导致内存溢出,此时建议换用SAX或者Pull解析。
- PopupWindow需要设置合理的宽高,同时记得设置背景,否则点击外部可能无法关闭弹出框。
- 表情资源需要提前放到对应的目录下,确保资源名称匹配,避免获取资源id失败。
AndroidDOM解析XML表情弹出框PopupWindow修改时间:2026-06-06 14:30:57