别藏着,穷,也随便需隐藏

     
 面对提问有关出世农村之问题,当红艺人赵丽颖答道:“我是农村长大的男女,感谢爸妈,把自己死得无像农村人口。”

简介

从去年 LeanCloud
发布实时通信(IM)服务后,基于用户反馈和工程师对急需的消化以及指向工作的提炼,上周专业披露了「实时通信
2.0
」。设计意见还是是「灵活、解耦、可组合、可定制」,具体可以参考《实时通信支出指南》,了解
LeanCloud 实时通信的基本概念和模型。

     
在热闹之游乐圈,当你缺乏日成为名时多少中注目,世俗的眼光啊难免,出生背景是人人考虑有人头地的主要因素。然而,不是每个人之亲爹都是未富即贵,财富并不过,就集成才华,才华拼不了,就集成品行吧!

下载和安装

可以到 LeanCloud
官方下载点下载
LeanCloud IM SDK v2 版。将生充斥至的 jar 包加入工程即可。

       
出生农村十有八九凡穷人。穷,往往带动在志短,想成为至少气质高雅一些之穷人,不是善事,但压根儿会为你记住,无形的能力推进着您去攀爬。

相当底文本聊天

俺们先行由最简易的环入手,看看怎么用 LeanCloud IM SDK v2
贯彻一对一文本闲话。

                                01

     
 阿富兄妹三口是村里的孤儿,十东时大人事故伤亡,母亲改嫁,生活的重负落于年了知天命之年之爷爷奶奶身上,老人谋生便是几亩地之收获。

      看罢众多贫穷造就励志哥的故事,但未是每个都这么。

     
 逢年过节,村里乡情浓厚,你家送件红衣裳,我家送修鱼干,阿富家代表红红火火,年年有鱼的迎春礼凑一起了。

     
 素生活之不够,知识熏陶的贫,谋生观念的落后,寒门难发出贵子。

     
 阿富在校时三天两头给求老人,家里长辈对客的管教有心无力,恨铁不成钢。毕业后同达到珠三角打工狂潮,总算走来农村,他感怀着挣钱回老家为房屋,几年生活过去,回家时差不多矣一个年相仿的女朋友,且他以为人父,这同样年,他们无满二十。

初始化

和 LeanCloud 其他服务一样,实时聊天服务之初始化也是以 Application 的
onCreate 方法被开展的:

public class MyApplication extends Application{

    public void onCreate(){
      ...
      AVOSCloud.initialize(this,"{{appId}}","{{appKey}}");
      ...
    }
}

同时以AndroidManifest.xml中间声明:

<manifest>
   ...

   <application
        android:name=".MyApplication"
        ....>
        ...

        <service android:name="com.avos.avoscloud.PushService" />

        <receiver android:name="com.avos.avoscloud.AVBroadcastReceiver">
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED" />
                <action android:name="android.intent.action.USER_PRESENT" />
            </intent-filter>
        </receiver>
        ...
   </application>

</manifest>

接下我们得好用户登录。

                               02

     
 记得我五年级那年,父亲以工厂因问题差点错过左臂,母亲已一切工作专心照料,生活捉襟见肘又面临开学季,爷爷和教育工作者还算是熟络,近300初之学费为后推平促进,我生会欠费入学。

     
 面对每周学费留堂的催交,让我懂上文化的老大难。用后来大城市读大学之校友韵儿的言辞就是:“在此处看,我们(农村)经济是不及别人,只能埋头苦学比成绩了。”

       
在13春秋的岁数寒冬每天早起5:30自然醒,后来才了解是压力所与。打开课本一全整个去抄写生词,仿佛它就是为退农村的唯一稻草。那无异年之后期,我顺手总分第一名为,慰藉在痛苦中之阿爸。父亲打省外的骨科医院回到晚让我带来了有限如约的《奥赛急先锋》,我理解,左手还无可知动弹的大在书之侧签名有多不易。

     
 后来,两单月后,父亲取工厂有工伤赔偿,我找班主任补交学费情景还历历在目,虽然已经时隔十几年。

登录

如若聊天发起方名叫 Tom,为直观起见,我们运用用户名来作为 clientId
登录聊天系统(LeanCloud 云端只要求 clientId
在动用内唯一即可,具体用啊数据由应用层决定),代码如下:

AVIMClient imClient = AVIMClient.getInstance("Tom");
imClient.open(new IMClientCallback(){
  @Override
  public void done(AVIMClient client, AVException e) {
    if (null != e) {
      // 出错了,可能是网络问题无法连接 LeanCloud 云端,请检查网络之后重试。
      // 此时聊天服务不可用。
      e.printStackTrace();
    } else {
      // 成功登录,可以开始进行聊天了(假设为 MainActivity)。
      Intent intent = new Intent(currentActivity, MainActivity.class);
      currentActivity.startActivity(intent);
    };
  }
});

                              03

     
珠三角打工的风潮依旧不弱化,特别是女孩,读了初中外出打工的事例不胜枚举,然后早早成家,“小孩”养小,周而复始,生活的步骤从祖辈复制粘贴。

      二老给本人最好老之支撑是指向知识的探究,这被自家高度之饱满自由。

     
 父亲每年还受对联师傅写一对准:万般皆下品,唯有读书高。门联年度岁还各有不同,唯独这幅红纸年年变,字尽同,稳稳当当地立在自己房间的墙壁及。

     
 有次依稀听到同学丽丽的二老吵架,我的生父对妈妈说:“读书花费还多为如支持,别给旁人说谁哪个的女……”后来才晓得,是丽丽到镇上求学和同学总是几上旷课外出游玩。特别是女孩,你的底言行会备受关注。

建对话

苟我们若同「Bob」这个用户进行拉,我们先创造一个对话,代码如下:

List<String> clientIds = new ArrayList<String>();
clientIds.add("Tom");
clientIds.add("Bob");

// 我们给对话增加一个自定义属性 type,表示单聊还是群聊
// 常量定义:
// int ConversationType_OneOne = 0; // 两个人之间的单聊
// int ConversationType_Group = 1;  // 多人之间的群聊
Map<String, Object> attr = new HashMap<String, Object>();
attr.put("type", ConversationType_OneOne);

