用sockets打造自己的Android聊天app(安卓篇)

用sockets打造自己的Android聊天app(安卓篇)

翻译自http://www.androidhive.info/2014/10/android-building-group-chat-app-using-sockets-part-2/

上一篇文章中我们介绍了web sockets,搭建好了web环境,这篇文章我们开始安卓app的开发。同web应用一样,有两个屏幕,第一个是输入名字,第二个就是显示和发送消息。OK,我们这次的开发环境依然是Eclipse IDE.

6 建立Android App

首先定义一下我们所用到的颜色res ⇒ values ⇒ colors.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="actionbar">#3cb879</color>
    <color name="body_background">#e8e8e8</color>
    <color name="body_background_green">#82e783</color>
    <color name="server_status_bar">#2b2b2b</color>
    <color name="title_gray">#434343</color>
    <color name="white">#ffffff</color>
    <color name="bg_msg_you">#5eb964</color>
    <color name="bg_msg_from">#e5e7eb</color>
    <color name="msg_border_color">#a1a1a1</color>
    <color name="bg_btn_join">#1e6258</color>
    <color name="bg_msg_input">#e8e8e8</color>
    <color name="text_msg_input">#626262</color>
    <color name="lblFromName">#777777</color>
</resources>

再定义我们所用到的字符串res ⇒ values ⇒ strings.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <string name="app_name">WebMobileGroupChat</string>
    <string name="title">(Android WebSockets Chat App)</string>
    <string name="author_name">By Ravi Tamada</string>
    <string name="author_url">www.androidhive.info</string>
    <string name="enter_name">Enter your name</string>
    <string name="btn_join">JOIN</string>
    <string name="btn_send">Send</string>

</resources>

再增加样式文件res ⇒ values ⇒ styles.xml

<resources>

    <style name="ChatAppTheme" parent="@android:style/Theme.Holo.Light">
        <item name="android:actionBarStyle">@style/MyActionBarTheme</item>
    </style>

    <style name="MyActionBarTheme" parent="@android:style/Widget.Holo.Light.ActionBar">
        <item name="android:background">@color/actionbar</item>
        <item name="android:titleTextStyle">@style/TitleTextStyle</item>
    </style>

     <style name="TitleTextStyle" parent="android:TextAppearance.Holo.Widget.ActionBar.Title">
        <item name="android:textColor">@color/white</item>
    </style>

</resources>

下面这个布局文件是第一个屏幕,让用户输入用户名:

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

    <ImageView
        android:id="@+id/imgLogo"
        android:layout_width="60dp"
        android:layout_height="60dp"
        android:layout_alignParentTop="true"
        android:layout_centerHorizontal="true"
        android:layout_gravity="center_horizontal"
        android:layout_marginBottom="10dp"
        android:layout_marginTop="60dp"
        android:src="@drawable/ic_launcher" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/imgLogo"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="15dp"
        android:text="@string/title"
        android:textColor="@color/white"
        android:textSize="13dp" />

    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:gravity="center_horizontal"
        android:orientation="vertical"
        android:padding="20dp" >

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginBottom="10dp"
            android:layout_marginTop="15dp"
            android:text="@string/enter_name"
            android:textColor="@color/white"
            android:textSize="18dp" />

        <EditText
            android:id="@+id/name"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_marginBottom="10dp"
            android:layout_marginTop="10dp"
            android:background="@color/white"
            android:inputType="textCapWords"
            android:padding="10dp" />

        <Button
            android:id="@+id/btnJoin"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="40dp"
            android:background="@color/bg_btn_join"
            android:paddingLeft="25dp"
            android:paddingRight="25dp"
            android:text="@string/btn_join"
            android:textColor="@color/white" />
    </LinearLayout>

    <!-- author info -->

    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_marginBottom="20dp"
        android:gravity="center_horizontal"
        android:orientation="vertical" >

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/author_name"
            android:textColor="@color/white"
            android:textSize="12dp" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/author_url"
            android:textColor="@color/white"
            android:textSize="12dp" />
    </LinearLayout>

</RelativeLayout>

下面是对应的Activity,很简单,就是传递数据
NameActivity.java


package info.androidhive.webgroupchat;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

public class NameActivity extends Activity {

