杰瑞科技汇

Android Socket Java如何实现高效通信?

Of course! Here is a comprehensive guide to using Java Sockets in Android, covering the basics, a practical example (a simple chat app), and crucial considerations for the Android platform.

Android Socket Java如何实现高效通信?-图1
(图片来源网络,侵删)

Understanding the Basics: TCP vs. UDP

When we talk about "Sockets" in networking, we're usually referring to one of two protocols:

  • TCP (Transmission Control Protocol):

    • Analogy: A phone call. You establish a connection, talk, and then hang up.
    • Characteristics: Connection-oriented, reliable, ordered, and error-checked. It's great for when you need to ensure all data arrives correctly (e.g., file transfer, web browsing, chat messages).
    • Classes in Java: Socket (client), ServerSocket (server).
  • UDP (User Datagram Protocol):

    • Analogy: Sending a postcard. You send it, but you don't know if or when it will arrive.
    • Characteristics: Connectionless, fast, but unreliable and unordered. It's great for real-time applications where speed is more important than perfect accuracy (e.g., video streaming, online gaming, VoIP).
    • Classes in Java: DatagramSocket, DatagramPacket.

For this guide, we'll focus on TCP, as it's the most common starting point.

Android Socket Java如何实现高效通信?-图2
(图片来源网络,侵删)

Key Considerations for Android

Using sockets on Android has some unique requirements compared to a standard Java application.

a. Network Permissions

Your app must explicitly declare that it needs internet access. Add this to your AndroidManifest.xml:

<manifest ...>
    <uses-permission android:name="android.permission.INTERNET" />
    <application ...>
        ...
    </application>
</manifest>

b. Performing Network Operations on a Background Thread

This is the most critical rule. You cannot perform network operations (like opening a socket or reading/writing data) on the main UI thread. Doing so will result in a NetworkOnMainThreadException and will likely make your app unresponsive.

The standard way to handle this is with an AsyncTask, Thread, Handler, or, more modernly, a Coroutine (if using Kotlin) or ExecutorService (in Java).

Android Socket Java如何实现高效通信?-图3
(图片来源网络,侵删)

c. Android's Battery Optimization (Doze Mode)

Since Android 6.0 (Marshmallow), the OS aggressively tries to save battery. In "Doze" mode, network access is severely restricted. For a persistent socket connection (like a chat app), you need to handle this.

  • Foreground Service: If your app needs to maintain a socket connection while in the background, you should run it as a Foreground Service. This makes the service a high-priority task and prevents the system from killing it during Doze mode. A Foreground Service must show a persistent notification.

Practical Example: Simple Client-Server Chat App

Let's build a simple chat application. We'll have a server that echoes back any message it receives and a client that can send messages and display received ones.

Part 1: The Server (Standard Java Application)

The server is best run on a regular computer or a cloud server (like AWS, Google Cloud, or Heroku). It's not an Android app.

Server.java

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Server {
    private static final int PORT = 12345;
    private static List<ClientHandler> clients = new ArrayList<>();
    private static ExecutorService pool = Executors.newFixedThreadPool(10);
    public static void main(String[] args) throws IOException {
        try (ServerSocket serverSocket = new ServerSocket(PORT)) {
            System.out.println("Server is listening on port " + PORT);
            while (true) {
                Socket clientSocket = serverSocket.accept();
                System.out.println("New client connected: " + clientSocket.getInetAddress().getHostAddress());
                ClientHandler clientThread = new ClientHandler(clientSocket);
                clients.add(clientThread);
                pool.execute(clientThread);
            }
        }
    }
    // This inner class handles communication with a single client
    static class ClientHandler implements Runnable {
        private Socket clientSocket;
        private PrintWriter out;
        private BufferedReader in;
        public ClientHandler(Socket socket) {
            this.clientSocket = socket;
        }
        @Override
        public void run() {
            try {
                out = new PrintWriter(clientSocket.getOutputStream(), true);
                in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
                String inputLine;
                while ((inputLine = in.readLine()) != null) {
                    System.out.println("Received from client: " + inputLine);
                    // Echo the message back to the client
                    out.println("Server: " + inputLine);
                    // Broadcast to all other clients (optional for a real chat app)
                    // for (ClientHandler client : clients) {
                    //     if (client != this) {
                    //         client.out.println("Client says: " + inputLine);
                    //     }
                    // }
                }
            } catch (IOException e) {
                System.out.println("Error handling client: " + e.getMessage());
            } finally {
                try {
                clientSocket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                clients.remove(this);
            }
        }
    }
}

Part 2: The Android Client (App)

This will be a simple Android app with an EditText to type messages and a TextView to display the chat log.

Step 1: Layout (activity_main.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:orientation="vertical"
    android:padding="16dp"
    tools:context=".MainActivity">
    <TextView
        android:id="@+id/statusTextView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Status: Disconnected"
        android:textSize="18sp"
        android:textStyle="bold"/>
    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1">
        <TextView
            android:id="@+id/chatTextView"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Chat will appear here..."
            android:textSize="16sp"/>
    </ScrollView>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">
        <EditText
            android:id="@+id/messageEditText"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:hint="Type a message"/>
        <Button
            android:id="@+id/sendButton"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Send" />
    </LinearLayout>
</LinearLayout>

Step 2: The Java Code (MainActivity.java)

We'll use an ExecutorService to manage our background thread.

import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class MainActivity extends AppCompatActivity {
    private TextView chatTextView, statusTextView;
    private EditText messageEditText;
    private Button sendButton;
    // Network components
    private Socket socket;
    private PrintWriter out;
    private BufferedReader in;
    // Threading
    private ExecutorService executorService;
    private Handler mainHandler; // To update UI from the background thread
    // Server details (replace with your server's IP address)
    private static final String HOST = "10.0.2.2"; // Special IP for localhost from emulator
    // private static final String HOST = "YOUR_SERVER_IP"; // For a real device
    private static final int PORT = 12345;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        chatTextView = findViewById(R.id.chatTextView);
        statusTextView = findViewById(R.id.statusTextView);
        messageEditText = findViewById(R.id.messageEditText);
        sendButton = findViewById(R.id.sendButton);
        executorService = Executors.newSingleThreadExecutor();
        mainHandler = new Handler(Looper.getMainLooper());
        sendButton.setOnClickListener(v -> {
            String message = messageEditText.getText().toString();
            if (!message.isEmpty()) {
                sendMessage(message);
                messageEditText.setText("");
            }
        });
        // Connect to the server in the background
        executorService.execute(this::connectToServer);
    }
    private void connectToServer() {
        try {
            statusTextView.setText("Connecting...");
分享:
扫描分享到社交APP
上一篇
下一篇