imClient.createConversation(clientIds, attr, new AVIMConversationCreatedCallback() {
  @Override
  public void done(AVIMConversation conversation, AVException e) {
    if (null != conversation) {
      // 成功了,这时候可以显示对话的 Activity 页面(假定为 ChatActivity)了。
      Intent intent = new Intent(this, ChatActivity.class);
      Intent.putExtra(“conversation”, conversation);
      startActivity(intent);
    }
  }
});

成立之「对话」在控制台怎么查

如果你所表现,我们创建一个对话之当儿,指定了成员(Tom 和
Bob)和一个分外的性质({type: 0})。这些数量保存至云端后,你当
控制台 -> 存储 -> 数据 里面会视,_Conversation
表中多了一样长长的记下,新记录之 m 属性值为["Tom", "Bob"]attr
属性值为{"type":0}。如您所预期,m 属性就是对许正在成员列表,attr
属性就是用户多的额头外属性值(以目标的款式储存)。

                             04

      穷是呀?它不但发生实际的压迫感,更产生长期留的自卑感。

     
 懵懂学生时,面对情书惶恐十分,这说不定并无希罕。多年从此,面对异性的橄榄枝,依然当他是无是“瞎”?一个友好审美另一个友好。面对好的人口若见面偷关注,然后为好一千单理由放弃。然后白日梦天天做,梦而同样涂鸦不行没有。

     
 自卑感让自身同朝无前,大学四年鞭策自己,奖学金每年如期而至,我并非算聪明,也无到底完美,但略并未辜负初心。自卑感到一定水准了,仿佛将团结正是主要战胜的对象,自己一次次跟惰性对抗,不思输得最惨。

     
 身体好并发乏力时,没有最多体育细胞的要好,运动就是是均等集革命,我下定狠心狠狠坚持了一个月份,往后平年的惯性维持,如今,运动都是家常便饭。达成目标,也克升官一个人口之幸福感。

出殡信息

成立好对话后,要发送信息是甚粗略的:

AVIMMessage message = new AVIMMessage();
message.setContent("hello");
conversation.sendMessage(message, new AVIMConversationCallback() {
  @Override
  public void done(AVException e) {
    if (null != e) {
      // 出错了。。。
      e.printStackTrace();
    } else {
      Logger.d("发送成功,msgId=" + message.getMessageId());
    }
  }
});

吓了,这样平等漫漫消息就是发送过去了。但是问题来了,对于「Bob」而言,他怎么才会吸纳别人发给他的音信啊?

                              05

       并非羡慕别人的具有,无需叹息自己之贫乏。

      前段时间,许久没有单身沟通的恋人小电过来畅聊。后段出现以下

       “看君平凡比较看,工作的话该出大大x位数存款了吧?”

        “ 没有。”

     “你改天看看几布置卡的余额,加起来应当有些吧!”

     
卡里余额在这个年龄就是是熟悉,理科生对数字并无生。你实在的对答,在人家看来可能是卖惨。话不投机半句多,我闪。

     
 2016年最后,听说有了驾照就比如有了世界,在新方针来之际,纵然费用居高不下,驾校门前人满为患,总起赶鸭子上架之势。看在银行卡,手机里莫名的低收入显示,哦,还从未,梦被。

     
 可已经想,同龄人里你到底省吃俭用,假期既没经常出旅行,奢侈品不曾购买,怎么就是一般月光族,怎么?连你还疑惑自己了?有些原因而懂,但从来不必要时刻享受。别人的钱管都是一个谜语,只不过你是不是立即仿佛好奇宝宝而已,我不是,也没有太可怜必要,何必为?

消息接收

每当 Bob 这无异端,要力所能及吸纳及消息,需要如下几步:

1,进行初始化;

2,实现团结的 AVIMMessageHandler,响应新消息到达通知,主要是之类函数:

public void onMessage(AVIMMessage message, AVIMConversation conversation, AVIMClient client);

于 Tom 发过来的音讯,要显得出来,我们只是需要兑现 onMessage
即可,示例代码如下:

class CustomMessageHandler extends AVIMMessageHandler {
  @Override
  public void onMessage(AVIMMessage message, AVIMConversation conversation, AVIMClient client) {
    // 新消息到来了。在这里增加你自己的处理代码。
    String msgContent = message.getContent();
    Logger.d(conversation.getConversationid() + " 收到一条新消息:" + msgContent);
  }
}

3,进行登录,代码也跟发送端一样。

完代码如下:

// 自定义消息响应类
class CustomMessageHandler extends AVIMMessageHandler {
  @Override
  public void onMessage(AVIMMessage message, AVIMConversation conversation, AVIMClient client) {
    // 新消息到来了。在这里增加你自己的处理代码。
    String msgContent = message.getContent();
    Logger.d(conversation.getConversationid() + " 收到一条新消息:" + msgContent);
  }
}

// application 的初始化部分
public void onCreate(){
  ...
  AVOSCloud.initialize(this,"{{appId}}","{{appKey}}");
  AVIMMessageManager.registerDefaultMessageHandler(new CustomMessageHandler());
  ...
}

// 用户登录部分
AVIMClient imClient = AVIMClient.getInstance("Bob");
imClient.open(new IMClientCallback(){
  @Override
  public void done(AVIMClient client, AVException e) {
    if (null != e) {
      // 出错了,可能是网络问题无法连接 LeanCloud 云端,请检查网络之后重试。
      // 此时聊天服务不可用。
      e.printStackTrace();
    } else {
      // 成功登录,可以开始进行聊天了。
    };
  }
});

注意!
AVIMMessageManager.registerDefaultMessageHandler() 一定要于
AVIMClient.open() 之前调用,否则恐怕造成服务器发回的有信息丢失。

                               06

      特困是整存不歇的从事,也不管需隐藏,更无需坐穷卖穷。

     
 无论是出生低微的穷人,还是含金钥匙出生之有钱人,往后的还用在从并中过。

       每一样上之明,都比今天迈入有,内心更红火一些,气质更卫生一些。

 

差一点个举足轻重的回调接口

起点的例证中得以视,要接受到别人吃您发送的音讯,需要重载
AVIMMessageHandler 类。从 v2 版开始,LeanCloud IM SDK
大量使用回调来举报操作结果,但是对有些低落之音通知,则还是使用接口来落实的,包括:

  • 即网出现变化
  • 对话中有新的信
  • 对话中出新成员在
  • 对话中发生成员离开
  • 叫邀加入某对话
  • 让蹬来对话