    private Button btnJoin;
    private EditText txtName;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_name);

        btnJoin = (Button) findViewById(R.id.btnJoin);
        txtName = (EditText) findViewById(R.id.name);

        // Hiding the action bar
        getActionBar().hide();

        btnJoin.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                if (txtName.getText().toString().trim().length() > 0) {

                    String name = txtName.getText().toString().trim();

                    Intent intent = new Intent(NameActivity.this,
                            MainActivity.class);
                    intent.putExtra("name", name);

                    startActivity(intent);

                } else {
                    Toast.makeText(getApplicationContext(),
                            "Please enter your name", Toast.LENGTH_LONG).show();
                }
            }
        });
    }
}

不要忘记在清单文件中加上网络权限
在做完这些之后你的app应该是这样子
这里写图片描述

在实现sockets之前,我们还需要定义一些资源,用来显示聊天界面

下载background图片放到drawable目录下。

定义如下三个drawable文件,这些用作聊天的背景tile_bg.xml, bg_msg_from.xml and bg_msg_you.xml

tile_bg.xml
<?xml version="1.0" encoding="utf-8"?>
<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
  android:src="@drawable/bg_messages"
  android:tileMode="repeat" />
bg_msg_from.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle" >

    <!-- view background color -->
    <solid android:color="@color/bg_msg_from" >
    </solid>

    <corners android:radius="5dp" >
    </corners>

</shape>
bg_msg_you.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle" >

    <!-- view background color -->
    <solid android:color="@color/bg_msg_you" >
    </solid>

    <corners android:radius="5dp" >
    </corners>

</shape>

然后我们在定义两个布局文件,分别是聊天的条目(自己的和别人的)

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

    <TextView
        android:id="@+id/lblMsgFrom"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="12dp"
        android:textColor="@color/lblFromName"
        android:textStyle="italic"
        android:padding="5dp"/>

    <TextView
        android:id="@+id/txtMsg"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="16dp"
        android:layout_marginRight="80dp"
        android:textColor="@color/title_gray"
        android:paddingLeft="10dp"
        android:paddingRight="10dp"
        android:paddingTop="5dp"
        android:paddingBottom="5dp"
        android:background="@drawable/bg_msg_from"/>

</LinearLayout>
list_item_message_right.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="right"
    android:orientation="vertical"
    android:paddingBottom="5dp"
    android:paddingRight="10dp"
    android:paddingTop="5dp" >

    <TextView
        android:id="@+id/lblMsgFrom"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:padding="5dp"
        android:textColor="@color/lblFromName"
        android:textSize="12dp"
        android:textStyle="italic" />

    <TextView
        android:id="@+id/txtMsg"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="80dp"
        android:background="@drawable/bg_msg_you"
        android:paddingBottom="5dp"
        android:paddingLeft="10dp"
        android:paddingRight="10dp"
        android:paddingTop="5dp"
        android:textColor="@color/white"
        android:textSize="16dp" />

</LinearLayout>

接下来的这个布局文件就是我们聊天的主界面

activity_main.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="@drawable/tile_bg"
    android:orientation="vertical" >

    <ListView
        android:id="@+id/list_view_messages"
        android:layout_width="fill_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:background="@null"
        android:divider="@null"
        android:transcriptMode="alwaysScroll"
        android:stackFromBottom="true">
    </ListView>

    <LinearLayout
        android:id="@+id/llMsgCompose"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:background="@color/white"
        android:orientation="horizontal"
        android:weightSum="3" >

        <EditText
            android:id="@+id/inputMsg"
            android:layout_width="0dp"
            android:layout_height="fill_parent"
            android:layout_weight="2"
            android:background="@color/bg_msg_input"
            android:textColor="@color/text_msg_input"
            android:paddingLeft="6dp"
            android:paddingRight="6dp"/>

        <Button
            android:id="@+id/btnSend"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:background="@color/bg_btn_join"
            android:textColor="@color/white"
            android:text="@string/btn_send" />
    </LinearLayout>

</LinearLayout>

接下来是两个帮助类,第一个Utils类有两个功能,第一个是存储Session id,第二个就是把消息转换成一个JSON字符串,如下

Utils.java
package info.androidhive.webgroupchat.other;

import org.json.JSONException;
import org.json.JSONObject;

import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;

public class Utils {

    private Context context;
    private SharedPreferences sharedPref;

    private static final String KEY_SHARED_PREF = "ANDROID_WEB_CHAT";
    private static final int KEY_MODE_PRIVATE = 0;
    private static final String KEY_SESSION_ID = "sessionId",
            FLAG_MESSAGE = "message";

