Android实现简单的聊天功能

Posted yintianhao

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android实现简单的聊天功能相关的知识,希望对你有一定的参考价值。

---恢复内容开始---

一直想试试做一个两个客户端可以聊天的功能,上网查了查,这个IM聊天的好像还真的不那么容易,无奈deadline快到了,所以只能用一下第三方的库了

这里我用的是环信,然后花了一天,其中走了不少弯路,把这个功能做出来了,记录一下这个坎坷的过程

 

首先,一般这种第三方服务,像之前用的百度地图,都需要去注册成为他们的开发者,所以第一步自然是去环信官网注册

网址在这:https://www.easemob.com/,就是直接点击页面上的注册就可以了

 

注册成功后,就是创建应用然后拿到对应的APPKey了,进入后台管理,点击创建应用,就会有相应的APPKey了,这里不多说了

 

然后接下来就是集成到androidStudio里面了,参考官方的集成教程就可以了

http://docs.easemob.com/im/200androidclientintegration/10androidsdkimport

把权限都写好,并将里面的APPKey换成自己的就行了

然后点击sychron now,ok了

 

现在开始撸代码

先写界面,推荐参考郭霖大神的<第一行代码>第二版里面的聊天界面,之前有想法自己用ListView来写,但是性能很差体验也差

还是用RecyclerView好一些

聊天主界面

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

    <android.support.v7.widget.RecyclerView
        android:id="@+id/msg_recycler_view"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"/>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <EditText
            android:id="@+id/input_text"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:hint="Type something here"
            android:maxLines="2"/>
        <Button
            android:id="@+id/send"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Send"/>

    </LinearLayout>

</LinearLayout>

消息的布局

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

        <LinearLayout
            android:id="@+id/left_layout"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="left"
            android:background="@drawable/message_left">
            <TextView
                android:id="@+id/left_msg"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center"
                android:layout_margin="10dp"
                android:textColor="#fff"/>

        </LinearLayout>

        <LinearLayout
            android:id="@+id/right_layout"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="right"
            android:background="@drawable/message_right">

            <TextView
                android:id="@+id/right_msg"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_margin="10dp"
                android:layout_gravity="center"/>

        </LinearLayout>



</LinearLayout>

  

消息类

package Tool;

/**
 * Created by 31786 on 2018/5/15.
 */

public class Msg {
    public static final int TYPE_RECIEVED = 0;//表示这是一条收到的消息
    public static final int TYPE_SENT = 1;//表示这是一条发出去的消息
    private String content;//消息的内容
    private int type;//消息的类型
    public Msg(String content,int type){
        this.content = content;
        this.type = type;
    }
    public String getContent(){
        return content;
    }
    public int getType(){
        return type;
    }
}

适配器

package Tool;

import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;

import com.example.car.R;

import java.util.List;

/**
 * Created by 31786 on 2018/5/15.
 */

public class MsgAdapter extends RecyclerView.Adapter<MsgAdapter.ViewHolder>{

    private List<Msg> mMsgList;//消息列表
    static class ViewHolder extends RecyclerView.ViewHolder{
        LinearLayout leftLayout;
        LinearLayout rightLayout;
        TextView leftMsg;
        TextView rightMsg;
        ViewHolder(View view){
            super(view);
            Log.d("ViewHolder","初始化了");
            leftLayout =(LinearLayout) view.findViewById(R.id.left_layout);
            rightLayout = (LinearLayout) view.findViewById(R.id.right_layout);
            leftMsg = (TextView) view.findViewById(R.id.left_msg);
            rightMsg = (TextView) view.findViewById(R.id.right_msg);
        }
    }
    public MsgAdapter(List<Msg> msgList){
        Log.d("MsgAdapter","初始化了");
        mMsgList = msgList;
    }
    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent,int viewType){
        Log.d("ViewHolder","初始化了");
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.msg_item,parent,false);
        return new ViewHolder(view);
    }
    @Override
    public void onBindViewHolder(ViewHolder holder,int position){
        Msg msg = mMsgList.get(position);
        if(msg.getType()==Msg.TYPE_RECIEVED){
            Log.d("RECIEVED......",msg.getContent());
            holder.leftLayout.setVisibility(View.VISIBLE);
            holder.rightLayout.setVisibility(View.GONE);
            holder.leftMsg.setText(msg.getContent());
        }else if(msg.getType()==Msg.TYPE_SENT){
            Log.d("SEND......",msg.getContent());
            holder.rightLayout.setVisibility(View.VISIBLE);
            holder.leftLayout.setVisibility(View.GONE);
            holder.rightMsg.setText(msg.getContent());
        }
    }
    @Override
    public int getItemCount(){
        Log.d("Item的数量是",String.valueOf(mMsgList.size()));
        return mMsgList.size();
    }
}

 