LeanCloud IM SDK 内部使用了三种接口来响应这些事件。

网事件响应接口

要用来处理网络转移事件,接口定义在
AVIMClientEventHandler,主要函数为:

  /**
   * 实现本方法以处理网络断开事件
   */
  public abstract void onConnectionPaused(AVIMClient client);

  /**
   * 实现本方法以处理网络恢复事件
   */
  public abstract void onConnectionResume(AVIMClient client);

每当网络中断的景下,所有的音信收发和对话操作都见面产出问题。

通过 AVIMClient.setClientEventHandler(AVIMClientEventHandler handler)
可以设定全局的 ClientEventHandler。

对话成员变动响应接口

主要用以处理对话中成员变动之轩然大波,接口定义在
AVIMConversationEventHandler,主要函数为:

  /**
   * 实现本方法以处理聊天对话中的参与者离开事件
   *
   * @param members 离开的参与者
   * @param kickedBy 踢人者,自愿退出的情况下踢人者就是参与者
   */
  public abstract void onMemberLeft(AVIMClient client,
      AVIMConversation conversation, List<String> members, String kickedBy);

  /**
   * 实现本方法以处理聊天对话中的参与者加入事件
   *
   * @param members 加入的参与者
   * @param invitedBy 邀请人,有可能是加入的参与者本身
   */
  public abstract void onMemberJoined(AVIMClient client,
      AVIMConversation conversation, List<String> members, String invitedBy);

  /**
   * 实现本方法来处理当前用户被踢出某个聊天对话事件
   *
   * @param kickedBy 踢出你的人
   */
  public abstract void onKicked(AVIMClient client, AVIMConversation conversation,
      String kickedBy);

  /**
   * 实现本方法来处理当前用户被邀请到某个聊天对话事件
   *
   * @param conversation 被邀请的聊天对话
   * @param operator 邀请你的人
   */
  public abstract void onInvited(AVIMClient client, AVIMConversation conversation,
      String operator);

通过
AVIMMessageManager.setConversationEventHandler(AVIMConversationEventHandler handler)
可以安装全局的 ConversationEventHandler。

信息应接口

要用以处理新消息到达事件,接口定义在
MessageHandlerAVIMMessageHandler
是一个缺损的落实类似,我们该经过重载 AVIMMessageHandler
的连锁方法来好信息处理。主要的道发生:

  // 收到新的消息
  @Override
  public void onMessage(AVIMMessage message, AVIMConversation conversation);

  // 自己发送的消息已经被对方接收
  @Override
  public void onMessageReceipt(AVIMMessage message, AVIMConversation conversation, AVIMClient client);

通过 AVIMMessageManager.registerDefaultMessageHandler(handler)
可以设置全局的 MessageHandler。

咱们兑现就三近乎接口,就好拍卖所有的打招呼消息了。示例代码如下:

class CustomNetworkHandler extends AVIMClientEventHandler {
  @Override
  public void onConnectionPaused(AVIMClient client) {
    // 请按自己需求改写
    Logger.d("connect paused");
  }

  @Override
  public void onConnectionResume(AVIMClient client) {
    // 请按自己需求改写
    Logger.d("connect resume");
  }
}

class CustomConversationHandler extends AVIMConversationEventHandler {
  public private Context gContext = null;
  private void toast(String str) {
    Toast.makeText(gContext, str, Toast.LENGTH_SHORT).show();
  }
  private void toast(Context context, String str) {
    Toast.makeText(context, str, Toast.LENGTH_SHORT).show();
  }

  @Override
  public void onMemberLeft(AVIMClient client, AVIMConversation conversation, List<String> members, String kickedBy) {
    // 请按自己需求改写
    toast(MsgUtils.nameByUserIds(members) + " left, kicked by " + MsgUtils.nameByUserId(kickedBy));
    //注:MsgUtils 是一个辅助类,nameByUserIds 用来将 userId 转换成用户名
  }

  @Override
  public void onMemberJoined(AVIMClient client, AVIMConversation conversation, List<String> members, String invitedBy) {
    // 请按自己需求改写
    toast(MsgUtils.nameByUserIds(members) + " joined , invited by " + MsgUtils.nameByUserId(invitedBy));
    //注:MsgUtils 是一个辅助类,nameByUserIds 用来将 userId 转换成用户名
  }

  @Override
  public void onKicked(AVIMClient client, AVIMConversation conversation, String kickedBy) {
    // 请按自己需求改写
    toast("you are kicked by " + MsgUtils.nameByUserId(kickedBy));
  }

  @Override
  public void onInvited(AVIMClient client, AVIMConversation conversation, String operator) {
    // 请按自己需求改写
    toast("you are invited by " + MsgUtils.nameByUserId(operator));
  }
};

class CustomMsgHandler extends AVIMMessageHandler {
  @Override
  public void onMessage(AVIMMessage message, AVIMConversation conversation, AVIMClient client) {
    // 请按自己需求改写
    String msgContent = message.getContent();
    Logger.d(conversation.getConversationid() + " 收到一条新消息:" + msgContent);
  }

  @Override
  public void onMessageReceipt(AVIMMessage message, AVIMConversation conversation, AVIMClient client) {
    // 请按自己需求改写
    Logger.d("发往对话 " + conversation.getConversationid() + " 的消息 "+ message.getMessageId() +" 已被接收");
  }
}

// 设置事件响应接口
AVIMClient.setClientEventHandler(new CustomNetworkHandler());
AVIMMessageManager.setConversationEventHandler(new CustomConversationHandler());
AVIMMessageManager.registerDefaultMessageHandler(new CustomMsgHandler());

支持富媒体之拉消息

点的代码演示了哪发送简单文本信息,但是现在的交互方式已经越发多样化,图像、语音、视频都是不行普遍的消息类型。v2
版的 LeanCloud IM SDK 已经得以十分好地支持这些富媒体消息,具体说明如下:

基类:AVIMTypedMessage

有富媒体消息之基类,其宣称也

//SDK定义的消息类型,LeanCloud SDK 自身使用的类型是负数,所有正数留给开发者自定义扩展类型使用,0 作为「没有类型」被保留起来。
enum AVIMReservedMessageType {
  UnsupportedMessageType(0),
  TextMessageType(-1),
  ImageMessageType(-2),
  AudioMessageType(-3),
  VideoMessageType(-4),
  LocationMessageType(-5),
  FileMessageType(-6);
};

