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中的代码
<?xml version="1.0" encoding="utf-8"?><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
<?xml version="1.0" encoding="utf-8"?><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>

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

更多相关文章

  1. 【移动开发】Android应用程序中实用的代码框架(一)
  2. android:scaleType="matrix"布局文件加载图片时候的显示方式
  3. android Matrix处理图片原理及方法整理
  4. android的消息处理机制(图文+源码分析)—Looper/Handler/Message
  5. 聊一聊Android的消息机制
  6. 我的Android NDK之旅(五),在Mac上用eclipse手动编写代码向android开
  7. cocos2d-x集成友盟消息推送SDK(Android版)
  8. Android消息推送完美方案

随机推荐

  1. Android(安卓)O 8.0及其以上系统的通知(N
  2. android 窗口背景透明方法
  3. Google操作系统是经典骗局?
  4. android ViewPager动态加载问题
  5. Android(安卓)开发学习手记(三):关于PullToR
  6. Android程序退出彻底关闭进程的方法
  7. Android(安卓)Handler 泄漏
  8. 手机rom的那些坑
  9. Android使用外部字体
  10. android 手机屏幕密度等级和屏幕逻辑尺寸