然后开始写逻辑

由于我这里是个子功能,我SDK的初始化和注册并没有放在当前这个聊天的活动里面,所以建议最好将SDK的初始化放在工程里面靠前的活动里面

因为如果初始化两次,那么第二次就会新建一个新的连接,就会出现问题,注册的话也是为了避免重复注册,我把注册和我APP本身的注册放在一起了

 

初始化代码

public void initMob(){
        Context appContext = this;
        int pid = android.os.Process.myPid();
        String processAppName = getAppName(pid);
// 如果APP启用了远程的service,此application:onCreate会被调用2次
// 为了防止环信SDK被初始化2次,加此判断会保证SDK被初始化1次
// 默认的APP会在以包名为默认的process name下运行,如果查到的process name不是APP的process name就立即返回
        if (processAppName == null ||!processAppName.equalsIgnoreCase(appContext.getPackageName())) {
            Log.e("YTH", "enter the service process!");

            // 则此application::onCreate 是被service 调用的,直接返回
            return;
        }
        EMClient.getInstance().init(this,new EMOptions());
        EMClient.getInstance().setDebugMode(true);
    }
    private String getAppName(int pID) {
        String processName = null;
        ActivityManager am = (ActivityManager) this.getSystemService(ACTIVITY_SERVICE);
        List l = am.getRunningAppProcesses();
        Iterator i = l.iterator();
        PackageManager pm = this.getPackageManager();
        while (i.hasNext()) {
            ActivityManager.RunningAppProcessInfo info = (ActivityManager.RunningAppProcessInfo) (i.next());
            try {
                if (info.pid == pID) {
                    processName = info.processName;
                    return processName;
                }
            } catch (Exception e) {
                // Log.d("Process", "Error>> :"+ e.toString());
            }
        }
        return processName;
    }

 

注册代码

public static void registerMob(){
        new Thread(new Runnable() {
            @Override
            public void run() {
                try{
                    EMClient.getInstance().createAccount(userNumber.getText().toString(),
                            passWord.getText().toString());
                }catch (HyphenateException e){
                    Log.e("聊天功能","注册失败");
                }
            }
        }).start();
    }

 

主界面的逻辑

package com.example.car;

import android.net.Uri;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

import com.google.android.gms.appindexing.Action;
import com.google.android.gms.appindexing.AppIndex;
import com.google.android.gms.appindexing.Thing;
import com.google.android.gms.common.api.GoogleApiClient;
import com.hyphenate.EMCallBack;
import com.hyphenate.EMMessageListener;
import com.hyphenate.chat.EMClient;
import com.hyphenate.chat.EMMessage;
import com.hyphenate.chat.EMTextMessageBody;
import com.hyphenate.util.EasyUtils;

import java.util.ArrayList;
import java.util.List;

import Tool.Msg;
import Tool.MsgAdapter;

public class Chatting extends AppCompatActivity implements View.OnClickListener, EMMessageListener {