    public Utils(Context context) {
        this.context = context;
        sharedPref = this.context.getSharedPreferences(KEY_SHARED_PREF,
                KEY_MODE_PRIVATE);
    }

    public void storeSessionId(String sessionId) {
        Editor editor = sharedPref.edit();
        editor.putString(KEY_SESSION_ID, sessionId);
        editor.commit();
    }

    public String getSessionId() {
        return sharedPref.getString(KEY_SESSION_ID, null);
    }

    public String getSendMessageJSON(String message) {
        String json = null;

        try {
            JSONObject jObj = new JSONObject();
            jObj.put("flag", FLAG_MESSAGE);
            jObj.put("sessionId", getSessionId());
            jObj.put("message", message);

            json = jObj.toString();
        } catch (JSONException e) {
            e.printStackTrace();
        }

        return json;
    }

}

下面是JavaBean对象

Message.java
package info.androidhive.webgroupchat.other;

public class Message {
    private String fromName, message;
    private boolean isSelf;

    public Message() {
    }

    public Message(String fromName, String message, boolean isSelf) {
        this.fromName = fromName;
        this.message = message;
        this.isSelf = isSelf;
    }

    public String getFromName() {
        return fromName;
    }

    public void setFromName(String fromName) {
        this.fromName = fromName;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public boolean isSelf() {
        return isSelf;
    }

    public void setSelf(boolean isSelf) {
        this.isSelf = isSelf;
    }

}

下面这个类是配置对象

WsConfig.java
package info.androidhive.webgroupchat.other;

public class WsConfig {
    public static final String URL_WEBSOCKET = "ws://192.168.0.102:8080/WebMobileGroupChatServer/chat?name=";
}

下面这个是ListView的适配器,主要就是判断是自己的消息还是别人的消息,在getView中分别填充

package info.androidhive.webgroupchat;

import info.androidhive.webgroupchat.other.Message;

import java.util.List;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;

public class MessagesListAdapter extends BaseAdapter {

    private Context context;
    private List<Message> messagesItems;

    public MessagesListAdapter(Context context, List<Message> navDrawerItems) {
        this.context = context;
        this.messagesItems = navDrawerItems;
    }

    @Override
    public int getCount() {
        return messagesItems.size();
    }

    @Override
    public Object getItem(int position) {
        return messagesItems.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @SuppressLint("InflateParams")
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {

        /**
         * The following list not implemented reusable list items as list items
         * are showing incorrect data Add the solution if you have one
         * */

        Message m = messagesItems.get(position);

        LayoutInflater mInflater = (LayoutInflater) context
                .getSystemService(Activity.LAYOUT_INFLATER_SERVICE);

        // Identifying the message owner
        if (messagesItems.get(position).isSelf()) {
            // message belongs to you, so load the right aligned layout
            convertView = mInflater.inflate(R.layout.list_item_message_right,
                    null);
        } else {
            // message belongs to other person, load the left aligned layout
            convertView = mInflater.inflate(R.layout.list_item_message_left,
                    null);
        }

        TextView lblFrom = (TextView) convertView.findViewById(R.id.lblMsgFrom);
        TextView txtMsg = (TextView) convertView.findViewById(R.id.txtMsg);

        txtMsg.setText(m.getMessage());
        lblFrom.setText(m.getFromName());

        return convertView;
    }
}

下载android websockets library,感谢 Koush大神

将下载的代码导入到eclipse中,并且在自己的项目中引用它
这里写图片描述

开始最重要的了。。。。

同js代码作为sockets客户端类似,WebSocketClient 也有一些回调函数,onConnect, onMessage and onDisconnect.

parseMessage() 函数用作解析从server中获得的Json字符串

在parseMessage()方法中,json的目的有flag表示

当新的消息收到时,要调用adapter.notifyDataSetChanged() 方法去更新列表

sendMessageToServer()发送到服务器

playBeep() 播放声音

package info.androidhive.webgroupchat;

import info.androidhive.webgroupchat.other.Message;
import info.androidhive.webgroupchat.other.Utils;
import info.androidhive.webgroupchat.other.WsConfig;

import java.net.URI;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

import org.json.JSONException;
import org.json.JSONObject;

import android.app.Activity;
import android.content.Intent;
import android.media.Ringtone;
import android.media.RingtoneManager;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.Toast;

import com.codebutler.android_websockets.WebSocketClient;

public class MainActivity extends Activity {