public abstract class AVIMTypedMessage extends AVIMMessage {
  public AVIMTypedMessage();

  public int getMessageType();

  @Override
  public final String getContent();

  @Override
  public final void setContent(String content);
}

文件消息(AVIMTextMessage)

AVIMTypedMessage 子类,表示一般的文件消息,其宣称也

public class AVIMTextMessage extends AVIMTypedMessage {
  public String getText();
  public void setText(String text);

  public Map<String, Object> getAttrs();
  public void setAttrs(Map<String, Object> attr);
}

好看来,对于文本消息,主要的性质有 textattr 两单,通过简单的
getter/setter 就足以看到。要发送文书消息,示例代码为:

AVIMTextMessage message = new AVIMTextMessage();
message.setText("hello");
conversation.sendMessage(message, new AVIMConversationCallback() {
  @Override
  public void done(AVException e) {
    if (null != e) {
      // 出错了。。。
      e.printStackTrace();
    } else {
      Logger.d("message sent.");
    }
  }
});

文本消息(AVIMFileMessage)

AVIMTypedMessage
子类,用来发送带附件的信,开发者可以据此她来发送「离线文件」。对于此类消息,LeanCloud
IM SDK 内部会先拿文件上传到 LeanCloud 文件存储服务器(自带 CDN
功能),然后将文件首先数据(url,文件大小等等)放在信息包内发送到
LeanCloud 实时通信服务端。其构造函数声明也:

// 传入本地文件路径,构造消息对象
public AVIMFileessage(String localPath) throws FileNotFoundException, IOException;
// 传入本地文件,构造消息对象
public AVIMFileMessage(File localFile) throws FileNotFoundException, IOException;
// 传入 AVFile 实例,构造消息对象
public AVIMFileMessage(AVFile file);

暨公事消息看似,文件消息呢支持附带文本以及任何自定义属性,可以经如下方法上加
/ 获取更多信息:

  • String getText() / void setText(String text)
  • Map<String, Object> getAttrs() / void setAttrs(Map<String,
    Object> attr);

出殡文书消息的以身作则代码为:

String localZipfilePath;
try {
  AVIMFileMessage message = new AVIMFileMessage(localZipfilePath);
  message.setText("这是你要的文档");
  conversation.sendMessage(message, new AVIMConversationCallback() {
    @Override
    public void done(AVException e) {
      if (null != e) {
        // 出错了。。。
        e.printStackTrace();
      } else {
        Logger.d("message sent");
      }
    }
  });
} catch (Exception ex) {
}

收取及这般消息随后,开发者可以透过以下方法,获取到文件首先数据(size
等)和一个包含二上制数据的 AVFile 对象:

  • AVFile getAVFile() 方法会返回一个二进制文件的 AVFile
    实例,之后可以通过 AVFile 来完成数据下载或者其他操作,具体可参见
    AVFile
    说明
  • String getFileUrl() 方法会返回二进制文件的 url
  • long getSize() 方法会返回二进制文件之其实尺寸(单位:byte)
  • Map<String, Object> getFileMetaData()
    可以获取二进制文件的其余元数据信息。

图像信息(AVIMImageMessage)

AVIMFileMessage
子类,专门就此来发送图像和附带文本的混消息,其构造函数声明也:

// 传入本地文件路径,构造消息对象
public AVIMImageMessage(String localPath) throws FileNotFoundException, IOException;
// 传入本地文件,构造消息对象
public AVIMImageMessage(File localFile) throws FileNotFoundException, IOException;
// 传入 AVFile 实例,构造消息对象
public AVIMImageMessage(AVFile file);

出殡图像信息的示范代码为:

String localImagePath;
try {
  AVIMImageMessage message = new AVIMImageMessage(localImagePath);
  message.setText("你说我好看不?");
  conversation.sendMessage(message, new AVIMConversationCallback() {
    @Override
    public void done(AVException e) {
      if (null != e) {
        // 出错了。。。
        e.printStackTrace();
      } else {
        Logger.d("message sent");
      }
    }
  });
} catch (Exception ex) {
}

收下及这般消息随后,开发者可以经如下方法,获取到几何图像元数据(width,height,图像
size)和一个蕴含图像数据的 AVFile 对象:

  • int getWidth() 方法会返回图像的大幅度(单位:pixel)
  • int getHeight() 方法会返回图像的高度(单位:pixel)
  • AVFile getAVFile() (继承自
    AVIMFileMessage)方法会返回一个图像文件的 AVFile 实例
  • String getFileUrl() (继承自 AVIMFileMessage)方法会返回图像文件的
    url
  • long getSize() (继承自
    AVIMFileMessage)方法会返回图像文件的其实尺寸(单位:byte)
  • String getText() (继承自
    AVIMFileMessage)方法会返回随图像一起发送的文件信息。
  • Map<String, Object> getFileMetaData() (继承自
    AVIMFileMessage)可以收获图像的其他元数据信息。

节奏消息(AVIMAudioMessage)

AVIMFileMessage
子类,专门用来发送语音及附带文本的插花消息,其构造函数声明也:

// 传入本地文件路径,构造消息对象
public AVIMAudioMessage(String localPath) throws FileNotFoundException, IOException;
// 传入本地文件,构造消息对象
public AVIMAudioMessage(File localFile) throws FileNotFoundException, IOException;   
// 传入 AVFile 实例,构造消息对象
public AVIMAudioMessage(AVFile file);

出殡音频消息的以身作则代码为:

String localAudioPath;
try {
  AVIMAudioMessage message = new AVIMAudioMessage(localAudioPath);
  message.setText("听听我唱的小苹果:)");
  conversation.sendMessage(message, new AVIMConversationCallback() {
    @Override
    public void done(AVException e) {
      if (null != e) {
        // 出错了。。。
        e.printStackTrace();
      } else {
        Logger.d("message sent");
      }
    }
  });
} catch (Exception ex) {
}

