Android小项目————聊天室(UI篇)

Android小项目————聊天室(UI篇)

一.前言

  • 这是所做的第二个android项目,主要目的对暑假所学的java和android知识点进行复习巩固和实践,由于知识所限,目前这个聊天室并不是很完善,而且由于对于多线程的相关知识点不太熟练,所以服务器端经常崩,后期会将其更加完善
  • 其中聊天室主界面主要借鉴的是郭霖老师《第一行代码》

二.所用知识点

  • java
    • IO流
    • 网络编程
    • 多线程
  • android
    • 活动
    • 布局
    • RecyckerView控件

三.界面运行效果截图

  • 登录界面
    Android小项目————聊天室(UI篇)_第1张图片
  • 客户端
    Android小项目————聊天室(UI篇)_第2张图片
    Android小项目————聊天室(UI篇)_第3张图片
  • 服务器端
    Android小项目————聊天室(UI篇)_第4张图片

四.编程前准备

  • 添加Recyckerview的依赖库
    1. 在app/build.gradle(在Project模式下打开,下同)文件中添加一条语句

      compile 'com.android.support:recyclerview-v7:24.2.1'
    2. 添加的地方
      Android小项目————聊天室(UI篇)_第5张图片
    3. 修改后,点击弹出了提醒语句中的 Sync Now
      这里写图片描述
  • 获得联网权限
    1. 在app/src/main/AndroidManifest.xml添加语句




  • 准备聊天气泡素材
    1. 准备两张气泡图片
      这里写图片描述
      这里写图片描述
    2. 打开android 下的draw9patch.bat文件对图片进行编辑
    3. 将图片重命名为message_left.9.png和message_right.9.png
    4. 将图片放在文件夹app/src/main/res/drawable中
    5. 如何嫌麻烦,可直接使用源码中的素材,源码在下一篇
  • 修改app图标
    1. 修改app/src/main/res/values/Strings.xml文件 修改内容如下:


      冰炭不投de小计算器

  • 修改app名称
    1. 将图标放在app/src/main/res/mipmap文件中
    2. 修改AndroidManifest.xml文件

      android:allowBackup="true"
      android:icon="@mipmap/图片名字" //修改这句
      android:label="@string/app_name"

五.登录界面

  • 目的:获得当前用户的昵称和ip地址
  • 步骤:

    • 新建一个android项目,并在最后一步选择Add No Activity
    • 新建一个Activity,命名为RegisterActivity,并勾选Generate Layout File(创建一个对应界面)和Launcher Activity(选为主活动)选项
    • 创建一个Name类

    代码:

  • RegisterActivity中的代码
public class RegisterActivity extends AppCompatActivity {

    private EditText input_name;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_register);
        input_name = (EditText)findViewById(R.id.input_name);
        Button confirm = (Button)findViewById(R.id.confirm);

        confirm.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View v) {
                Name.name = input_name.getText().toString();
                Name.IP = getLocalIpAddress() ;
                Log.e("RegisterActivity",Name.IP+Name.name);
                if(!Name.name.equals("")) {
                    Intent intent = new Intent(RegisterActivity.this, ChatroomActivity.class);
                    startActivity(intent);
                }
            }
        });
    }

    //获取本机ip
    public static String getLocalIpAddress() {
        try {
            for (Enumeration en = NetworkInterface
                    .getNetworkInterfaces(); en.hasMoreElements();) {
                NetworkInterface intf = en.nextElement();
                for (Enumeration enumIpAddr = intf
                        .getInetAddresses(); enumIpAddr.hasMoreElements();) {
                    InetAddress inetAddress = enumIpAddr.nextElement();
                    if (!inetAddress.isLoopbackAddress() && !inetAddress.isLinkLocalAddress()) {
                        return inetAddress.getHostAddress().toString();
                    }
                }
            }
        } catch (SocketException ex) {
            Log.e("WifiPreference IpAddress", ex.toString());
        }

        return null;
    }
}
  • app/src/main/res/layout/Activity_register.xml中的代码

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#d8e0e8"
    >
    <EditText
        android:id="@+id/input_name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:hint="输入一个昵称,最好短点"
        android:maxLines="2" />

    <Button
        android:id="@+id/confirm"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="确定"/>

LinearLayout>
  • Name中的代码
public class Name {
    public static String name ;
    public static  String IP;
}

六.聊天界面

  • 步骤:
    • 新建一个Activity,命名为ChatroomActivity,勾选Generate Layout File不勾选auncher Activity
    • 新建一个Msg类
    • 新建一个MsgAdapter类
    • 在app/src/main/res/layout文件夹中新建一个msg_item.xml文件
      代码:
  • ChatroomActivity中的代码
public class ChatroomActivity extends AppCompatActivity {

    private List msgList = new ArrayList<>();
    private EditText inputTest;
    private Button send;
    private RecyclerView msgRecyclerView;
    private MsgAdapter adapter;
    private ClientThread mClientThread;