    // LogCat tag
    private static final String TAG = MainActivity.class.getSimpleName();

    private Button btnSend;
    private EditText inputMsg;

    private WebSocketClient client;

    // Chat messages list adapter
    private MessagesListAdapter adapter;
    private List<Message> listMessages;
    private ListView listViewMessages;

    private Utils utils;

    // Client name
    private String name = null;

    // JSON flags to identify the kind of JSON response
    private static final String TAG_SELF = "self", TAG_NEW = "new",
            TAG_MESSAGE = "message", TAG_EXIT = "exit";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        btnSend = (Button) findViewById(R.id.btnSend);
        inputMsg = (EditText) findViewById(R.id.inputMsg);
        listViewMessages = (ListView) findViewById(R.id.list_view_messages);

        utils = new Utils(getApplicationContext());

        // 从上一个屏幕获取姓名
        Intent i = getIntent();
        name = i.getStringExtra("name");

        btnSend.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                // Sending message to web socket server
                sendMessageToServer(utils.getSendMessageJSON(inputMsg.getText()
                        .toString()));

                // Clearing the input filed once message was sent
                inputMsg.setText("");
            }
        });

        listMessages = new ArrayList<Message>();

        adapter = new MessagesListAdapter(this, listMessages);
        listViewMessages.setAdapter(adapter);

        /**
         * 创建web sockets客户端,有如下的回调函数
         * */
        client = new WebSocketClient(URI.create(WsConfig.URL_WEBSOCKET
                + URLEncoder.encode(name)), new WebSocketClient.Listener() {
            @Override
            public void onConnect() {

            }

            /**
             * 从服务端接受消息
             * */
            @Override
            public void onMessage(String message) {
                Log.d(TAG, String.format("Got string message! %s", message));

                parseMessage(message);

            }

            @Override
            public void onMessage(byte[] data) {
                Log.d(TAG, String.format("Got binary message! %s",
                        bytesToHex(data)));

                // Message will be in JSON format
                parseMessage(bytesToHex(data));
            }

            /**
             * 连接中断
             * */
            @Override
            public void onDisconnect(int code, String reason) {

                String message = String.format(Locale.US,
                        "Disconnected! Code: %d Reason: %s", code, reason);

                showToast(message);

                // clear the session id from shared preferences
                utils.storeSessionId(null);
            }

            @Override
            public void onError(Exception error) {
                Log.e(TAG, "Error! : " + error);

                showToast("Error! : " + error);
            }

        }, null);

        client.connect();
    }

    /**
     * 发送消息
     * */
    private void sendMessageToServer(String message) {
        if (client != null && client.isConnected()) {
            client.send(message);
        }
    }

    /**
     * 解析从服务端收到的json 消息的目的由flag字段所指定,flag=self,消息属于指定的人,
     * new:新人加入   *    到对话中,message:新的消息,exit:退出
     * 
     *
     * 
     * 
     * */
    private void parseMessage(final String msg) {

        try {
            JSONObject jObj = new JSONObject(msg);

            // JSON node 'flag'
            String flag = jObj.getString("flag");

            // 如果是self,json中包含sessionId信息
            if (flag.equalsIgnoreCase(TAG_SELF)) {

                String sessionId = jObj.getString("sessionId");

                // Save the session id in shared preferences
                utils.storeSessionId(sessionId);

                Log.e(TAG, "Your session id: " + utils.getSessionId());

            } else if (flag.equalsIgnoreCase(TAG_NEW)) {
                // If the flag is 'new', new person joined the room
                String name = jObj.getString("name");
                String message = jObj.getString("message");

                // number of people online
                String onlineCount = jObj.getString("onlineCount");

                showToast(name + message + ". Currently " + onlineCount
                        + " people online!");

            } else if (flag.equalsIgnoreCase(TAG_MESSAGE)) {
                // if the flag is 'message', new message received
                String fromName = name;
                String message = jObj.getString("message");
                String sessionId = jObj.getString("sessionId");
                boolean isSelf = true;

                // Checking if the message was sent by you
                if (!sessionId.equals(utils.getSessionId())) {
                    fromName = jObj.getString("name");
                    isSelf = false;
                }

                Message m = new Message(fromName, message, isSelf);

                // 把消息加入到arraylist中
                appendMessage(m);

            } else if (flag.equalsIgnoreCase(TAG_EXIT)) {
                // If the flag is 'exit', somebody left the conversation
                String name = jObj.getString("name");
                String message = jObj.getString("message");

                showToast(name + message);
            }

        } catch (JSONException e) {
            e.printStackTrace();
        }

    }

    @Override
    protected void onDestroy() {
        super.onDestroy();

        if(client != null & client.isConnected()){
            client.disconnect();
        }
    }

    /**
     * 把消息放到listView里
     * */
    private void appendMessage(final Message m) {
        runOnUiThread(new Runnable() {

            @Override
            public void run() {
                listMessages.add(m);

                adapter.notifyDataSetChanged();

                // Playing device's notification
                playBeep();
            }
        });
    }

    private void showToast(final String message) {

        runOnUiThread(new Runnable() {

            @Override
            public void run() {
                Toast.makeText(getApplicationContext(), message,
                        Toast.LENGTH_LONG).show();
            }
        });

    }

    /**
     * 播放默认的通知声音
     * */
    public void playBeep() {

        try {
            Uri notification = RingtoneManager
                    .getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
            Ringtone r = RingtoneManager.getRingtone(getApplicationContext(),
                    notification);
            r.play();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    final protected static char[] hexArray = "0123456789ABCDEF".toCharArray();

    public static String bytesToHex(byte[] bytes) {
        char[] hexChars = new char[bytes.length * 2];
        for (int j = 0; j < bytes.length; j++) {
            int v = bytes[j] & 0xFF;
            hexChars[j * 2] = hexArray[v >>> 4];
            hexChars[j * 2 + 1] = hexArray[v & 0x0F];
        }
        return new String(hexChars);
    }

}

最终结果应该是这样的

这里写图片描述

这里写图片描述

  • 17
    点赞
  • 90
    收藏
    觉得还不错? 一键收藏
  • 16
    评论
很高兴能为您解答这个问题。以下是一个简单的Android聊天应用程序的代码,使用Sockets实现: 1. 创建项目并添加依赖项: ``` dependencies { implementation 'androidx.appcompat:appcompat:1.2.0' implementation 'androidx.constraintlayout:constraintlayout:2.0.4' } ``` 2. 创建界面布局文件: activity_main.xml ``` <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <EditText android:id="@+id/editText" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:ems="10" /> <Button android:id="@+id/sendButton" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignBottom="@+id/editText" android:layout_alignParentEnd="true" android:text="Send" /> <ScrollView android:id="@+id/scrollView" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_above="@id/editText"> <TextView android:id="@+id/textView" android:layout_width="match_parent" android:layout_height="wrap_content" /> </ScrollView> </RelativeLayout> ``` 3. 创建后台线程和Socket: MainActivity.java ``` import androidx.appcompat.app.AppCompatActivity; import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.ScrollView; import android.widget.TextView; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.Socket; public class MainActivity extends AppCompatActivity { private Socket socket; private PrintWriter printWriter; private BufferedReader bufferedReader; private TextView textView; private EditText editText; private Button sendButton; private ScrollView scrollView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); textView = findViewById(R.id.textView); editText = findViewById(R.id.editText); sendButton = findViewById(R.id.sendButton); scrollView = findViewById(R.id.scrollView); new Thread(new Runnable() { @Override public void run() { try { socket = new Socket("your_server_ip_address", 1234); printWriter = new PrintWriter(socket.getOutputStream(), true); bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream())); Handler handler = new Handler(Looper.getMainLooper()) { @Override public void handleMessage(Message message) { textView.append(message.obj.toString()); scrollView.fullScroll(View.FOCUS_DOWN); } }; String line; while ((line = bufferedReader.readLine()) != null) { Message message = new Message(); message.obj = line + "\n"; handler.sendMessage(message); } } catch (IOException e) { e.printStackTrace(); } } }).start(); sendButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { String message = editText.getText().toString(); editText.setText(""); printWriter.println(message); } }); } @Override protected void onDestroy() { super.onDestroy(); try { socket.close(); } catch (IOException e) { e.printStackTrace(); } } } ``` 注意替换 `your_server_ip_address` 为您的服务器IP地址。 4. 启动服务器并测试应用程序: 使用另一个设备或模拟器作为服务器,并在运行之前启动服务器。启动应用程序并测试聊天功能。 希望这可以帮助您开始使用Sockets构建Android聊天应用程序。
评论 16
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值