吸收到这般消息后,开发者可以通过如下方法,获取到几何口风频元数据(时长
duration、音频 size)和一个含有音频数据的 AVFile 对象:

  • double getDuration() 方法会返回音频的长(单位:秒)
  • AVFile getAVFile() (继承自
    AVIMFileMessage)方法会返回一个音频文件的 AVFile 实例
  • String getFileUrl() (继承自 AVIMFileMessage)方法会返回音频文件的
    url
  • long getSize() (继承自
    AVIMFileMessage)方法会返回音频文件的实际上尺寸(单位:byte)
  • String getText() (继承自
    AVIMFileMessage)方法会返回随音频一起发送的文本信息。
  • Map<String, Object> getFileMetaData() (继承自
    AVIMFileMessage)可以赢得音频的外元数据信息。

视频信息(AVIMVideoMessage)

AVIMFileMessage
子类,专门就此来发送视频和附带文本的混杂消息,其构造函数声明也:

// 传入本地文件路径,构造消息对象
public AVIMVideoMessage(String localPath) throws FileNotFoundException, IOException;
// 传入本地文件,构造消息对象
public AVIMVideoMessage(File localFile) throws FileNotFoundException, IOException;
// 传入 AVFile 文件,构造消息对象
public AVIMVideoMessage(AVFile file);

出殡视频信息的演示代码为:

String localVideoPath;
try {
  AVIMVideoMessage message = new AVIMVideoMessage(localVideoPath);
  message.setText("敢不敢跟我比一比");
  conversation.sendMessage(message, new AVIMConversationCallback() {
    @Override
    public void done(AVException e) {
      if (null != e) {
        // 出错了。。。
        e.printStackTrace();
      } else {
        Logger.d("message sent");
      }
    }
  });
} catch (Exception ex) {
}

接受及这么消息随后,开发者可以可以经过如下方法,获取到多收看频元数据(时长
duration、视频 size)和一个涵盖视频数据的 AVFile 对象:

  • double getDuration() 方法会返回视频的长短(单位:秒)
  • AVFile getAVFile() (继承自
    AVIMFileMessage)方法会返回一个视频文件的 AVFile 实例
  • String getFileUrl() (继承自 AVIMFileMessage)方法会返回视频文件的
    url
  • long getSize() (继承自
    AVIMFileMessage)方法会返回视频文件的莫过于尺寸(单位:byte)
  • String getText() (继承自
    AVIMFileMessage)方法会返回随视频一起发送的文件信息。
  • Map<String, Object> getFileMetaData() (继承自
    AVIMFileMessage)可以获得视频的其余元数据信息。

地理位置信息(AVIMLocationMessage)

AVIMTypedMessage
子类,支持发送地理位置信息及附带文本的夹消息,其声称也:

public class AVIMLocationMessage extends AVIMTypedMessage {
  public String getText();
  public void setText(String text);

  public Map<String, Object> getAttrs();
  public void setAttrs(Map<String, Object> attr);

  public AVGeoPoint getLocation();
  public void setLocation(AVGeoPoint location);
}

与公事消息看似,地理位置信息就是长了一个 AVGeoPoint 的 Location
属性。要发送位置信息的示范代码为:

AVIMLocationMessage message = new AVIMLocationMessage();
message.setText("快点过来!");
message.setLocation(new AVGeoPoint(15.9, 56.4));
conversation.sendMessage(message, new AVIMConversationCallback() {
  @Override
  public void done(AVException e) {
    if (null != e) {
      // 出错了。。。
      e.printStackTrace();
    } else {
      Logger.d("message sent");
    }
  }
});

收纳至如此的音随后,开发者可以得到到实际的地理位置数据。

怎么接纳富媒体消息

新版 LeanCloud IM SDK 内部封装了对富媒体消息之支撑,所有富媒体消息还是自
AVIMTypedMessage 派生出的。发送的早晚可直接调用
conversation.sendMessage()
函数。在接收端,我们呢特地增加了千篇一律接近回调接口
AVIMTypedMessageHandler,其定义也:

public class AVIMTypedMessageHandler<T extends AVIMTypedMessage> extends MessageHandler<T> {

  @Override
  public void onMessage(T message, AVIMConversation conversation, AVIMClient client);

  @Override
  public void onMessageReceipt(T message, AVIMConversation conversation, AVIMClient client);
}

开发者可以编制好之音讯处理 handler,然后调用
AVIMMessageManager.registerMessageHandler(Class<? extends AVIMMessage> clazz, MessageHandler<?> handler)
函数来注册目标 handler。

接收端对于富媒体消息的通报处理的以身作则代码如下:

class MsgHandler extends AVIMTypedMessageHandler<AVIMTypedMessage> {

  @Override
  public void onMessage(AVIMTypedMessage message, AVIMConversation conversation, AVIMClient client) {
    // 请按自己需求改写
    switch(message.getMessageType()) {
    case AVIMReservedMessageType.TextMessageType:
      AVIMTextMessage textMsg = (AVIMTextMessage)message;
      Logger.d("收到文本消息:" + textMsg.getText() + ", msgId:" + textMsg.getMessageId());
      break;
    case AVIMReservedMessageType.FileMessageType:
      AVIMFileMessage fileMsg = (AVIMFileMessage)message;
      Logger.id("收到文件消息。msgId=" + fileMsg.getMessageId() + ", url=" + fileMsg.getFileUrl() + ", size=" + fileMsg.getSize());
      break;
    case AVIMReservedMessageType.ImageMessageType:
      AVIMImageMessage imageMsg = (AVIMImageMessage)message;
      Logger.id("收到图片消息。msgId=" + imageMsg.getMessageId() + ", url=" + imageMsg.getFileUrl() + ", width=" + imageMsg.getWidth() + ", height=" + imageMsg.getHeight());
      break;
    case AVIMReservedMessageType.AudioMessageType:
      AVIMAudioMessage audioMsg = (AVIMAudioMessage)message;
      Logger.id("收到音频消息。msgId=" + audioMsg.getMessageId() + ", url=" + audioMsg.getFileUrl() + ", duration=" + audioMsg.getDuration());
      break;
    case AVIMReservedMessageType.VideoMessageType:
      AVIMVideoMessage videoMsg = (AVIMAudioMessage)message;
      Logger.id("收到视频消息。msgId=" + videoMsg.getMessageId() + ", url=" + videoMsg.getFileUrl() + ", duration=" + videoMsg.getDuration());
      break;
    case AVIMReservedMessageType.LocationMessageType:
      AVIMLocationMessage locMsg = (AVIMLocationMessage)message;
      Logger.id("收到位置消息。msgId=" + locMsg.getMessageId() + ", latitude=" + locMsg.getLocation().getLatitude() + ", longitude=" + locMsg.getLocation().getLongitude());
      break;
    }
  }

