澳门皇冠金沙网站-澳门皇冠844网站

热门关键词: 澳门皇冠金沙网站,澳门皇冠844网站

环信官方Demo源码分析及SDK简单应用,Messages消息

图片 1名片分享.jpg

环信官方Demo源码分析及SDK简单应用

Messages. 291

近来的需求需要对环信进行定制化,实现如图所示的名片分享功能。环信聊天中的每一种消息类型都由一种对应的ChatRow来控制,相当于adapter里的Holder。

环信官方Demo源码分析及SDK简单应用-ChatDemoUI3.0

消息维护... 291

自定义GroupCardChatRow继承EaseChatRow,在 onBubbleClick()中重写消息的点击事件。

环信官方Demo源码分析及SDK简单应用-LoginActivity

00系统消息ID(8占位符). 291

public class GroupCardChatRow extends EaseChatRow { private TextView contentView; private TextView tvGroupName; private ImageView imgGroup; private TextView tvIntroduce; private TextView tvNember; private String gid; public GroupCardChatRow(Context context, EMMessage message, int position, BaseAdapter adapter) { super(context, message, position, adapter); } //接收和发送名片消息的布局 @Override protected void onInflateView() { inflater.inflate(message.direct() == EMMessage.Direct.RECEIVE ? R.layout.ease_row_received_group_card : R.layout.ease_row_sent_group_card, this); } @Override protected void onFindViewById() { contentView =  findViewById(R.id.tv_chatcontent); tvGroupName =  findViewById(R.id.tv_group_name); imgGroup = (ImageView) findViewById(R.id.img_group); tvIntroduce =  findViewById(tv_introduce); tvNember =  findViewById(R.id.tv_number); } @Override public void onSetUpView() { try { Map<String, String> map = new HashMap<>(); map = new Gson().fromJson(message.getStringAttribute(EaseConstant.EXTRA_GROUP_CARD), Map.class); String name = map.get; String description = map.get("description"); String pic = map.get; String memberCount = map.get("member_count"); gid = map.get; tvGroupName.setText; ImageUtil.loadImageWithView(context, pic, imgGroup); tvIntroduce.setText(description); tvNember.setText("群成员人数:"   memberCount   "人"); } catch (HyphenateException e) { e.printStackTrace(); } handleTextMessage(); } protected void handleTextMessage() { if (message.direct() == EMMessage.Direct.SEND) { setMessageSendCallback(); switch (message.status { case CREATE: progressBar.setVisibility(View.GONE); statusView.setVisibility(View.VISIBLE); break; case SUCCESS: progressBar.setVisibility(View.GONE); statusView.setVisibility(View.GONE); break; case FAIL: progressBar.setVisibility(View.GONE); statusView.setVisibility(View.VISIBLE); break; case INPROGRESS: progressBar.setVisibility(View.VISIBLE); statusView.setVisibility(View.GONE); break; default: break; } } else { if (!message.isAcked() && message.getChatType() == ChatType.Chat) { try { EMClient.getInstance().chatManager().ackMessageRead(message.getFrom(), message.getMsgId; } catch (HyphenateException e) { e.printStackTrace(); } } } } @Override protected void onUpdateView() { adapter.notifyDataSetChanged(); } @Override protected void onBubbleClick() { // TODO Auto-generated method stub Intent intent = new Intent(context, GroupCardActivity.class); intent.putExtra("gid", gid); context.startActivity; }}

环信官方Demo源码分析及SDK简单应用-主界面的三个fragment-会话界面

语法规则... 292

环信中消息类型包括txt、音频、位置、文件、图片、视频类型,群名片也属于txt类型,我们通过message的拓展字段来区分消息类型是否为名片。

环信官方Demo源码分析及SDK简单应用-主界面的三个fragment-通讯录界面

使用全局的Message Class. 292

发送群名片消息的时候给message添加群名片拓展字段,发送正常txt消息时不添加拓展字段,在adapter中根据拓展字段是否为空来判断消息类型

环信官方Demo源码分析及SDK简单应用-主界面的三个fragment-设置界面

静态的指定Message. 292

protected void sendMessage(UserPageBean userPageBean) { EMMessage message = EMMessage.createTxtSendMessage("群邀请", userPageBean.getIm_namelogin; message.setAttribute(EaseConstant.EXTRA_GROUP_CARD, groupMessage); EMClient.getInstance().chatManager().sendMessage; }

环信官方Demo源码分析及SDK简单应用-EaseUI

动态的指定Message. 292

在EaseMessageAdapter中新添加两种消息类型MESSAGE_TYPE_SENT_GROUP_CARD 、 MESSAGE_TYPE_RECV_GROUP_CARD

环信官方Demo源码分析及SDK简单应用-IM集成开发详案及具体代码实现

INTO msgtext 、DISPLAY LIKE dtype选项... 293

修改 getItemViewType和createChatRow方法,在其中添加这两种消息类型

EaseUI

直接显示消息常量,不引用消息ID与消息号... 294

public class EaseMessageAdapter extends BaseAdapter { private final static String TAG = "msg"; private Context context; private static final int HANDLER_MESSAGE_REFRESH_LIST = 0; private static final int HANDLER_MESSAGE_SELECT_LAST = 1; private static final int HANDLER_MESSAGE_SEEK_TO = 2; private static final int MESSAGE_TYPE_RECV_TXT = 0; private static final int MESSAGE_TYPE_SENT_TXT = 1; private static final int MESSAGE_TYPE_SENT_IMAGE = 2; private static final int MESSAGE_TYPE_SENT_LOCATION = 3; private static final int MESSAGE_TYPE_RECV_LOCATION = 4; private static final int MESSAGE_TYPE_RECV_IMAGE = 5; private static final int MESSAGE_TYPE_SENT_VOICE = 6; private static final int MESSAGE_TYPE_RECV_VOICE = 7; private static final int MESSAGE_TYPE_SENT_VIDEO = 8; private static final int MESSAGE_TYPE_RECV_VIDEO = 9; private static final int MESSAGE_TYPE_SENT_FILE = 10; private static final int MESSAGE_TYPE_RECV_FILE = 11; private static final int MESSAGE_TYPE_SENT_EXPRESSION = 12; private static final int MESSAGE_TYPE_RECV_EXPRESSION = 13; private static final int MESSAGE_TYPE_SENT_GROUP_CARD = 14; private static final int MESSAGE_TYPE_RECV_GROUP_CARD = 15; public int itemTypeCount; // reference to conversation object in chatsdk private EMConversation conversation; EMMessage[] messages = null; private String toChatUsername; private boolean isTrueName; private boolean isBidTureName; private MessageListItemClickListener itemClickListener; private EaseCustomChatRowProvider customRowProvider; private boolean showUserNick; private boolean showAvatar; private Drawable myBubbleBg; private Drawable otherBuddleBg; private String orderId; private String type; private ListView listView; private boolean isbidded; private boolean isbiddedMessage; public EaseMessageAdapter(Context context, String username, int chatType, ListView listView, boolean isTrueName, String orderId, boolean isBidTureName, String type, boolean isBidded) { this.context = context; this.listView = listView; toChatUsername = username; this.isTrueName = isTrueName; this.orderId = orderId; this.isBidTureName = isBidTureName; this.type = type; this.conversation = EMClient.getInstance().chatManager().getConversation(username, EaseCommonUtils.getConversationType, true); this.isbidded = isBidded; } List<EMMessage> msgs1; Handler handler = new Handler() { private void refreshList() { // you should not call getAllMessages() in UI thread // otherwise there is problem when refreshing UI and there is new message arrive List<EMMessage> msgs = conversation.getAllMessages(); List<String> friendsMessageList = new ArrayList<>(); List<String> orderUnBidMessageList = new ArrayList<>(); List<String> orderBidMessageList = new ArrayList<>(); String msgId; for (int i = 0; i < msgs.size { msgId = msgs.get.getMsgId(); String msgOrderId = null;// try { msgOrderId =  msgs.get.get(EaseConstant.EXTRA_ORDER_ID); isbiddedMessage =  msgs.get.get(EaseConstant.EXTRA_IS_BIDDED);// msgOrderId = msgs.get.getStringAttribute(EaseConstant.EXTRA_ORDER_ID);// } catch (HyphenateException e) {// e.printStackTrace();// } if (msgOrderId == null || msgOrderId.equals { friendsMessageList.add; } else if (msgOrderId.equals { if { if (isbiddedMessage){ orderBidMessageList.add; } }else { if (!isbiddedMessage){ orderUnBidMessageList.add; } } } } if (orderId == null) { msgs1 = conversation.loadMessages(friendsMessageList); } else { if { msgs1 = conversation.loadMessages(orderBidMessageList); }else { msgs1 = conversation.loadMessages(orderUnBidMessageList); } } messages = msgs1.toArray(new EMMessage[msgs1.size; conversation.markAllMessagesAsRead(); notifyDataSetChanged(); } @Override public void handleMessage(android.os.Message message) { switch (message.what) { case HANDLER_MESSAGE_REFRESH_LIST: refreshList(); break; case HANDLER_MESSAGE_SELECT_LAST: if (messages.length > 0) { listView.setSelection(messages.length - 1); } break; case HANDLER_MESSAGE_SEEK_TO: int position = message.arg1; listView.setSelection; break; default: break; } } }; public void refresh() { if (handler.hasMessages(HANDLER_MESSAGE_REFRESH_LIST)) { return; } android.os.Message msg = handler.obtainMessage(HANDLER_MESSAGE_REFRESH_LIST); handler.sendMessage; } /** * refresh and select the last */ public void refreshSelectLast() { final int TIME_DELAY_REFRESH_SELECT_LAST = 100; handler.removeMessages(HANDLER_MESSAGE_REFRESH_LIST); handler.removeMessages(HANDLER_MESSAGE_SELECT_LAST); handler.sendEmptyMessageDelayed(HANDLER_MESSAGE_REFRESH_LIST, TIME_DELAY_REFRESH_SELECT_LAST); handler.sendEmptyMessageDelayed(HANDLER_MESSAGE_SELECT_LAST, TIME_DELAY_REFRESH_SELECT_LAST); } /** * refresh and seek to the position */ public void refreshSeekTo(int position) { handler.sendMessage(handler.obtainMessage(HANDLER_MESSAGE_REFRESH_LIST)); android.os.Message msg = handler.obtainMessage(HANDLER_MESSAGE_SEEK_TO); msg.arg1 = position; handler.sendMessage; } public EMMessage getItem(int position) { if (messages != null && position < messages.length) { return messages[position]; } return null; } public long getItemId(int position) { return position; } /** * get count of messages */ public int getCount() { return messages == null ? 0 : messages.length; } /** * get number of message type, here 14 = (EMMessage.Type) * 2 */ public int getViewTypeCount() { if (customRowProvider != null && customRowProvider.getCustomChatRowTypeCount { return customRowProvider.getCustomChatRowTypeCount()   16; } return 16; } /** * get type of item */ public int getItemViewType(int position) { EMMessage message = getItem; if (message == null) { return -1; } if (customRowProvider != null && customRowProvider.getCustomChatRowType > 0) { return customRowProvider.getCustomChatRowType   13; } if (message.getType() == EMMessage.Type.TXT) { if (message.getBooleanAttribute(EaseConstant.MESSAGE_ATTR_IS_BIG_EXPRESSION, false)) { return message.direct() == EMMessage.Direct.RECEIVE ? MESSAGE_TYPE_RECV_EXPRESSION : MESSAGE_TYPE_SENT_EXPRESSION; } try { if (!TextUtils.isEmpty(message.getStringAttribute(EaseConstant.EXTRA_GROUP_CARD))){ return message.direct() == EMMessage.Direct.RECEIVE ? MESSAGE_TYPE_RECV_GROUP_CARD : MESSAGE_TYPE_SENT_GROUP_CARD; } } catch (HyphenateException e) { e.printStackTrace(); } return message.direct() == EMMessage.Direct.RECEIVE ? MESSAGE_TYPE_RECV_TXT : MESSAGE_TYPE_SENT_TXT; } if (message.getType() == EMMessage.Type.IMAGE) { return message.direct() == EMMessage.Direct.RECEIVE ? MESSAGE_TYPE_RECV_IMAGE : MESSAGE_TYPE_SENT_IMAGE; } if (message.getType() == EMMessage.Type.LOCATION) { return message.direct() == EMMessage.Direct.RECEIVE ? MESSAGE_TYPE_RECV_LOCATION : MESSAGE_TYPE_SENT_LOCATION; } if (message.getType() == EMMessage.Type.VOICE) { return message.direct() == EMMessage.Direct.RECEIVE ? MESSAGE_TYPE_RECV_VOICE : MESSAGE_TYPE_SENT_VOICE; } if (message.getType() == EMMessage.Type.VIDEO) { return message.direct() == EMMessage.Direct.RECEIVE ? MESSAGE_TYPE_RECV_VIDEO : MESSAGE_TYPE_SENT_VIDEO; } if (message.getType() == EMMessage.Type.FILE) { return message.direct() == EMMessage.Direct.RECEIVE ? MESSAGE_TYPE_RECV_FILE : MESSAGE_TYPE_SENT_FILE; } return -1;// invalid } protected EaseChatRow createChatRow(Context context, EMMessage message, int position) { EaseChatRow chatRow = null; if (customRowProvider != null && customRowProvider.getCustomChatRow(message, position, this) != null) { return customRowProvider.getCustomChatRow(message, position, this); } message.ext().put(EaseConstant.EXTRA_IS_TRUENAME, isTrueName); switch (message.getType { case TXT: if (message.getBooleanAttribute(EaseConstant.MESSAGE_ATTR_IS_BIG_EXPRESSION, false)) { chatRow = new EaseChatRowBigExpression(context, message, position, this); } else { try { if (TextUtils.isEmpty(message.getStringAttribute(EaseConstant.EXTRA_GROUP_CARD))) { chatRow = new EaseChatRowText(context, message, position, this); }else { chatRow = new GroupCardChatRow(context, message, position, this); } } catch (HyphenateException e) { e.printStackTrace(); chatRow = new EaseChatRowText(context, message, position, this); } } break; case LOCATION: chatRow = new EaseChatRowLocation(context, message, position, this); break; case FILE: chatRow = new EaseChatRowFile(context, message, position, this); break; case IMAGE: chatRow = new EaseChatRowImage(context, message, position, this); break; case VOICE: chatRow = new EaseChatRowVoice(context, message, position, this); break; case VIDEO: chatRow = new EaseChatRowVideo(context, message, position, this); break; default: break; } return chatRow; } @SuppressLint public View getView(final int position, View convertView, ViewGroup parent) { EMMessage message = getItem; if (convertView == null) { convertView = createChatRow(context, message, position); } //refresh ui with messages ((EaseChatRow) convertView).setUpView(message, position, itemClickListener, isTrueName, isBidTureName, type); return convertView; } public String getToChatUsername() { return toChatUsername; } public void setShowUserNick(boolean showUserNick) { this.showUserNick = showUserNick; } public void setShowAvatar(boolean showAvatar) { this.showAvatar = showAvatar; } public void setMyBubbleBg(Drawable myBubbleBg) { this.myBubbleBg = myBubbleBg; } public void setOtherBuddleBg(Drawable otherBuddleBg) { this.otherBuddleBg = otherBuddleBg; } public void setItemClickListener(MessageListItemClickListener listener) { itemClickListener = listener; } public void setCustomChatRowProvider(EaseCustomChatRowProvider rowProvider) { customRowProvider = rowProvider; } public boolean isShowUserNick() { return showUserNick; } public boolean isShowAvatar() { return showAvatar; } public Drawable getMyBubbleBg() { return myBubbleBg; } public Drawable getOtherBuddleBg() { return otherBuddleBg; }}

实际工作过程中,我们是用不了太多东西的,如果只是集成个im最多用到的就是聊天列表和聊天页面。

RAISING <exc>选项:消息以异常形式抛出(是否以异常形式抛出还要看主调函数是否捕获了)... 294

我们来看重头戏EaseUI这个库。

CALL FUNCTION[error_message]. 296

官方文档

RAISE语句(触发异常)... 297

其实官方的WiKi已经介绍的特别详细了。官方EaseUI文档

Message Types. 299

我们来看Demo

消息显示及处理... 300

// start chat acitivity

非屏幕PAI事件块中... 300

Intent intent = new Intent(getActivity(), ChatActivity.class);

屏幕中(对话屏幕)... 303

if(conversation.isGroup()){

选择屏幕中... 306

if(conversation.getType() == EMConversationType.ChatRoom){

在List输出列表事件中... 309

// it's group chat

Messages in Function Modules and Methods. 312

intent.putExtra(Constant.EXTRA_CHAT_TYPE, Constant.CHATTYPE_CHATROOM);

Messsage的普通使用... 312

}else{

Messsage转异常(…RAISING选项)... 312

intent.putExtra(Constant.EXTRA_CHAT_TYPE, Constant.CHATTYPE_GROUP);

捕获Message(error_message)... 313

}

DEMO_MESSAGES程序(SAP自带的各种情况下的Message测试)... 313

}

在状态栏中显示信息... 322

// it's single chat

“E”消息与回退按扭... 322

intent.putExtra(Constant.EXTRA_USER_ID, username);

确认框函数POPUP_TO_CONFIRM

startActivity(intent);

Messages

ChatActivity

消息维护

所有的消息都是存储在T100表里的,可以使用S**E9**1事务码来维护:

图片 2

我们来看看ChatActivity

00系统消息ID(8占位符)

MESSAGE e001(00) WITH 'No local currecny maintained for company:' p_bukrs.

上面的00为系统预定义的消息类,如下:

图片 3

从上面可以看出,001这条消息可以传递8个参数。

package com.hyphenate.chatuidemo.ui;

语法规则

使用全局的Message Class

以下程序定义语句后面可以加上选项:...MESSAGE-ID<id>.

图片 4

这样在这些类型的的程序里可以这样来使用MESSAGE语句:

MESSAGE<t><num>[WITH<f1>... <f4>][RAISING<exc>].

REPORT zjzj_test1 MESSAGE-ID

  1. MESSAGE s002.

import android.content.Intent;

静态的指定Message

MESSAGE   <t><nnn>(<id>)  [WITH<f1>... <f4>][RAISING<exc>].

MESSAGE s002(00).

这里在语句中指定了消息ID,如果程序开头指定了消息Class,则这里也会将它覆盖,使用此语句中的消息ID。

import android.os.Bundle;

动态的指定Message

MESSAGE ID    <id>         TYPE       <t>           NUMBER           <n>                      [WITH<f1>...<f4>]   [RAISING<exc>].

DATA: t(1) VALUE 'S',
      id(2) VALUE '00',
      num(3) VALUE '002'.
MESSAGE ID id TYPE t NUMBER num.

import android.support.annotation.NonNull;

INTO msgtext 、DISPLAY LIKE dtype选项

这两个选项对于以上3个(使用全局的Message Class、静态的指定Message、动态的指定Message)都有效。

 

使用MESSAGE … INTO…可以很方便拼接BDC执行返回结果:

data: gt_messtab type table of bdcmsgcoll with header line .

call transaction  'VA02' using bdcdata
                       MODE   'A'*
                       mode   p_runtp
                       update 'S'
                       messages into gt_messtab.

  loop at gt_messtab .
    message id gt_messtab-msgid type gt_messtab-msgtyp number gt_messtab-msgnr
                   with gt_messtab-msgv1
                   gt_messtab-msgv2
                   gt_messtab-msgv3
                   gt_messtab-msgv4
                   into l_msg.
  endloop.

DATA mtext TYPE string.

CALL FUNCTION ... EXCEPTIONS error_message = 4.
IF sy-subrc = 4.
  MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
          INTO msgtext
          WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
ENDIF.

 

INTO msgtext选项与Message Type没有关系(不管是什么类型,即使是X类型,也会将消息存入到msgtext变量中),这不像RAISING选项。

 

DISPLAY LIKE dtype:

对于原先就以dialog box方式显示的消息,仍然还是显示在dialog box中。

如果dtype为A或者是I类型时,E、W类型的消息(除开PBO与LOAD-OF-PROGRAM)将会在dialog box中显示。

不管dtype类型为什么,S类型的消息都会显示在状态栏中,PBO与LOAD-OF-PROGRAM中的I类型消息也是这样。

X类型消息总会引起运行时错误。

注:此种方式不会影响到消息本身的性为处理,只是改变了消息的显示类型(图标),如下面只是改变了S类型消息在状态栏中以错误图标来显示:

 MESSAGE  msg  TYPE 'S' DISPLAY LIKE 'E'.

import com.hyphenate.chatuidemo.R;

直接显示消息常量,不引用消息ID与消息号

MESSAGE msgtext TYPE c

MESSAGE 'aaaa' TYPE 'S'.

import com.hyphenate.chatuidemo.runtimepermissions.PermissionsManager;

选项">RAISING <exc>选项:消息以异常形式抛出(是否以异常形式抛出还要看主调函数是否捕获了)

该选项对于以上4个(使用全局的Message Class、静态的指定Message、动态的指定Message、直接显示消息常量)都有效。

  MESSAGE ID 'SABAPDEMOS' TYPE MESSAGE_TYPE NUMBER '777'
          WITH MESSAGE_TYPE MESSAGE_PLACE MESSAGE_EVENT
  RAISING MESS.

RAISING 后面接的是异常名(如下面的MESS异常),只有在Function或Class中定义的异常,才能用在RAISING选项的后面,具体使用过程如下:

图片 5

图片 6

图片 7

当使用该选项后,并且如果在调用的地方(CALL FUNCTION或者是 CALL METHOD的地方)使用了EXCEPTION选项来捕获RAISING抛出的异常,则不再以MESSAGE的原有形式来显示消息,而是被主调捕获后进一步处理或者是程序Dump(AEIWS类型都能被捕获到,但X类型的Message不会走到被主调者捕获这一步,因为在被调程序中就宕掉了);反过来,当主调者未使用EXCEPTION选项(或者使用了但未捕获到所抛出的异常),则RAISING选项会被忽略,MESSAGE语句会按照无RAISING选项时那样运行(弹框还是在状态栏中显示、以及程序是否终止等性为)。

下面程序中,第一次调用时中会弹出消息框(因为没有使用EXCEPTIONS选项捕获),而第二次不会弹出消息框,也不会在状态栏中显示,而是被后继程序捕获后输出:

CLASS c1 DEFINITION.
  PUBLIC SECTION.
    CLASS-METHODS m1 EXCEPTIONS exc1.
ENDCLASS.
CLASS c1 IMPLEMENTATION.
  METHOD m1.
    MESSAGE 'Message in a Method' TYPE 'I' RAISING exc1.
  ENDMETHOD.
ENDCLASS.

START-OF-SELECTION.
c1=>m1( ).
c1=>m1( EXCEPTIONS exc1 = 4 ).
IF sy-subrc = 4.
  write: / '被捕获'.
ENDIF.

 

下面也不会显示错误消息,因E类型消息(注:不是异常,是消息)被error_message所捕获了:

FUNCTION ZJZJ_FUNC1.
 MESSAGE id '00'  TYPE 'E' NUMBER 001 WITH '1' '2'.
ENDFUNCTION.

REPORT  ZJZJTEST.
CALL FUNCTION 'ZJZJ_FUNC1'
  EXCEPTIONS
    error_message = 4.
if sy-subrc <> 0.
  WRITE: / '被捕获'.
ENDIF.

 

 

RAISING异常后,与消息相关的信息分别存储到相应系统字段中:
SY-MSGID 消息类
SY-MSGNO消息号
SY-MSGTY 消息类型
SY-MSGV1 ... SY-MSGV4 消息参数

CLASS c1 DEFINITION.
  PUBLIC SECTION.
    CLASS-METHODS m1 EXCEPTIONS exc1.
ENDCLASS.
CLASS c1 IMPLEMENTATION.
  METHOD m1.
    MESSAGE id '00'  TYPE 'I' NUMBER 001 WITH '1' '2' RAISING exc1.
  ENDMETHOD.
ENDCLASS.

START-OF-SELECTION.
  c1=>m1( EXCEPTIONS exc1 = 4 ).
  IF sy-subrc = 4.
    write: / SY-MSGID.
    write: / SY-MSGNO.
    write: / SY-MSGTY.
    write: / SY-MSGV1.
    write: / SY-MSGV2.
  ENDIF.

00
001
I
1
2

import com.hyphenate.easeui.ui.EaseChatFragment;

CALL FUNCTION[error_message]

CALL FUNCTION func ...[EXCEPTIONS[exc1= n1    exc2= n2 ...]
[others= n_others] ].
[error_message** **= n_error]

exc1,exc2...与OTHERS异常只能捕获到MESSAGE...RAISING选项或RAISE语句抛出的异常,即MESSAGE...RAISING与RAISE抛出的异常只能被exc1,exc2...与OTHERS异常所捕获,而error_message是无法捕获MESSAGE...RAISING与RAISE抛出的异常的。

error_message为系统内置的隐式性异常,主用来捕获那些未使用RAISING选项的A、E两类消息(注:error_message的作用是用来捕获消息的,而不是针对MESSAGE...RAISING与RAISE抛出的异常)

在主调程序中使用error_message来捕获Message请参考:在主调程序中捕获Message

MESSAGE中的RAISING<exc1...exci>抛出异常时,如果在Call Function的Exception列表中有exc1...exci或others异常,则会优先被exc1...exci或others捕获到;否则RAISING选项将直接被忽略掉,MESSAGE会被error_message所捕获(前提是在CALL FUNCTION时,加上了error_message异常,且不管MESAGGE为任何类型,此时都不会再显示MESSAGE,具体请参考在主调程序中捕获Message中的1、2两点说明):

图片 8

REPORT  ZJZJTEST.
CALL FUNCTION 'ZJZJ_FUNC1'
  EXCEPTIONS
    ERROR_MESSAGE = 5
    "如果注释掉下面E类型异常捕获列表,则会输出2**
    "**否则,像这里就会输出1
        E = 4
       D = 6.
if sy-subrc = 4.
  WRITE: / '1'.
ENDIF.
if sy-subrc = 5.
  WRITE: / '2'.
ENDIF.

import com.hyphenate.util.EasyUtils;

RAISE语句(触发异常)

在Function Module里有两种方式触发异常(注:下面二种也只能在Function Module使用):

l  RAISE <except>.

l  MESSAGE..... RAISING <except>.

这些语句的作用依赖于主调程序中是否处理<except>异常。如果异常<except>或者others出现在了CALL FUNCTION语句中的EXCEPTIONS选项中,<except>异常将会被主调程序所捕获。如果主调程序没有捕获<except>异常,则:

l  RAISE 语句会终止程序并且切换到debug模式

l  MESSAGE ..... RAISING语句会根据message type来像MESSAGE语句那样正常显示消息(前提条件是要在CALL FUNCTION 语句中使用error_message来捕获消息)

一旦主调程序捕获了异常,以上两种触发异常的方式都会返回到主调程序,并且不会返回值(Function Module参数输出)。MESSAGE ..... RAISING语句也不会再显示消息,而是将相关的信息填充到SY-MSGID, SY-MSGTY,SY-MSGNO, and SY-MSGV1 to SY-MSGV4这些系统变量中(即使是I,S,W三种消息类型也会设置这些系统变量)

 

RAISE [RESUMABLE] EXCEPTION **{ { TYPE cx_class [EXPORTING p1 = a1 p2 = a2 ...]} | oref }**.

cx_class为异常Class,EXPORTING为构造此异常类的构造参数,oref可以是已存在的异常Class引用,如:

DATA oref TYPE REF TO cx_root.
DATA:text TYPE string , result TYPE i.
TRY .
    TRY.
        result = 1 / 0.
      CATCH cx_sy_zerodivide INTO oref.
        text = oref->get_text( ).
        RAISE EXCEPTION oref."捕获后继续向外层抛出在函数里不需Exception选项,请参考下面示例(可能抛出是non-class-based exceptions,而不是class-based exceptions吧?
    ENDTRY.
  CATCH cx_root INTO oref.
    text = oref->get_text( ).
    WRITE: / text.
ENDTRY.

RAISE EXCEPTION语句一般用来抛出基于Class的异常类class-based exceptions,而RAISE一般是直接用来抛出 non-class-based exceptions,如:

图片 9

FUNCTION ZJZJ_FUNC1.
  RAISE e.
ENDFUNCTION.

 

REPORT  ZJZJTEST.
CALL FUNCTION 'ZJZJ_FUNC1'
  EXCEPTIONS
    OTHERS = 4.
if sy-subrc = 4.
  WRITE: / '1'.
ENDIF.

 

RESUMABLE选项

表示可恢复的异常,可以在CATCH块里使用RESUME语句直接跳到抛出异常语句后面继续执行,RESUME后面语句不再被执,CLEANUP块也不会被执行。该选项只能用于BEFORE UNWIND类型的CATCH块中:

DATA oref TYPE REF TO cx_root.
DATA text TYPE string.
DATA i TYPE i.
TRY .
    RAISE RESUMABLE EXCEPTION TYPE cx_demo_constructor
      EXPORTING
        my_text = sy-repid.
    i = i 1.
    WRITE: / i.
CATCH BEFORE UNWIND cx_demo_constructor INTO oref .
    text = oref->get_text( ).
    IF i < 1.
      RESUME.
    ENDIF.
    WRITE:/ '--'.
ENDTRY.

结果只输出 1

 

Message Types

 

 

X

Exit

退出

Nomessageis displayed,andtheprogramterminateswitha shortdump. Programterminationswithashortdumpnormallyonlyoccurwhena runtimeerroroccurs.MessagetypeX allowsyoutoforceaprogram termination.TheshortdumpcontainsthemessageID.

消息不会显示,程序会终止并伴随着shortdump.信息。程序终止一般是由于运行时错误,但X消息允许你强迫终止程序。运行时会产生错误,屏幕显示异常的堆栈信息

 

A

Abend

终止

Themessageappearsinadialogbox,andtheprogramterminates.Whentheuserhasconfirmedthemessage,controlreturnstothenext- highestareamenu.

此种消息只能以模式对话框来显示,并且会终止当应用程序。当用户确认后,控制权返回到最高层区域菜单所在屏幕,即“SAP Easy Access”初始屏幕:程序被取消

 

E

Error

错误

Depending ontheprogram context, an errordialogappearsorthe programterminates.

依赖于程序上下文(可能显示在对话框中或状态栏上),显示错误对话框或者是终止程序(工具条按钮变灰,但不会中转到SAP Easy Access屏幕)

 

W

Warning

警告

Depending ontheprogram context, an errordialogappearsorthe programterminates.

依赖于程序上下文(可能显示在对话框中或状态栏上),显示错误对话框或者是终止程序(工具条按钮变灰,但不会中转到SAP Easy Access屏幕)

 

I

Information

消息

Themessageappearsinadialogbox.Oncetheuserhasconfirmedthemessage,theprogramcontinuesimmediatelyaftertheMESSAGE statement.

此种类型的消息只会出现在显示在对话框中。一旦用户确认了对话框,程序将继续执行MESSAGE语句后面的语句

 

S

Status

状态

TheprogramcontinuesnormallyaftertheMESSAGEstatement,andthemessageisdisplayedinthestatusbarof thenextscreen.

程序会继续执行MESSAGE后面的语句,并且消息将显示在下一屏幕的状态栏中(如果没有下一屏幕,则显示在本屏幕的状态栏中)。程序不会被中断

/**

消息显示及处理

Messages可以以模式对话框或者在屏幕的状态栏中显示,这究竟如何显示,则依赖限Messages的类型与运行时MESSAGE语句所在上下文环境。

特别是是E 与 W类型的消息,它们的行为与所在的程序上下文相关。

* chat activity,EaseChatFragment was used {@link #EaseChatFragment}

非屏幕PAI事件块中

适用所有不属于任何屏幕处理事件块。非屏幕处理包括以下事件块:

n  PB**O**(PBO of screens):对话屏幕的PBO块

n  The selection screen event AT SELECTION-SCREEN OUTPUT(PBO of a selection screen)选择屏幕的PBO块

n  报表程序事件块:INITIALIZATIONSTART-OF-SELECTION、GET、END-O**F-SELECTION**

n  列表事件块TOP-OF-PAGEEND-O**F-PAGE**

 

另:此节具体的各种情况下的演示,还可以通过 DEMO_MESSAGES程序(SAP自带的各种情况下的Message测试)此节的程序来演示

类型

Display显示

(显示在对话框中还是状态栏中)

Processing处理(是终止程序还是继续,以及终止时返回到哪里)(注:显示及处理是不一样的)

X

None

不显示信息

Triggers a runtime error with short dump

触发运行时错误并伴随着dump

A

Dialogbox以对话框形式显示:

Programterminates,andcontrolreturnstolastarea menu

并且会终止当应用程序,控制权返回到“SAP Easy Access”初始屏幕

E

In PBO context,the same as type A, otherwise statusbar

在PBO块里与A类型相同(指显示方式相同,即以对话框形式显示):

否则(指那些上面除PBO以外的事件块——INITIALIZATION、START-OF-SELECTION、GET、END-OF-SELECTION、TOP-OF-PAGE、END-OF-PAGE)显示在状态栏中(此种情况贴图在右边)。

In PBO context like type A,

otherwise,program terminates and control returns to pointfrom which the program was called

在PBO块里与A类型消息相同(指处理方式相同,即退出应用程序,并跳转到欢迎屏幕);否则,程序终止,但控制权返回到该程序被调用的地方(指界面停留在运行前的地方):

W

In PBO context,thes a meas type S, otherwise statusbar

在PBO里与S类型相同:

否则显示在状态栏中(此种情况贴图在右边)。

In PBO context like type S,otherwise,program terminates andcontrol returns to point from which the program was called

在PBO中与S类型相同

否则,程序终止,并且控制权返回到程序被调用的地方(指界面停留在调用前的地方):

I

In PBO context,thes a meas type S,otherwise dialogbox

在PBO里与S类型相同:

否则以对话框的形式显示(此种情况贴图在右边)。

Program continues processing after the MESSAGE

Statement

程序会继续向下执行

S

Status bar of next screen

消息会显示在下一屏幕的状态栏中(前提是有下一屏幕):

如果没有下一屏幕,则显示在当前屏幕的状态栏中(此种情况贴图在右边)。

Program continues processing after the MESSAGE Statement

程序会继续向下执行

 

 

 

 

 

 

 

 

 

 

 

*

屏幕中(对话屏幕)

会影响用户的的输入性为。屏幕处理即所有的PAI modules

另:此节具体的各种情况下的演示,还可以通过 DEMO_MESSAGES程序(SAP自带的各种情况下的Message测试)此节的程序来演示

类型

Display显示

(显示在对话框中还是状态栏中)

Processing处理

(是终止程序还是继续,以及终止时返回到哪里)

X

None

不会显示消息

Triggers a runtime error with short dump

触发运行时错误并伴随着dump

A

Dialog box以对话框显示

Program terminates, and control returns to last area menu

并且会终止当应用程序,控制权返回到欢迎屏幕

E

Status bar在状态栏中显示

PAI processing is terminated, and control returns to the

current screen. All of the screen fields for which there is a

FIELD or CHAIN statement are ready for input. The user

must enter a new value. The system then restarts PAI

processing for the screen using the new values. Error

messages are not possible in POH or POV processing.

Instead, a runtime error occurs.

PAI处理结束,并且控制权返回到当前屏幕。MESSAGE所在的Module所属的FIELD或CHAIN所对应的字段全部可以重新输入(其他不在FIELD与CHAIN中的字段会灰掉,以及即使在其他FIELD或其他CHAIN中的字段如果通过验证了的也会灰掉。变灰就意味着验证已通过,无需才输入),且用户必须重新输入新的值。然后系统将重新对新输入的值进行PAI处理。注:Error消息将不能用在POH与POV,否则将会发生运行时错误

W

Statusbar

在状态栏中显示

Like type E, but the user can confirm the message by

pressing ENTER without having to enter new values. The

system then resumes PAI processing directly after the

MESSAGE statement. Warning messages are not possible

in POH or POV processing. Instead, a runtime error occurs.

像类型E一样(指出弹出警告消息后,哪些屏幕字段变灰,哪些需要重新输入,这些处理相同)。但用户可以在不必输入新的值情况下按回车键继来忽略警告消息,系统会继续后面的PAI处理。

注:Warning消息将不能用在POH与POV,否则将会发生运行时错误

I

Dialog box对话框中显示

Program continues processing after the MESSAGEStatement

程序会继续向下执行

S

Status bar of next screen

消息会显示在下一屏幕的状态栏中

Program continues processing after the MESSAGEStatement

程序会继续向下执行

*/

选择屏幕中

包括AT SELECTION-SCREEN及所有带ON选项的AT SELECTION-SCREEN,但不包括AT SELECTION-SCREEN OUTPUT,具体有哪些事件请参考这里

另:此节具体的各种情况下的演示,还可以通过 DEMO_MESSAGES程序(SAP自带的各种情况下的Message测试)此节的程序来演示

类型pe

Display显示

(显示在对话框中还是状态栏中)

Processing处理

(是终止程序还是继续,以及终止时返回到哪里)

A

Dialogbox以对话框显示

Program terminates, and control returns to last area menu

并且会终止当应用程序,控制权返回到欢迎屏幕

E

Statusbar

在状态栏中显示

Selection screen processing terminates, and the selection

screen is redisplayed. The screen fields specified through

the additions to the AT SELECTION-SCREEN statement

are ready for input. The user mustenter a new value. The

system then restarts the selection screen processing using

the new values. You cannot use error messages with the

ON HELP-REQUEST or ON VALUE-REQUEST additions.

Instead, a runtime error occurs.

选择屏幕处理结束,并且控制权返回到选择屏幕重新显示。

AT SELECTION-SCREEN ON中的字段将可以重新输出(如果是发生在AT SELECTION-SCREEN里,则所有屏幕字段都是可以重新输入的),并且用户必须输入新的值,系统然后重新对新输入的值进行处理,如果验证通过(不再弹出错误消息),则是继续后面的屏幕事件处理。

不能将error消息与ON HELP-REQUEST or ON VALUE-REQUEST选项的AT SELECTION-SCREEN一起使用,否则出现运行时错误

W

Statusbar

在状态栏中显示

Like type E, but the user can confirm the message by

pressing ENTER without having to enter new values. The

system then resumes selection screen processing directly

after the MESSAGE statement. You cannot use warning

messages with the ON HELP-REQUEST or ON VALUEREQUEST

additions. Instead, a runtime error occurs.

像类型E一样(指出弹出警告消息后,哪些屏幕字段变灰,哪些需要重新输入,这些处理相同)。但用户可以在不必输入新的值情况下按回车键继来忽略警告消息,系统会继续后面的PAI处理。

注:不能将warning消息与ON HELP-REQUEST or ON VALUE-REQUEST选项的AT SELECTION-SCREEN一起使用,否则出现运行时错误

I

Dialogbox

对话框中显示

Program continues processing after the MESSAGEStatement

程序会继续向下执行

S

Statusbarof nextscreen

消息会显示在下一屏幕的状态栏中

Program continues processing after the MESSAGEStatement

程序会继续向下执行

X

None

不会显示消息

Triggers a runtime error with short dump

触发运行时错误并伴随着dump

public class ChatActivity extends BaseActivity{

在List输出列表事件中

适用于所有列表处理list is being processed。

2  AT LINE-SELECTION

2  AT USER-COMMAND

2  AT PF<nn>

2  TOP-OF-PAGE DURING LINE-SELECTION

另:此节具体的各种情况下的演示,还可以通过 DEMO_MESSAGES程序(SAP自带的各种情况下的Message测试)此节的程序来演示

类型

Display显示(显示在对话框中还是状态栏中)

Processing处理(是终止程序还是继续,以及终止时返回到哪里)

A

Dialogbox以对话框显示

Program terminates, and control returns to last area menu

并且会终止当应用程序,控制权返回到欢迎屏幕

E

Statusbar在状态栏中显示

Processing block terminates. Previous list levels remaindisplayed.

事件块处理终止,继续保留上一级别的List

I

Dialogbox对话框中显示

Program continues processing after the MESSAGEStatement

程序会继续向下执行

S

Status bar of next screen

消息会显示在下一屏幕的状态栏中

Program continues processing after the MESSAGEstatement

程序会继续向下执行

W

Statusbar在状态栏中显示

Like type E.

像类型E一样

X

None

不会显示消息

Triggers a runtime error with short dump

触发运行时错误并伴随着dump

public static ChatActivity activityInstance;

Messages in Function Modules and Methods

Message在Funcion与Method中有下面两种不同的功能:Messsage的普通使用、使用Messsage触发异常

此节具体的各种情况下的演示,还可以通过 DEMO_MESSAGES程序(SAP自带的各种情况下的Message测试)此节的程序来演示

private EaseChatFragment chatFragment;

Messsage的普通使用

如果你在Message词句中未使用RAISING选项,则它就是一个普通的Message,是不能被调用者所捕获的,此时Message将会根据上下文来进行显示与处理

String toChatUsername;

Messsage转异常(…RAISING选项)

如果加了选项RAISING时:MESSAGE... RAISING <exc>,此时的Message 的处理方式与是否显示,就要依赖于主调者在调用时,是否加上了exception <exc>选项:

1、如果调用时没有带exception <exc>选项,此时Message语包中的RAISING <exc>选项抛出的异常将会被忽略,Message语句会当作正常消息来处理

2、如果调用时加上了exception <exc>选项对exc 异常进行了捕获,则不会再显示消息(但如果即使加上了exception选项,但没有捕获到exc异常,则此时会忽略RAISING选项)。只要异常被捕获,相关消息内容将会入存入到SY-MSGID,SY-MSGTY, SY-MSGNO, and SY-MSGV1 to SY-MSGV4有关系统变量中。

捕获Message(error_message)

可以在Message语句没有使用RAISING选项的情况下,在主调程序中的Exception参数列表中使用隐式异常error_message选项来捕获Message,但error_message是否能捕获得到Message,与消息类型相关:

1、对于W、I、S类型的消息,将不显示消息(本来是要显示的),也不会去设置 sy-subrc = n_error此时还是会将消息的相关信息存储到SY-MSGID, SYMSGTY,SY-MSGNO, and SY-MSGV1 to SY-MSGV4这些系统变量中

2、对于A、E类型消息,也将不显示提示消息,但会抛出ERROR_MESSAGE异常,即这两类型的消息会自动被转换为error_message异常抛出,并终最被CALL FUNCTION 中Exception异常列表中的error_message异常所捕获,并设置sy-subrc = n_error。此时与消息相关的信息分别存储到相应系统字段中:
SY-MSGID 消息类
SY-MSGNO 消息号
SY-MSGTY 消息类型
SY-MSGV1 ... SY-MSGV4 消息参数

此时,对于A类型消息而言,ROLLBACK WORK语句将会隐式执行

3、对于X类型消息将会抛出runtime error,并且程序会dump

CALL FUNCTION[error_message]

@Override

DEMO_MESSAGES程序(SAP自带的各种情况下的Message测试)

关于Message不同上下文环境的运行情况,请参数SAP自带的实例程序:DEMO_MESSAGES

下面的程序是从DEMO_MESSAGES拷贝过来,并进行了少量修改,可以对不同情况下,Message的运行情况测试。如果需运行此程序,请先从DEMO_MESSAGES拷贝一份,生成必要的屏幕,再将下面的代码贴入。

图片 10

图片 11图片 12

图片 13图片 14

图片 15图片 16

REPORT zjzj_demo_messages.
DATA: ok_code TYPE sy-ucomm,"用来接收对话屏幕传递过来的 Function Code
      save_ok TYPE sy-ucomm,"ok_code的副本,使用副本的原因请参考这里
      BEGIN OF place,"消息执行所在程序类型复选框
        report(1) TYPE c,
        function(1) TYPE c,
        list(1) TYPE c,
        selscreen(1) TYPE c,
        dynpro(1) TYPE c,
      END OF place,
      BEGIN OF type,"消息的类型复选框
        a(1) TYPE c,
        e(1) TYPE c,
        i(1) TYPE c,
        s(1) TYPE c,
        w(1) TYPE c,
        x(1) TYPE c,
      END OF type,
      BEGIN OF event,"屏幕事件类型复选框
        pai(1) TYPE c,
        pbo(1) TYPE c,
      END OF event,
      BEGIN OF except,"异常抛出、消息捕获复选框
        no(1) TYPE c,
        yes(1) TYPE c,
        catch(1) TYPE c,
        nocatch(1) TYPE c,
      END OF except,
      message_type(1) TYPE c,
      message_place(40) TYPE c,
      message_event(20) TYPE c.
DATA:msg TYPE string.

"此选择屏幕供后面对话屏幕的Module来调用
SELECTION-SCREEN BEGIN OF SCREEN 1100.
   PARAMETERS: input1(10) TYPE c,
            input2(10) TYPE c.
   SELECTION-SCREEN SKIP.
   SELECTION-SCREEN BEGIN OF LINE.
      SELECTION-SCREEN COMMENT 1(33) text-001.
      PARAMETERS  funct AS CHECKBOX.
      SELECTION-SCREEN COMMENT 38(64) text-015.
   SELECTION-SCREEN END OF LINE.
SELECTION-SCREEN END OF SCREEN 1100.

START-OF-SELECTION.
  "为对话屏幕上相应字段设置默认值
  place-report = 'X'.
  type-i = 'X'.
  "event-pai = 'X'.
  except-no = 'X'.
  "将CALL SCREEN 100放在死循环里的调用的效果是:由于100是这里的主屏幕(第一个屏幕)
  "后续其他的屏幕都是由此屏幕来调用(CALL SELECTION-SCREEN 1100、CALL SCREEN 300)新
  "产生的或者是跳转得到的(LEVE TO 200)。如果在Module user_command_0100中是通过 LEVE TO 200
  "跳转到200对话屏幕的,则在200屏幕上的标准工具栏中点击了 Back 或者 Exit 按钮后,则
  "主屏幕(100)所在的屏幕序列会结束(因为LEVE TO 200就是在主屏幕序列中,所以在200
  "屏幕中的 LEAVE TO SCREEN 0 最终会结束掉主屏幕所在的屏幕序列),当屏幕序列结事时,序列中的
  "所有屏幕也会随之关闭,并返回到被关闭序列所产生之外,即CALL SCREEN 100调用处,此时会继续执行
  "CALL SCREEN 100的后续语句,如果果此时不再调用其他屏幕,则整个程序会结束(最终的界面会停留在
  "ABAP编辑器上——在通过ABAP编辑运行此程序的情况下),所以为了后继其他情况的Message 测试
  "将 CALL SCREEN 100语句的调用就放在了循环中;另一种情况是,如果在Module user_command_0100中是通过
  "CALL SELECTION-SCREEN 1100或CALL SCREEN 300调用产生的新序列屏幕,则在选择屏幕1100或对话
  "屏幕300所在的屏幕序列结束时(可点击选择屏幕1100标准工具栏中的Back按钮,或在屏幕逻辑流中使用
  "LEAVE TO SCREEN 0语句时会结束屏幕序列),不会返回到 CALL SCREEN 100 语句后面的后续语句继续执行,
  "而是停留在以前已经显示出来的主调屏幕100(会调用100屏幕的PBO,重新显示100屏幕),所以此种情况
  "下可以省略这个Do...While循环
  DO.
    CALL SCREEN 100."全屏方式调用对话屏幕100
    IF place-report = 'X'.
      message_event = 'START-OF-SELECTION'.
      message_place = 'in main program'.
      PERFORM call_message.
    ELSEIF place-function = 'X'.
      message_event = 'START-OF-SELECTION'.
      message_place = 'in function module from main program'.
      PERFORM call_function.
    ENDIF.
  ENDDO.

************************************************************************
* Dialog Modules                                                       *
************************************************************************
MODULE status_0100 OUTPUT.
  "在这里控制复制框是否可选(禁止输入)
  IF place-report = 'X' OR  place-function = 'X' OR  place-list = 'X' .
    PERFORM modi_screnn USING '' '0' '' '0'.
  ENDIF.
  IF  place-dynpro = 'X' OR place-selscreen = 'X'.
    PERFORM modi_screnn USING 'X' '0' '' '1'.
  ENDIF.

  SET PF-STATUS 'SCREEN_100'.
  SET TITLEBAR 'TITL_100'.
ENDMODULE.                    "status_0100 OUTPUT

MODULE cancel INPUT.
  LEAVE PROGRAM.
ENDMODULE.                    "cancel INPUT

MODULE user_command_0100 INPUT.
  save_ok = ok_code.
  CLEAR ok_code.
  "将100屏幕上用户选中的消息转换成真实的消息类型
  PERFORM convert_user_input.
  CASE save_ok.
    WHEN 'TEST'.
      "如果选择的是在 主调程序中 或者是在 Function 执行Message
      IF place-report = 'X' OR place-function = 'X'.
        LEAVE TO SCREEN 0."结束当前屏幕序列,返回到主调程序的CALL SCREEN后继续执行
        "如果选择是在对话屏幕中执行Message,则结束当前屏幕100,调转到200屏幕(不会产生
        "新的屏幕序列)
      ELSEIF place-dynpro = 'X'.
        LEAVE TO SCREEN

  1.         "如果选择是在选择屏幕中执行Message,则会产生一个新的屏幕序列,跳转1100选择屏幕
          ELSEIF place-selscreen = 'X'.
            "下面是原程序采用CALL方式来调用1100选择屏幕的,但这种方式会产生一个新的屏幕
            "序列,结束1100选择屏幕所有的新屏幕序列后,原主调屏幕100所在的屏幕序列不会消失
            ",所以这种方式下,主调程序中的 CALL SCREEN 100 所在的Do...While就没有意义了
            "且点击标准工具栏上的 Back 按钮时,该选择屏幕所在的屏幕序列会结束,返回到 100 屏幕
            CALL SELECTION-SCREEN
  2.         "在这里不能使用下面方式代替上面的CALL SELECTION-SCREEN 1100,否则在第二次调用此语句时
            "会出错,具体问题不清
            "LEAVE TO SCREEN
  3.         "如果选择是在输出列表List中执行Message,则跳转到 300屏幕,也不会产生新的屏幕序列
          ELSEIF place-list = 'X'."如果要求Messge在输出列表List中调用时
            "会产生新的屏幕序列,如果此地方运行50次,则最后因为屏幕序列大于50而堆栈溢出,
            "因为每次运行此语句时,都会产生一个新的屏幕序列,且在离开300屏幕所在
            "的序列时,并未关掉屏幕序列(status_0300 PBO中设置返回到100屏幕)。但上面的
            "CALL SELECTION-SCREEN 1100 不会有这样的问题,因为在按1100所在屏幕的标准工具栏上
            "的Back按钮时,会结束1100所在的屏幕序列。所以这里最好修改成 LEAVE TO SCREEN 300
            "这样在多次调用此处后不会因为产生了50个序列而溢出
            CALL SCREEN
  4.         "LEAVE TO SCREEN
  5.       ENDIF.
        WHEN 'FC_PLC'."FC_PLC为屏幕上的单先按钮的Function code
          "不要在这里控制屏幕字段的可输入性(比如这里点 Main Program单选按钮后,
          "要使屏幕上的 PBO与PAI两个复选框变灰),即不要在这里对SCREEN内表进行修改
          "而是将修改的代码直接移到PBO事件块里。因为在这里即使你修改了SCRENN内表的
          "值,但在该PAI执行完后,去执行PBO时,SCREEN内表的值又会回到屏幕设计时设定的
          "的初始设置了,所以在这里直接修改SCREEN是无法将屏幕字段置为灰的,除非在这里
          "将这些修改设置存储起来,再在PBO根据这些值来修改SCREEN内表,但这样显得麻烦,
          "还不如直接在PBO中对SCREEN进行修改
        WHEN OTHERS.
          "如果是其他情况,则结束整个程序
          LEAVE PROGRAM.
      ENDCASE.
    ENDMODULE.                    "user_command_0100 INPUT

MODULE status_0200 OUTPUT.
  SET PF-STATUS 'SCREEN_200'.
  SET TITLEBAR 'TITL_200'.
  "如果设置的是在对话屏幕的 PBO 事件块中执行Message
  IF event-pbo = 'X'.
    message_event = 'PBO'.
    message_place = 'on dynpro'.
    "在对话屏幕的PBO里并没有通过调用函数方式去执行Message
    PERFORM call_message.
  ENDIF.
ENDMODULE.                    "status_0200 OUTPUT

MODULE user_command_0200 INPUT.
  save_ok = ok_code.
  CLEAR ok_code.
  CASE save_ok.
      "如果用户点击的是标准工具栏中的 Back 或 Exit 按钮时,则立即结束当前屏幕序列
    WHEN 'BACK_100'.
      LEAVE TO SCREEN

  1.     WHEN 'LAUNCH'.
          "IF event-pai = 'X'.
          message_event = 'PAI'.
          message_place = 'on dynpro'.
          PERFORM call_message.
          " ENDIF.
        WHEN 'FUNC'.
          message_event = 'PAI'.
          message_place = 'in function module on dynpro'.
          PERFORM call_function.
        WHEN 'EXIT'.
          LEAVE TO SCREEN
  2.   ENDCASE.
    ENDMODULE.                    "user_command_0200 INPUT

MODULE status_0300 OUTPUT.
  SET PF-STATUS 'LIST'.
  SET TITLEBAR 'TITL_300'.
  "LEAVE TO LIST-PROCESSING将控制权从对话屏幕转向输出列表处理器LIST PROCESSING,让当前屏幕的PBO与
  "PAI中的Write输出语句将结果都输出到该输出列表List屏幕之上
 "离开这里(300屏幕)并到达(TO)列表处理,并且(AND)设置  after exiting the list processor时,会
  "跳转到对话屏幕100,如果设置为0,则当前屏幕序列会关闭
  "该语句不会挂起当前屏幕的PBO处理,执行后会立即继续执行后续语句,这与LEAVE TO SCREEN XXX是不同的
  LEAVE TO LIST-PROCESSING AND RETURN TO SCREEN 100.

  NEW-PAGE NO-TITLE.
  WRITE 'Basic List'.
  "让当前屏幕(300屏幕)不弹出来。该语句作用是:如果该语句用在PBO中,当前屏幕不会显示,但会继续后续的PBO
 "处理,且前一屏幕还会继续保持显示。
  "该语句不能使用在PBO之外的块处理中。该语句的一般是与LEAVE TO LIST-PROCESSING一起使用,当使用
"LEAVE TO LIST-PROCESSING之后,控制权从屏幕转向了输出列表,所有的Write输出结果都会写到输出列表中(否
"则这些Write语句会输入到对话屏幕中),如果此时不想显示屏幕200,则可以使用此语句来过路此屏幕,当然这可
"以使用LEAVE SCREEN.语句来代替此语句,但LEAVE screen需要放在pbo的最后面(因为leave screen后面的
"语句是不会再执行的),但suppress dialog可以放在pbo中的任何位置
  "注:如果在被压制的屏幕的PAI事件中弹出了任何类型的消息,则被压制的屏幕还是会显示出来。
  SUPPRESS DIALOG.
  "LEAVE SCREEN.离开当前屏幕跳转到当前屏幕的下一屏幕,注:如果全要使用此语句代替SUPPRESS DIALOG,则要
"放Module的最后面
ENDMODULE.                    "status_0300 OUTPUT

************************************************************************
* Selection screen events                                              *
************************************************************************
AT SELECTION-SCREEN OUTPUT."1100选择屏幕的PBO事件
  IF event-pbo = 'X'.
    message_event = 'PBO'.
    message_place = 'on selection screen'.
    PERFORM call_message.
  ENDIF.

  "此为1100选择屏幕的PAI事件,该事件在点击选择屏幕上的 "执行" 按钮后调用。
AT SELECTION-SCREEN.
  IF funct = 'X'.
    message_event = 'PAI'.
    message_place = 'in funktion module on selection screen'.
    PERFORM call_function.
  ELSEIF event-pai = 'X'.
    message_event = 'PAI'.
    message_place = 'on selection screen'.
    PERFORM call_message.
  ENDIF.

************************************************************************
* List events
************************************************************************
AT USER-COMMAND.
  CASE sy-ucomm.
    WHEN 'DETAIL'.
      WRITE: / 'Detail list, level:', sy-lsind.
    WHEN 'MESSAGE'.
      message_event = 'AT USER-COMMAND'.
      message_place = 'on list'.
      WRITE: / 'Detail list, level:', sy-lsind.
      PERFORM call_message.
    WHEN 'FUNCT'.
      message_event = 'AT USER-COMMAND'.
      message_place = 'in funktion module on list'.
      PERFORM call_function.
      WRITE: / 'Detail list, level:', sy-lsind.
  ENDCASE.

************************************************************************
* Subroutines                                                          *
************************************************************************
FORM call_message.
  CONCATENATE message_type ', ' message_place ',' message_event INTO msg.
  MESSAGE ID '00' TYPE message_type NUMBER '001' WITH msg .
ENDFORM.                    "call_message

FORM call_function.
  IF except-no = 'X'."抛(RAISING)异常,但不处理
    "由于函数抛出了异常,但未处理,所以会忽略掉 MESSAGE 的raising 选项,最
    "后message以原本的形式展现,不会转存到 SY-MSGID 、SY-MSGNO 、SY-MSGTY、
    "SY-MSGV1 ... SY-MSGV4 系统变量中去
    CALL FUNCTION 'ZJZJ_FUNCTION_MESSAGE_RAISING'
      EXPORTING

protected void onCreate(Bundle arg0) {

        message_type 

message_type
        message_place = message_place
        message_event = message_event.
  ELSEIF except-yes = 'X'."抛(RAISING)异常,且进行处理
    "由于函数抛出了异常,且在主调程序中进行了处理,所以MESSAGE最终不会以原本形式展现,raising 选
    "项抛出的的异常信息会转存到 SY-MSGID 、SY-MSGNO 、SY-MSGTY、SY-MSGV1 ... SY-MSGV4 系统变量中去
    CALL FUNCTION 'ZJZJ_FUNCTION_MESSAGE_RAISING'
      EXPORTING

super.onCreate(arg0);

        message_type 

message_type
        message_place = message_place
        message_event = message_event
      EXCEPTIONS
        mess          = 4."捕获到异常
    CASE sy-subrc.
      WHEN 0.
        CONCATENATE sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4 INTO msg.
        MESSAGE i001(00)
                WITH 'No exception raised in function module' msg.
      WHEN 4."如果捕获到了mess异常
        CONCATENATE sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4 INTO msg.
        MESSAGE i001(00)
                WITH 'Handling exception from function module.' msg .
    ENDCASE.
  ELSEIF except-catch = 'X'."捕获消息
    CALL FUNCTION 'ZJZJ_FUNCTION_MESSAGE'
      EXPORTING

setContentView(R.layout.em_activity_chat);

        message_type 

message_type
        message_place = message_place
        message_event = message_event
      EXCEPTIONS
        error_message = 4.
    CASE sy-subrc.
      WHEN 0.
        CONCATENATE sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4 INTO msg.
        MESSAGE i001(00)
                WITH 'No exception(type E A) raised in function module.' msg.
      WHEN 4.
        CONCATENATE sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4 INTO msg.
        MESSAGE i001(00)
                WITH 'Handling exception from function module.' msg.
    ENDCASE.
  ELSEIF except-nocatch = 'X'."未捕获消息
    CALL FUNCTION 'ZJZJ_FUNCTION_MESSAGE'
      EXPORTING

activityInstance = this;

        message_type 

message_type
        message_place = message_place
        message_event = message_event.
  ENDIF.
ENDFORM.                    "call_function

FORM convert_user_input.
  IF type-a = 'X'.
    message_type = 'A'.
  ELSEIF type-e = 'X'.
    message_type = 'E'.
  ELSEIF type-i = 'X'.
    message_type = 'I'.
  ELSEIF type-s = 'X'.
    message_type = 'S'.
  ELSEIF type-w = 'X'.
    message_type = 'W'.
  ELSEIF type-x = 'X'.
    message_type = 'X'.
  ENDIF.
ENDFORM.                    "convert_user_input

FORM modi_screnn USING pai pai_input pbo pbo_input.
  LOOP AT SCREEN.
    IF screen-name = 'EVENT-PAI'.
      "复选框 EVENT-PAI 是否钩选上
      event-pai = pai.
      "设置 EVENT-PAI 是否可选(禁止输入)
      screen-input = pai_input.
      MODIFY SCREEN.
    ENDIF.
    IF screen-name = 'EVENT-PBO'.
      "复选框 EVENT-PBO 是否钩选上
      event-pbo = pbo.
      "设置 EVENT-PBO 是否可选(禁止输入)
      screen-input = pbo_input.
      MODIFY SCREEN.
    ENDIF.

    IF place-report = 'X'
      and ( screen-name = 'EXCEPT-NO'
      or screen-name = 'EXCEPT-YES'
      or screen-name = 'EXCEPT-CATCH'
      or screen-name = 'EXCEPT-NOCATCH' ).
      except-no = ''.
      screen-input = '0'.
      MODIFY SCREEN.
    ENDIF.
  ENDLOOP.
ENDFORM.                    " MODI_SCRENN

FUNCTION ZJZJ_FUNCTION_MESSAGE_RAISING.
  DATA: msg TYPE string.
  CONCATENATE MESSAGE_TYPE ',' MESSAGE_PLACE ',' MESSAGE_EVENT INTO msg.
  MESSAGE ID '00' TYPE MESSAGE_TYPE NUMBER '001' WITH msg RAISING MESS.
ENDFUNCTION.

FUNCTION ZJZJ_FUNCTION_MESSAGE.
  DATA: msg TYPE string.
  CONCATENATE message_type ','  message_place ',' message_event INTO msg.
  MESSAGE ID '00' TYPE message_type NUMBER '001' WITH msg.
ENDFUNCTION.

//get user id or group id

在状态栏中显示信息

一般用于多步操作的进度指示,显示当前正在处理的任务信息

CALL FUNCTION 'SAPGUI_PROGRESS_INDICATOR'"
EXPORTING
TEXT = text-022.

toChatUsername = getIntent().getExtras().getString("userId");

“E”消息与回退按扭

START-OF-SELECTION.

  DATA: l_vkorg TYPE likp-vkorg .

  SELECT SINGLE vkorg FROM likp  INTO l_vkorg WHERE vbeln = p_vbeln .

    CALL FUNCTION 'ZMM_ILG_LOCK_DN'
      EXPORTING
        i_vbeln  = p_vbeln
        i_loctyp = p_loctyp
      IMPORTING
        e_zflag  = flg
        e_errmg  = msg.

    IF p_loctyp = '0' AND flg = 'S'.
      MESSAGE 'DN block successful.' TYPE 'S'.
    ELSEIF p_loctyp = '1' AND flg = 'S'.
      MESSAGE 'DN unblock successful.' TYPE 'S'.
    ELSE.
      CONCATENATE 'Update failed: '  msg  INTO msg.
      * MESSAGE  msg  TYPE 'E'."如果使用此种方式打印消息,则程序会显示成下面截图样子,此时界面没有了,回退按钮也不能使用,所以修改成如下形式即可
      MESSAGE  msg  TYPE 'S' DISPLAY LIKE 'E'.
      STOP.”使用程序停止下来,不然的话会执行START-OF-SELECTION事件块后面剩余的程序
    ENDIF.

 

图片 17

 

 MESSAGE s001(00) DISPLAY LIKE 'E' WITH text-001 l_vkorg.
      STOP.

 

在函数中,不直接弹出消息,而是向上再次抛出:

MESSAGE E201 WITH HOST RAISING NOT_CONNECTED.

在上层可以这样捕获:

CALL FUNCTION 'ZMM_DATA_TO_FTP'
      EXPORTING
        im_funid       = l_funid
        im_filename    = l_filename
        im_rfcdest     = 'SAPFTPA'
      TABLES
        text           = t_div
      EXCEPTIONS

//use EaseChatFratFragment

        not_connected 

2
        OTHERS         = 5.
    IF sy-subrc <> 0.
      MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
              WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
    ENDIF.

chatFragment = new ChatFragment();

确认框函数POPUP_TO_CONFIRM

图片 18

//pass parameters to chat fragment

chatFragment.setArguments(getIntent().getExtras());

getSupportFragmentManager().beginTransaction().add(R.id.container, chatFragment).commit();

}

@Override

protected void onDestroy() {

super.onDestroy();

activityInstance = null;

}

@Override

protected void onNewIntent(Intent intent) {

// make sure only one chat activity is opened

String username = intent.getStringExtra("userId");

if (toChatUsername.equals(username))

super.onNewIntent(intent);

else {

finish();

startActivity(intent);

}

}

@Override

public void onBackPressed() {

chatFragment.onBackPressed();

if (EasyUtils.isSingleActivity(this)) {

Intent intent = new Intent(this, MainActivity.class);

startActivity(intent);

}

}

public String getToChatUsername(){

return toChatUsername;

}

@Override public void onRequestPermissionsResult(int requestCode, @NonNull String permissions,

@NonNull int grantResults) {

PermissionsManager.getInstance().notifyPermissionsChange(permissions, grantResults);

}

}

官方文档是这么说的

封装EaseChatFragment的ChatFragment

那么Demo中是做了一层封装的。

package com.hyphenate.chatuidemo.ui;

import android.app.Activity;

import android.content.ClipData;

import android.content.Intent;

import android.graphics.Bitmap;

import android.graphics.Bitmap.CompressFormat;

import android.media.ThumbnailUtils;

import android.net.Uri;

import android.os.Build;

import android.os.Bundle;

import android.text.Editable;

import android.text.TextWatcher;

import android.view.LayoutInflater;

import android.view.View;

import android.view.View.OnClickListener;

import android.view.ViewGroup;

import android.widget.BaseAdapter;

import android.widget.Toast;

import com.easemob.redpacketsdk.constant.RPConstant;

import com.easemob.redpacketui.utils.RPRedPacketUtil;

import com.easemob.redpacketui.utils.RedPacketUtil;

import com.easemob.redpacketui.widget.ChatRowRandomPacket;

import com.easemob.redpacketui.widget.ChatRowRedPacket;

import com.easemob.redpacketui.widget.ChatRowRedPacketAck;

import com.easemob.redpacketui.widget.ChatRowTransfer;

import com.hyphenate.chat.EMClient;

import com.hyphenate.chat.EMCmdMessageBody;

import com.hyphenate.chat.EMGroup;

import com.hyphenate.chat.EMMessage;

import com.hyphenate.chat.EMTextMessageBody;

import com.hyphenate.chatuidemo.Constant;

import com.hyphenate.chatuidemo.DemoHelper;

import com.hyphenate.chatuidemo.R;

import com.hyphenate.chatuidemo.domain.EmojiconExampleGroupData;

import com.hyphenate.chatuidemo.domain.RobotUser;

import com.hyphenate.chatuidemo.widget.ChatRowVoiceCall;

import com.hyphenate.easeui.EaseConstant;

import com.hyphenate.easeui.ui.EaseChatFragment;

import com.hyphenate.easeui.ui.EaseChatFragment.EaseChatFragmentHelper;

import com.hyphenate.easeui.widget.chatrow.EaseChatRow;

import com.hyphenate.easeui.widget.chatrow.EaseCustomChatRowProvider;

import com.hyphenate.easeui.widget.emojicon.EaseEmojiconMenu;

import com.hyphenate.util.EasyUtils;

import com.hyphenate.util.PathUtil;

import java.io.File;

import java.io.FileOutputStream;

import java.util.List;

import java.util.Map;

public class ChatFragment extends EaseChatFragment implements EaseChatFragmentHelper{

// constant start from 11 to avoid conflict with constant in base class

private static final int ITEM_VIDEO = 11;

private static final int ITEM_FILE = 12;

private static final int ITEM_VOICE_CALL = 13;

private static final int ITEM_VIDEO_CALL = 14;

private static final int REQUEST_CODE_SELECT_VIDEO = 11;

private static final int REQUEST_CODE_SELECT_FILE = 12;

private static final int REQUEST_CODE_GROUP_DETAIL = 13;

private static final int REQUEST_CODE_CONTEXT_MENU = 14;

private static final int REQUEST_CODE_SELECT_AT_USER = 15;

private static final int MESSAGE_TYPE_SENT_VOICE_CALL = 1;

private static final int MESSAGE_TYPE_RECV_VOICE_CALL = 2;

private static final int MESSAGE_TYPE_SENT_VIDEO_CALL = 3;

private static final int MESSAGE_TYPE_RECV_VIDEO_CALL = 4;

//red packet code : 红包功能使用的常量

private static final int MESSAGE_TYPE_RECV_RED_PACKET = 5;

private static final int MESSAGE_TYPE_SEND_RED_PACKET = 6;

private static final int MESSAGE_TYPE_SEND_RED_PACKET_ACK = 7;

private static final int MESSAGE_TYPE_RECV_RED_PACKET_ACK = 8;

private static final int MESSAGE_TYPE_RECV_TRANSFER_PACKET = 9;

private static final int MESSAGE_TYPE_SEND_TRANSFER_PACKET = 10;

private static final int MESSAGE_TYPE_RECV_RANDOM = 11;

private static final int MESSAGE_TYPE_SEND_RANDOM = 12;

private static final int REQUEST_CODE_SEND_RED_PACKET = 16;

private static final int ITEM_RED_PACKET = 16;

private static final int REQUEST_CODE_SEND_TRANSFER_PACKET = 17;

private static final int ITEM_TRANSFER_PACKET = 17;

//end of red packet code

/**

* if it is chatBot

*/

private boolean isRobot;

@Override

public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

return super.onCreateView(inflater, container, savedInstanceState);

}

@Override

protected void setUpView() {

setChatFragmentListener(this);

if (chatType == Constant.CHATTYPE_SINGLE) {

Map robotMap = DemoHelper.getInstance().getRobotList();

if(robotMap!=null && robotMap.containsKey(toChatUsername)){

isRobot = true;

}

}

super.setUpView();

// set click listener

titleBar.setLeftLayoutClickListener(new OnClickListener() {

@Override

public void onClick(View v) {

if (EasyUtils.isSingleActivity(getActivity())) {

Intent intent = new Intent(getActivity(), MainActivity.class);

startActivity(intent);

}

onBackPressed();

}

});

((EaseEmojiconMenu)inputMenu.getEmojiconMenu()).addEmojiconGroup(EmojiconExampleGroupData.getData());

if(chatType == EaseConstant.CHATTYPE_GROUP){

inputMenu.getPrimaryMenu().getEditText().addTextChangedListener(new TextWatcher() {

@Override

public void onTextChanged(CharSequence s, int start, int before, int count) {

if(count == 1 && "@".equals(String.valueOf(s.charAt(start)))){

startActivityForResult(new Intent(getActivity(), PickAtUserActivity.class).

putExtra("groupId", toChatUsername), REQUEST_CODE_SELECT_AT_USER);

}

}

@Override

public void beforeTextChanged(CharSequence s, int start, int count, int after) {

}

@Override

public void afterTextChanged(Editable s) {

}

});

}

}

@Override

protected void registerExtendMenuItem() {

//use the menu in base class

super.registerExtendMenuItem();

//extend menu items

inputMenu.registerExtendMenuItem(R.string.attach_video, R.drawable.em_chat_video_selector, ITEM_VIDEO, extendMenuItemClickListener);

inputMenu.registerExtendMenuItem(R.string.attach_file, R.drawable.em_chat_file_selector, ITEM_FILE, extendMenuItemClickListener);

if(chatType == Constant.CHATTYPE_SINGLE){

inputMenu.registerExtendMenuItem(R.string.attach_voice_call, R.drawable.em_chat_voice_call_selector, ITEM_VOICE_CALL, extendMenuItemClickListener);

inputMenu.registerExtendMenuItem(R.string.attach_video_call, R.drawable.em_chat_video_call_selector, ITEM_VIDEO_CALL, extendMenuItemClickListener);

}

//聊天室暂时不支持红包功能

//red packet code : 注册红包菜单选项

if (chatType != Constant.CHATTYPE_CHATROOM) {

inputMenu.registerExtendMenuItem(R.string.attach_red_packet, R.drawable.em_chat_red_packet_selector, ITEM_RED_PACKET, extendMenuItemClickListener);

}

//red packet code : 注册转账菜单选项

if (chatType == Constant.CHATTYPE_SINGLE) {

inputMenu.registerExtendMenuItem(R.string.attach_transfer_money, R.drawable.em_chat_transfer_selector, ITEM_TRANSFER_PACKET, extendMenuItemClickListener);

}

//end of red packet code

}

@Override

public void onActivityResult(int requestCode, int resultCode, Intent data) {

super.onActivityResult(requestCode, resultCode, data);

if (requestCode == REQUEST_CODE_CONTEXT_MENU) {

switch (resultCode) {

case ContextMenuActivity.RESULT_CODE_COPY: // copy

clipboard.setPrimaryClip(ClipData.newPlainText(null,

((EMTextMessageBody) contextMenuMessage.getBody()).getMessage()));

break;

case ContextMenuActivity.RESULT_CODE_DELETE: // delete

conversation.removeMessage(contextMenuMessage.getMsgId());

messageList.refresh();

break;

case ContextMenuActivity.RESULT_CODE_FORWARD: // forward

Intent intent = new Intent(getActivity(), ForwardMessageActivity.class);

intent.putExtra("forward_msg_id", contextMenuMessage.getMsgId());

startActivity(intent);

break;

default:

break;

}

}

if(resultCode == Activity.RESULT_OK){

switch (requestCode) {

case REQUEST_CODE_SELECT_VIDEO: //send the video

if (data != null) {

int duration = data.getIntExtra("dur", 0);

String videoPath = data.getStringExtra("path");

File file = new File(PathUtil.getInstance().getImagePath(), "thvideo" System.currentTimeMillis());

try {

FileOutputStream fos = new FileOutputStream(file);

Bitmap ThumbBitmap = ThumbnailUtils.createVideoThumbnail(videoPath, 3);

ThumbBitmap.compress(CompressFormat.JPEG, 100, fos);

fos.close();

sendVideoMessage(videoPath, file.getAbsolutePath(), duration);

} catch (Exception e) {

e.printStackTrace();

}

}

break;

case REQUEST_CODE_SELECT_FILE: //send the file

if (data != null) {

Uri uri = data.getData();

if (uri != null) {

sendFileByUri(uri);

}

}

break;

case REQUEST_CODE_SELECT_AT_USER:

本文由澳门皇冠金沙网站发布于编辑程序,转载请注明出处:环信官方Demo源码分析及SDK简单应用,Messages消息