在 Android 中进行套接字编程的两个问题

5

我在互联网上找到了一些套接字编程的例子,并尝试为以太网启用的Arduino服务器构建自己的Android客户端。但我遇到了两个问题。 首先,我的主要活动代码:

package com.domiflichi.TesterProject;

import java.io.BufferedWriter; // output
import java.io.BufferedReader; // input
import java.io.InputStreamReader; // input
import java.io.OutputStreamWriter; // output
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.Socket;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;

import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;







public class TesterProjectMain extends Activity implements OnClickListener
{

private Button connectPhones;

private TextView myTextView; // represents the 'status text'

private String serverIpAddress = "";

private boolean connected = false;


private Handler handler = new Handler();

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


connectPhones = (Button) findViewById(R.id.connect_phones);

connectPhones.setOnClickListener(connectListener);
connectPhones.setOnClickListener(this);



myTextView = (TextView) findViewById(R.id.text1);

}



// This was created when using the 'implements OnClickListener' in the class
public void onClick(View v) {
if (v.getId() == R.id.connect_phones) {
if (!connected) {
serverIpAddress = "192.168.0.178";
if (!serverIpAddress.equals("")) {
Thread cThread = new Thread(new ClientThread());
cThread.start();
connectPhones.setEnabled(false); // Once the button is pressed, disable it. :)
}
}

} else if (v.getId() == R.id.status_req) {
// CODE HERE FOR STATUS REQUEST BUTTON?

} else if (v.getId() == R.id.cmd_toggle) {
// CODE HERE FOR TOGGLE DOOR BUTTON?

} else if (v.getId() == R.id.cmd_crack) {
// CODE HERE FOR CRACK BUTTON?

} else if (v.getId() == R.id.disconnect) {
// CODE HERE FOR DISCONNECT BUTTON?

}
}





public class ClientThread implements Runnable {

public void run() {
try {
InetAddress serverAddr = InetAddress.getByName(serverIpAddress);
Log.d("ClientActivity", "C: Connecting...");
Socket socket = new Socket(serverAddr, 23);
connected = true;

while (connected) {
try {
Log.d("ClientActivity", "C: Sending command.");
PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())), true);
out.println("mypass*");
Log.d("ClientActivity", "C: Sent.");





BufferedReader r = new BufferedReader(new InputStreamReader(socket.getInputStream()));
final StringBuilder total = new StringBuilder();
String line;
while ((line = r.readLine()) != null) {
total.append(line);
Log.d("Server response", line.toString());

}





handler.post(new Runnable() {
public void run() {


if (total.toString().contentEquals("status:open")) {

myTextView.setText(R.string.status_open);
} else {
myTextView.setText(R.string.status_closed);
}

}
});







connected = false;

} catch (Exception e) {
Log.e("ClientActivity", "S: Error", e);
}

}


socket.close();
Log.d("ClientActivity", "C: Closed.");


} catch (Exception e) {
Log.e("ClientActivity", "C: Error", e);
connected = false;
}
}
}
}

我的两个问题是:
  1. 我不知道如何使我的按钮与发送命令到服务器的套接字进行交互。连接后,我有(4)个按钮需要通过套接字发送各种命令(套接字在通过单击“连接”按钮启动的单独线程中运行)。 (寻找“// CODE HERE FOR STATUS REQUEST BUTTON?”评论,以了解我期望放置各种按钮代码的位置)
  2. 我需要将

    'handler.post(new Runnable() {'

代码块移至我的主循环中:
(while ((line = r.readLine()) != null) {
total.append(line);
Log.d("Server response", line.toString());
}

然而,当我这样做时,并且改变:

if (total.toString().contentEquals("status:open")) {

if (line.toString().contentEquals("status:open")) {

(因为我只想一次读取一行) Eclipse报错如下: 无法引用在不同方法中定义的内部类中的非最终变量行。
如果我尝试更改上面的行...: String line; 到 static String line;
Eclipse会在下一行报错:
while ((line = r.readLine()) != null) { 说: 最终局部变量行可能已经被分配。
我甚至不敢相信我已经走了这么远,因为我是一个完全的新手,但现在我遇到了难题。
1个回答

2
对于您的第二个问题:创建一个新的final,以在可运行对象中使用。
while ((line = r.readLine()) != null) {
    total.append(line);
    Log.d("Server response", line.toString());
    final String status = line;
    handler.post(new Runnable() {
        public void run() {
            if (status.contentEquals("status:open")) {
                myTextView.setText(R.string.status_open);
            } else {
                myTextView.setText(R.string.status_closed);
            }
        }
    });
}

对于你的第一个问题:

你选择了一个相当复杂的任务。你的线程需要检查一些由外部设置的条件,以便线程可以决定接下来要做什么。从这些按钮中,你可以更改例如AtomicInteger,如果没有任何事情要做,则为0,如果你想打开灯,则为1,2等等。

您的Thread将检查该值,将其重置为0(在一个.getAndSet(0)中),然后执行它应该执行的操作。

编辑:它看起来是这样的

这就是线程

public class LoopingNetworkThread extends Thread {
    public static final int TASK_END = -1;
    public static final int TASK_NOOP = 0;
    public static final int TASK_LIGHTS_ON = 1;
    public static final int TASK_LIGHTS_OFF = 2;

    private final AtomicInteger mNextTask = new AtomicInteger(0);

    /* Executed in this threads context */
    @Override
    public void run() {
        openSocket();
        int currentTask;
        while ((currentTask = mNextTask.getAndSet(TASK_NOOP)) != TASK_END) {
            switch (currentTask) {
                case TASK_LIGHTS_ON:
                    sendLightsOn();
                    break;
                case TASK_LIGHTS_OFF:
                    sendLightsOff();
                    break;
                default:
                    keepAlive();
                    break;
            }
            // depending on your requirements sleep some time inbetween.
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                // ignore
            }
        }
        // the while ends once you set task to TASK_END
        closeSocket();
    }

    private void openSocket() {  }
    private void closeSocket() {  }
    private void keepAlive() {  }
    private void sendLightsOn() {  }
    private void sendLightsOff() {  }

    /* Executed in a different thread context */
    public int setNextTask(int task){
        // return what we overwrite here, maybe that is useful.
        return mNextTask.getAndSet(task);
    }
}

你的活动

public class YourActivity extends Activity {
    private LoopingNetworkThread mThread;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        mThread = new LoopingNetworkThread();
        View startButton = findViewById(R.id.button1);
        View stopButton = findViewById(R.id.button2);
        startButton.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                mThread.start();
            }
        });
        stopButton.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                mThread.setNextTask(LoopingNetworkThread.TASK_END);
            }
        });
    }
}

谢谢你的回复。第一个问题已解决,没有其他问题了。谢谢。 - Domiflichi
对于我的第二个问题,感谢您提供的想法/解决方案。我正在尝试实现AtomicInteger,但我认为我做错了什么。很抱歉,这个评论框不太友好...我将使用“回答您的问题”链接。 - Domiflichi
这并不是一个不友好的评论 :) 请看编辑部分,或许能更好地解释一下。 - zapl
嗨@zapl,你指的是什么?嘿,看起来我的原始帖子被@Lucifer编辑了?为什么?都编辑了些什么?我还有一个新问题...请看下面我最新的帖子。 - Domiflichi
哦,好的,但我只是想知道为什么你说“那不是一个不友好的评论”...我对这个论坛还很新,希望我没有点击什么东西给你带来了负面的“反馈”。;) - Domiflichi
显示剩余7条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接