  @Override
  public void onMessageReceipt(AVIMTypedMessage message, AVIMConversation conversation, AVIMClient client) {
  }
}
MsgHandler msgHandler = new MsgHandler();
AVIMMessageManager.registerMessageHandler(AVIMTypedMessage.class, msgHandler);

LeanCloud IM SDK 内部消息分发的逻辑是这么的:对于收受的任一新消息,SDK
内部都见面先解析消息之型,根据项目找到开发者也及时同样类别注册之拍卖
handler,然后挨家挨户调用这些 handler 的 onMessage
函数。如果没找到专门处理当下无异门类消息之 handler,就会传送给
defaultHandler 处理。

这样一来,在开发者也 TypedMessage(及其子类) 指定了特别的
handler,也指定了大局的 defaultHandler
了底时节,如果发送端发送的是通用的 AVIMMessage 消息,那么受端就是
AVIMMessageManager.registerDefaultMessageHandler()中指定的 handler
被调用;如果发送的凡 AVIMTypedMessage(及其子类)的音讯,那么受端就是
AVIMMessageManager.registerMessageHandler()中指定的 handler 被调用。

哪些扩大自己的富媒体消息

接轨给
AVIMTypedMessage,开发者也可以扩展自己之富媒体消息。其要求与手续是:

  • 贯彻新的信类型,继承自 AVIMTypedMessage。这里用留意少触及:
    • 于 class 上平添一个 @AVIMMessageType(type=123) 的
      Annotation,具体信息类型的价值(123)由开发者自己支配(LeanCloud
      内建的音类型应用负数,所有正数都留给给开发者扩展使用)。
    • 每当消息里属性上而多 @AVIMMessageField(name=””) 的
      Annotation,name
      为可选字段于声明字段属性,同时起定义的字段要发对应之
      getter/setter 方法。
  • 调用
    AVIMMessageManager.registerAVIMMessageType(Class<? extends AVIMTypedMessage> messageType)
    函数进行项目注册
  • 调用
    AVIMMessageManager.registerMessageHandler(Class<? extends AVIMMessage> clazz, MessageHandler<?> handler)
    函数进行信息处理 handler 注册。

AVIMTextMessage 的源码如下,可供参考:

@AVIMMessageType(type = -1)
public class AVIMTextMessage extends AVIMTypedMessage {

  @AVIMMessageField(name = "_lctext")
  String text;
  @AVIMMessageField(name = "_lcattrs")
  Map<String, Object> attrs;

  public String getText() {
    return this.text;
  }

  public void setText(String text) {
    this.text = text;
  }

  public Map<String, Object> getAttrs() {
    return this.attrs;
  }

  public void setAttrs(Map<String, Object> attr) {
    this.attrs = attr;
  }
}

群组聊天

以及前方的单聊类似,群组聊天为亟需先建一个会话(AVIMConversation),然后发送、接收新的音信。

创群组

暨单聊类似,建立一个大抵人聊天的群组也是格外简单的。例如:

Map<String, Object> attr = new HashMap<String, Object>();
attr.put("type", ConversationType_Group);
imClient.createConversation(clientIds, attr, new AVIMConversationCreatedCallback() {
  @Override
  public void done(AVIMConversation conversation, AVException e) {
    if (null != conversation) {
      // 成功了!
      Intent intent = new Intent(currentActivity, ChatActivity.class);
      Intent.putExtra(“conversation”, conversation);
      currentActivity.startActivity(intent);
    }
  }
});

遂后,我们尽管可进聊天界面了。

通往群组发送信息

出殡信息非常简单,与前方单聊的面貌同样。

咱俩见面小心到,AVIMConversation 还有一个发送信息之法门:

public void sendMessage(final AVIMMessage message, final int messageFlag,
      final AVIMConversationCallback callback)

比方这里 flag 的概念来如下三栽类型:

  • 暂态消息(AVIMConversation.TRANSIENT_MESSAGE_FLAG)。这种消息不见面被电动保存(以后当史信息被无法找到它们),也未支持延迟收,离线用户更非见面收到推送通知,所以适合用来举行控制协议。譬如聊天过程中「某某在输入中…」这样的状态信息,就合通过暂态消息来发送。
  • 一般性消息(AVIMConversation.NONTRANSIENT_MESSAGE_FLAG)。这种信息就是咱最为常用的消息类型,在
    LeanCloud
    云端会自动保存起来,支持延迟收和离线推送,以后在史信息遭到可找到它们。
  • 得回执消息(AVIMConversation.RECEIPT_MESSAGE_FLAG)。这啊是一律栽家常消息,只是消息于对方接后
    LeanCloud 服务端会发送一个回执通知受发送方(这就算是
    AVIMMessageHandler 中
    public void onMessageReceipt(AVIMMessage message, AVIMConversation conversation, AVIMClient client)
    函数被调用的机会)。

吸纳群组消息

吸收一个群组的信息,与吸纳单聊的信呢是同的。

成员管理

以询问到聊天室成员之后,可以吃用户约一些谈得来之意中人进入,作为管理员也可去一些「可怕」的积极分子。
加入新成员的 API 如下:

// 假设需要邀请 Alex,Ben,Chad 三人加入对话
List<String> userIds = new ArrayList<String>();
userIds.add("Alex");
userIds.add("Ben");
userIds.add("Chad");
conversation.addMembers(userIds, new AVIMConversationCallback() {
  @Override
  public void done(AVException error) {
    if (null != error) {
      // 加入失败,报错.
      error.printStackTrace();
    } else {
      // 发出邀请,此后新成员就可以看到这个对话中的所有消息了。
      Logger.d("invited.");
    }
  }
});

约成功后,相关方收到通知之时序是这样的:

    操作者(管理员)                    被邀请者                        其他人
1, 发出请求 addMembers
2,                               收到 onInvited 通知
3, 收到 onMemberJoined 通知      收到 onMemberJoined 通知      收到 onMemberJoined 通知

对应地,踢人时的调用 API 是:

List<String> userIds = new ArrayList<String>();
userIds.add("Alex");
conversation.kickMembers(userIds, new AVIMConversationCallback() {
  @Override
  public void done(AVException error) {
    if (null != error) {
      // 失败,报错.
      error.printStackTrace();
    } else {
      // 成功。
      Logger.d("kicked.");
    }
  }
});

踢人经常,相关方收到通知的时序如下:

    操作者(管理员)                被踢者                       其他人
1, 发出请求 kickMembers
2,                          收到 onKicked 通知
3, 收到 onMemberLeft 通知                             收到 onMemberLeft 通知

注意!
比方请、踢人操作有的时段,被邀请者/被踢者当前不在线,那么通知消息并无会见让离线缓存,所以他们更上线的早晚以未会见接通知。

获取历史信息

LeanMessage 会将非暂态消息自动保存于云端,之后开发者可以透过
AVIMConversation 来抱该对话之拥有历史信息。获取历史信息的 API 如下:

String oldestMsgId;
long oldestMsgTimestamp;
conversation.queryMessages(oldestMsgId,oldestMsgTimestamp, limit, new AVIMHistoryMessageCallback(){
  @Override
  public void done(List<AVIMMessage> messages, AVException e) {
    if (null != e) {
      // 出错了:(
    } else {
      // 成功,可以将消息加入缓存,同时更新 UI
    }
  }
});

注意:
得到历史信息的当儿,LeanCloud
云端是自从某个条信息开始,往前寻找开发者指定的 N
条消息,返回给客户端。为这个,获取历史信息需要传入三个参数:起始消息的
msgId,起始消息之出殡时间穿,需要获得的信条数。

由此就同 API 拿到之音讯就是 AVIMMessage 或 AVIMTypedMessage
实例数组,开发者可以像前收到新信息通知一致处理。

启用离线消息推送(仅针对 iOS 平台用户中)

管是才聊还是群聊,当用户 A
发出信息后,如果目标对话中生出部分用户眼前不在线,LeanCloud
云端可以供离线推送的法来提醒用户。这等同功能默认是倒闭的,你得在
LeanCloud 应用控制台中开启它。开启方法如下:

  • 报到 LeanCloud 应用控制台,选择是的用上;
  • 摘最好上面的「消息」服务,依次点击左边菜单「实时消息」->「设置」;
  • 在右手「iOS
    用户离线时之推送内容」下填好您要推送出去的音内容,保存;

诸如此类 iOS 平台及的用户就是得接过 Push Notification
了(当然,前提是用本身申请及了 RemoteNotification
权限,也以正确的推送证书上污染至了 LeanCloud 控制台)。

群组消息不打扰(仅对 iOS 平台用户中)

任凭是才聊还是群聊,对于发朝普通的 Conversation
的便消息,如果接收方当前不在线,LeanCloud 云端支持通过 Push
Notification
的措施展开提示。一般情况下立刻还是可怜好之,但是要是有群组特别活泼,那离线用户就见面吸纳了多的推送,会形成不聊之搅和。

针对是 LeanCloud IM 服务也同意单个用户来关闭/打开某个对话之离线推送功能。

寻群组

任是单聊,还是群聊,在 LeanCloud IM SDK
里面还是对话(Conversation)。我们受对话设置了如下几栽属性:

  • conversationId,字符串,对话 id,只念,对话创建之后由于 LeanCloud
    云端赋予一个大局唯一的 id。
  • creator,字符串,对话创建者 id,只念,标识对话创建者信息
  • members,数组,对话参与者,这里记录了独具的参与者
  • name,字符串,对话之讳,optional,可用来对于群组命名
  • attributes,Map/Dict,自定义属性,optional,供开发者自己壮大用。

咱们提供了专门的近乎,来查找一定的群组:通过 imClient.getQuery()
得到一个 AVIMConversationQuery 实例,然后调用
AVIMConversationQuery.wherexxx
多样措施来充实约原则。例如要寻找时报到用户参与的享有群聊对话,其代码为

// 搜索 Tom 参与的所有群组对话
List<String> clients = new ArrayList<String>();
clients.add("Tom");
AVIMConversationQuery conversationQuery = imClient.getQuery();
conversationQuery.containsMember(clients);

// 之前有常量定义:
// const int ConversationType_OneOne = 0;
// const int ConversationType_Group = 1;
conversationQuery.whereEqualTo("attr.type", ConversationType_Group);

conversationQuery.findInBackground(new AVIMConversationQueryCallback(){
  @Override
  public void done(List<AVIMConversation> conversations, AVException e) {
    if (null != e) {
      // 出错了。。。
      e.printStackTrace();
    } else {
      if (null != conversation) {
        Logger.d("找到了符合条件的 " + conversations.size() + " 个对话");
      } else {
        Logger.d("没有找到符合条件的对话");
      }
    }
  }
});

AVIMConversationQuery 中设置标准的法与 AVQuery 类似。这里
conversationQuery.containsMember()
表示对话之分子中最少含有这些口,可用来因部分成员查找对话;与是类似的还有一个
conversationQuery.withMembers()
则表示有还只发生这些分子,用来冲所有成员查找目标对话;conversationQuery.whereXXX()
文山会海措施可用来界定对话名称与从定义属性,这里要强调的某些凡,对于自定义属性的羁绊规范,属性名一定要以
attr 开头,如上例所示,限定额外的 type 条件的时刻需要指定的属性名是
attr.type。具体可以参考其头文件。

绽开聊天室

开放聊天室(也受暂态对话)可以用来很多地方,譬如弹幕、直播等等。在
LeanCloud IM SDK
中,开放聊天室是平等看似非常的群组,它为支撑创造、加入/踢来成员等操作,消息记录会被封存并可供应获取;与一般群组不一致的地方具体体现吗:

  • 切莫支持查询成员列表,你可以通过相关 API 查询在线人数;
  • 匪支持离线消息、离线推送通知等力量;
  • 靡成员进入、离开的打招呼;
  • 一个用户同样次于登录只能进入一个开聊天室,加入新的放聊天室后会自动离开原的聊天室;
  • 加盟后半时内断网重连见面自动进入原聊天室,超过这时尽管用重新加入;

创造开放聊天室

跟平凡的群组类似,建立一个绽放聊天室也是坏粗略的,只是在
AVIMClient.createConversation(conversationMembers, name, attributes, isTransient, callback)
中我们要传入 isTransient=true 选项。例如:

Map<String, Object> attr = new HashMap<String, Object>();
attr.put("type", ConversationType_Group);
imClient.createConversation(clientIds, name, attr, true, new AVIMConversationCreatedCallback() {
  @Override
  public void done(AVIMConversation conversation, AVException e) {
    if (null != conversation) {
      // 成功了,进入聊天室
      Intent intent = new Intent(currentActivity, ChatActivity.class);
      Intent.putExtra(“conversation”, conversation);
      currentActivity.startActivity(intent);
    }
  }
});

创办成功以后,我们尽管足以上聊天界面了。开放聊天室的别操作,都同日常群组操作一样。

在开放聊天室

假使任何极端用户都得投入开放聊天室。作为开发者,我们好透过通过特定条件检索到具有开放聊天室,然后允许用户自由参加,其现身说法代码为:

conversation.join(new AVIMConversationCallback(){
  @Override
  public void done(AVException e) {
    if (null != e) {
      // 出错了:(
    } else {
      // 成功,此时可以进入聊天界面了。。。
      Intent intent = new Intent(currentActivity, ChatActivity.class);
      Intent.putExtra(“conversation”, conversation);
      currentActivity.startActivity(intent);
    }
  }
});

查询在线人数

通过 AVIMConversation.getMemberCount()
方法可以实时查询开放聊天室的在线人数。示例代码如下:

conversation.getMemberCount(new AVIMConversationMemberCountCallback(){
  @Override
  public void done(Integer memberCount, AVException e) {
    if (null != e) {
      // 出错了:(
    } else {
      // 成功,此时 memberCount 的数值就是实时在线人数
    }
  }
});

签约和安

为满足开发者对权力和认证的求,LeanCloud
还计划了操作签名的建制。我们好于 LeanCloud
应用控制台中的「设置」->「应用选项」->「聊天推送」下面勾选「聊天服务签约认证」来启用签名(强烈推荐这样做)。启用后,所有的用户登录、对话创建/加入、邀请成员、踢来成员等操作都急需验证签名,这样开发者就好本着信息进行充分的操纵。

客户端即时边究竟欠如何行使与否?我们特需要实现 SignatureFactory
接口,然后以用户登录之前,把这个接口的实例赋值给 AVIMClient
即可(AVIMClient.setSignatureFactory(factory))。

设定了 signatureFactory 之后,对于急需鉴权的操作,LeanCloud IM SDK
与劳务器端通讯的时还见面带动达使用自己别的 Signature 信息,LeanCloud
云端会下 app 的 masterKey 来验证信息之管用,保证聊天渠道的安全。

对 SignatureFactory 接口,我们唯有需要实现即简单个函数即可:

  /**
   * 实现一个基础签名方法 其中的签名算法会在SessionManager和AVIMClient(V2)中被使用
   */
  public Signature createSignature(String peerId, List<String> watchIds) throws SignatureException;

  /**
   * 实现AVIMConversation相关的签名计算
   */
  public Signature createConversationSignature(String conversationId, String clientId,
      List<String> targetIds, String action) throws SignatureException;

createSignature
函数会在用户登录的时光让调用,createConversationSignature
会在对话创建/加入、邀请成员、踢来成员等操作时于调用。

公需要举行的就算是按部就班前文所陈述之签算法实现签约,其中 Signature
声明如下:

public class Signature {
  public List<String> getSignedPeerIds();
  public void setSignedPeerIds(List<String> signedPeerIds);

  public String getSignature();
  public void setSignature(String signature);

  public long getTimestamp();
  public void setTimestamp(long timestamp);

  public String getNonce();
  public void setNonce(String nonce);
}

里面四个属性分别是:

  • signature 签名
  • timestamp 时间戳,单位秒
  • nonce 随机字符串 nonce
  • signedPeerIds 放行的 clientId 列表,v2 中已经撇开不用

下面的代码展示了冲 LeanCloud
云代码进行签约时,客户端的实现部分,你得参照其来就好的逻辑实现:

public class KeepAliveSignatureFactory implements SignatureFactory {
 @Override
 public Signature createSignature(String peerId, List<String> watchIds) {
   Map<String,Object> params = new HashMap<String,Object>();
   params.put("self_id",peerId);
   params.put("watch_ids",watchIds);

   try{
     Object result =  AVCloud.callFunction("sign",params);
     if(result instanceof Map){
       Map<String,Object> serverSignature = (Map<String,Object>) result;
       Signature signature = new Signature();
       signature.setSignature((String)serverSignature.get("signature"));
       signature.setTimestamp((Long)serverSignature.get("timestamp"));
       signature.setNonce((String)serverSignature.get("nonce"));
       return signature;
     }
   }catch(AVException e){
     throw (SignatureFactory.SignatureException) e;
   }
   return null;
 }

  @Override
  public Signature createConversationSignature(String convId, String peerId, List<String> targetPeerIds,String action){
   Map<String,Object> params = new HashMap<String,Object>();
   params.put("self_id",peerId);
   params.put("group_id",convId);
   params.put("group_peer_ids",targetPeerIds);
   params.put("action",action);

   try{
     Object result = AVCloud.callFunction("group_sign",params);
     if(result instanceof Map){
        Map<String,Object> serverSignature = (Map<String,Object>) result;
        Signature signature = new Signature();
        signature.setSignature((String)serverSignature.get("signature"));
        signature.setTimestamp((Long)serverSignature.get("timestamp"));
        signature.setNonce((String)serverSignature.get("nonce"));
        return signature;
     }
   }catch(AVException e){
     throw (SignatureFactory.SignatureException) e;
   }
   return null;
  }
}

LeanCloud IM SDK
专注做好底层的通讯服务,有再次多可定制化的地方,譬如说:

  • 账户体系跟 IM 系统是分别的;
  • 消息成为离线推送的时候,推送内容开发者是足以定制的;
  • 经 web hook,开发者可以对信息进行更多处理;
  • 闲聊过程被通过信息鉴权机制,开发者可以产生重复多控制;

因不够 UI
组件,实事求是地称在初用户接入成本或有些高,但是当业务规模扩张、产品求变换多以后,相信大家见面越加好
LeanCloud 这种自由灵活的行使体验,以及稳定快速的劳动品质。