    private Handler mHandler;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_chatroom);

        //各种赋值初始化
        inputTest = (EditText)findViewById(R.id.input_text);
        send = (Button)findViewById(R.id.send);
        msgRecyclerView =(RecyclerView)findViewById(R.id.msg_recycler_view);
        //创建一个LinearLayoutManager(线性布局)对象将它设置到RecyclerView
        LinearLayoutManager layoutmanager = new LinearLayoutManager(this);
        msgRecyclerView.setLayoutManager(layoutmanager);
        //调用构造方法创造实例,参数消息集合
        adapter = new MsgAdapter(msgList);
        msgRecyclerView.setAdapter(adapter);

        //重写Handler类handleMessage方法,并将对象赋给mHandler
        //该Handler绑定主线程,如果主线程的what为0则更新输入
        mHandler=new Handler() {
            @Override
            public void handleMessage(Message handleMsg) {
                if (handleMsg.what == 0) {
                    //接受到消息后的操作
                    String content = handleMsg.obj.toString();
                    Log.d( "xjj",content);
                    String [] arr = content.split("#\\$#");
                    String ip =arr[0];
                    String name =arr[1];
                    String str =arr[2];
                    Log.d( "xjj",ip + name + str);
                    Msg msg;
                    if(ip.equals(Name.IP)) {
                        msg = new Msg(name, str, Msg.TYPE_SENT);
                    }else {
                        msg = new Msg(name, str, Msg.TYPE_RECEIVED);
                    }
                    msgList.add(msg);
                    adapter.notifyItemInserted(msgList.size() - 1);//当有新消息时,刷新RecyclView中的显示
                    msgRecyclerView.scrollToPosition(msgList.size() - 1);//将RecyclerView定位到最后一行
                    inputTest.setText("");//清空输入框*/
                }
            }
        };

        //发送按钮监听器
        send.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View v){

                String content = inputTest.getText().toString();
                if(!"".equals(content)){
                    try {
                        //将输入框的信息传递给msg,并标记
                        Message handleMsg = new Message();
                        handleMsg.what = 1;
                        handleMsg.obj = inputTest.getText().toString();
                        //将msg传递给发送子线程
                        mClientThread.revHandler.sendMessage(handleMsg);
                        //输入框变空
                        inputTest.setText("");
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        });

        //创建实例,将mHandler作为参数传递给mClientThread实例
        mClientThread = new ClientThread(mHandler);
        //启动子线程
        new Thread(mClientThread).start();
    }
}
  • Msg中的代码
public class Msg {
    public static final int TYPE_RECEIVED = 0;//收到的消息
    public static final int TYPE_SENT = 1;//发出去的消息
    private String name;
    private String content;
    private int type;
    //content表示消息内容,type表示类型
    public Msg(String name,String content ,int type){
        this.name = name;
        this.content = content;
        this.type = type;
    }
    public String getContent(){
        return content;
    }
    public int getType(){
        return type;
    }
    public String getName() {return name;}
}
  • MsgAdapter中的代码
public class MsgAdapter extends RecyclerView.Adapter<MsgAdapter.ViewHolder>{
    private List mMsgList;
    //ViewHolder内部类
    static class ViewHolder extends RecyclerView.ViewHolder{
        LinearLayout leftLayout;
        LinearLayout rightLayout;
        TextView leftMsg;
        TextView rightMsg;
        TextView leftname;
        //构造方法
        public ViewHolder(View view){
            super(view);
            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);
            leftname = (TextView) view.findViewById(R.id.left_name);
        }
    }

    //MsgAdapter构造方法,参数是消息类的集合
    public MsgAdapter(List msgList){
        mMsgList = msgList;
    }

    @Override
    //创建ViewHolder实例
    public ViewHolder onCreateViewHolder(ViewGroup parent , int viewType){
        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_RECEIVED){
            //如果是收到的消息,则显示左边的消息布局,将右边的消息布局隐藏
            holder.leftLayout.setVisibility(View.VISIBLE);
            holder.rightLayout.setVisibility(View.GONE);
            holder.leftMsg.setText(msg.getContent());
            holder.leftname.setText(msg.getName());
        }else if(msg.getType()==Msg.TYPE_SENT){
            //如果是发出去的消息,则显示右边的消息布局,将左边的消息布局隐藏
            holder.rightLayout.setVisibility(View.VISIBLE);
            holder.leftLayout.setVisibility(View.GONE);
            holder.rightMsg.setText(msg.getContent());
        }
    }

    @Override
    public int getItemCount(){
        return mMsgList.size();
    }
}
  • msg_item.xml中的代码
<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="6dp">

    <LinearLayout
        android:id="@+id/left_layout"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        >
        <TextView
            android:id="@+id/left_name"
            android:layout_width="40dp"
            android:layout_height="match_parent"
            android:gravity="center"
            android:textSize="17sp"
            android:ellipsize="end"
            />

        <LinearLayout
            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="6dp"
                android:textColor="#fff"
                />
        LinearLayout>
    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_gravity="center"
            android:layout_margin="6dp"/>

    LinearLayout>

LinearLayout>
  • activity chatroom.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="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>

未完,后续关于网络编程部分见下一篇

你可能感兴趣的:(Android,应用层)