# 自定义消息 以掷骰子为例 首先,先定义一个自定义消息的类型 ```java public interface CustomAttachmentType { // 多端统一 int Guess = 1; int SnapChat = 2; int Sticker = 3; int RTS = 4; int Crops=5;//骰子 } ``` 第二步,定义一个自定义消息附件的基类,负责解析你的自定义消息的公用字段,比如类型等 。 > 注意: 实现 MsgAttachment 接口的成员都要实现 Serializable。 ```java public abstract class CustomAttachment implements MsgAttachment { protected int type; CustomAttachment(int type) { this.type = type; } public void fromJson(JSONObject data) { if (data != null) { parseData(data); } } @Override public String toJson(boolean send) { return CustomAttachParser.packData(type, packData()); } public int getType() { return type; } protected abstract void parseData(JSONObject data); protected abstract JSONObject packData(); } ``` 第三步,继承这个基类,实现“骰子”的附件类型。 > 注意,成员变量都要实现 Serializable。 ```java public class CrapsAttachment extends CustomAttachment{ public enum Craps { one(1, "1"), two(2, "2"), three(3, "3"), four(4,"4"), five(5,"5"), six(6,"6"), ; private int value; private String desc; Craps(int value, String desc) { this.value = value; this.desc = desc; } static Craps enumOfValue(int value) { for (Craps direction : values()){ if (direction.getValue() == value) { return direction; } } return one; } public int getValue() { return value; } public String getDesc() { return desc; } } private Craps value; public CrapsAttachment() { super(CustomAttachmentType.Guess); random(); } @Override protected void parseData(JSONObject data) { value = Craps.enumOfValue(data.getIntValue("value")); } @Override protected JSONObject packData() { JSONObject data = new JSONObject(); data.put("value", value.getValue()); return data; } private void random() { int value = new Random().nextInt(6) + 1; this.value = Craps.enumOfValue(value); } public Craps getValue() { return value; } } ``` 第四步,实现自定义消息的附件解析器。 ```java public class CustomAttachParser implements MsgAttachmentParser { private static final String KEY_TYPE = "type"; private static final String KEY_DATA = "data"; @Override public MsgAttachment parse(String json) { CustomAttachment attachment = null; try { JSONObject object = JSON.parseObject(json); int type = object.getInteger(KEY_TYPE); JSONObject data = object.getJSONObject(KEY_DATA); switch (type) { case CustomAttachmentType.Crops: attachment = new CrapsAttachment(); default: attachment = new DefaultCustomAttachment(); break; } if (attachment != null) { attachment.fromJson(data); } } catch (Exception e) { } return attachment; } public static String packData(int type, JSONObject data) { JSONObject object = new JSONObject(); object.put(KEY_TYPE, type); if (data != null) { object.put(KEY_DATA, data); } return object.toJSONString(); } } ``` 第五步,将自定义消息展示UI上(当然这里显示的文字,如果想要显示成图片,可以参考demo) ```java public class MsgViewHolderCrops extends MsgViewHolderText{ @Override protected String getDisplayText() { //实例化一个attachment CrapsAttachment attachment = (CrapsAttachment)message.getAttachment(); return attachment.getValue().getDesc() + "点!"; } } ``` 第六步,发送自定义消息 ```java public class CrapsAction extends BaseAction{ public CrapsAction(){ super(R.drawable.message_plus_crops_selector, R.string.input_panel_crops); } @Override public void onClick() { CrapsAttachment attachment = new CrapsAttachment(); IMMessage message = MessageBuilder.createCustomMessage( getAccount(), getSessionType(), attachment.getValue().getDesc(), attachment ); sendMessage(message); } } ``` 第七步,将该附件解析器注册到 SDK 中。为了保证生成历史消息时能够正确解析自定义附件,注册一般应放在 Application 的 onCreate 中完成 ```java NIMClient.getService(MsgService.class).registerCustomAttachmentParser(new CustomAttachParser()); ``` 第八步,注册扩展消息类型的显示ViewHolder,由于这里使用我们UIKIT,所以也需要注册到Application的onCreate中 ```java NimUIKit.registerMsgItemViewHolder(CrapsAttachment.class, MsgViewHolderCrops.class); ``` 第九步,添加“骰子”的按钮到“+”号中,Demo是在SessionHelper.java里面,定制的单聊界面。 ```java ArrayList actions = new ArrayList<>(); actions.add(new CrapsAction()); ```