    private List<Msg> msgList = new ArrayList<>();//消息列表
    private EditText inputText;//输入框
    private Button send;//发送
    private RecyclerView msgViewRecyclerView;
    private MsgAdapter adapter;
    private String chatId;//自己传进来的跟自己聊天的人的ID
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_chatting);
        initEvents();
        addListener();
    }

    public void addListener() {
        send.setOnClickListener(this);
    }

    public void initEvents() {
        inputText = (EditText) findViewById(R.id.input_text);
        send = (Button) findViewById(R.id.send);
        msgViewRecyclerView = (RecyclerView) findViewById(R.id.msg_recycler_view);
        LinearLayoutManager layoutManager = new LinearLayoutManager(this);
        msgViewRecyclerView.setLayoutManager(layoutManager);
        adapter = new MsgAdapter(msgList);
        msgViewRecyclerView.setAdapter(adapter);
    }

    public void sendMessage(String content,String chatWithId) {
        EMMessage message = EMMessage.createTxtSendMessage(content,chatWithId);
//如果是群聊,设置chattype,默认是单聊
        message.setChatType(EMMessage.ChatType.Chat);
//发送消息
        EMClient.getInstance().chatManager().sendMessage(message);
        message.setMessageStatusCallback(new EMCallBack() {
            @Override
            public void onSuccess() {
                Log.d("发送信息成功","发送信息成功");
                //Toast.makeText(Chatting.this, "发送信息成功", Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onError(int code, String error) {
                Log.d("发送信息失败",error);
                //Toast.makeText(Chatting.this, "发送信息失败", Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onProgress(int progress, String status) {
                //Toast.makeText(Chatting.this, "发送信息中"+status, Toast.LENGTH_SHORT).show();
                Log.d("发送信息中",status);
            }
        });
    }

    @Override
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.send:
                Log.d("MainActivity", "Send......");
                String content = inputText.getText().toString();
                if (!"".equals(content)) {
                    Msg msg = new Msg(content, Msg.TYPE_SENT);
                    Log.d("Send", content);
                    msgList.add(msg);
                    adapter.notifyItemInserted(msgList.size() - 1);//刷新
                    msgViewRecyclerView.scrollToPosition(msgList.size() - 1);//定位
                    inputText.setText("");
                    sendMessage(content,chatId);
                }
                break;
            default:
                break;
        }
    }

    @Override
    public void onMessageReceived(List<EMMessage> messages) {
        //将恢复的信息加入到消息列表里面并刷新
        for (int i = 0; i < messages.size(); i++) {
            String content = ((EMTextMessageBody) messages.get(i).getBody()).getMessage();
            msgList.add(new Msg(content, Msg.TYPE_RECIEVED));
            //Toast.makeText(getApplicationContext(), content, Toast.LENGTH_SHORT).show();
            Log.d("size="+messages.size(),"回复的信息"+content);
        }
        adapter.notifyItemInserted(msgList.size() - 1);
        adapter.notifyDataSetChanged();
        msgViewRecyclerView.scrollToPosition(msgList.size() - 1);

    }

    @Override
    public void onCmdMessageReceived(List<EMMessage> messages) {

    }

    @Override
    public void onMessageRead(List<EMMessage> messages) {

    }

    @Override
    public void onMessageDelivered(List<EMMessage> messages) {

    }

    @Override
    public void onMessageChanged(EMMessage message, Object change) {

    }



    @Override
    public void onResume(){
        super.onResume();
        EMClient.getInstance().chatManager().addMessageListener(this);
    }
    public void onStop(){
        super.onStop();
        EMClient.getInstance().chatManager().removeMessageListener(this);
    }
}

出来的效果还行,凑合着能用

 技术分享图片

---恢复内容结束---

以上是关于Android实现简单的聊天功能的主要内容,如果未能解决你的问题,请参考以下文章

Unity3D 实现简单的语音聊天 [Android版本]

Android开发之聊天室

Android开发之聊天室

android中实现简单的聊天功能

Android实现类似QQ聊天的功能 怎么实现

GitLab