你好!这里是风筝的博客,
欢迎和我一起交流。
前几天在我的群里发现好多群友在弄ESP-8266这款wifi模块,想起当初我在玩这个模块时想自己做一个手机app上位机,趁着清明放假,就把这个app做出来吧。(java没怎么学过,Android只会简单的拖拖控件,这个app还是挺捉急的......)
先看下UI的源码。
这是activity_main.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:weightSum="1">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<EditText
android:layout_width="0dp"
android:layout_weight="1.5"
android:layout_height="match_parent"
android:layout_gravity="right"
android:textSize="21dp"
android:hint="Addr IP"
android:inputType="textUri"
android:id="@+id/ip" />
<EditText
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_gravity="left"
android:textSize="21dp"
android:hint="Port"
android:inputType="number"
android:id="@+id/port" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:weightSum="1">
<Button
android:id="@+id/Connet"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Connet"
android:layout_gravity="left"
android:layout_marginLeft="30dp"
android:layout_weight="0.4" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="0.4"
android:id="@+id/textView" />
<Button
android:id="@+id/Close"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Close"
android:layout_marginRight="50dp"
android:layout_weight="0.4" />
</LinearLayout>
<TextView
android:layout_width="85dp"
android:layout_height="wrap_content"
android:layout_marginLeft="12dp"
android:textSize="20dp"
android:text="数据接收:"
android:id="@+id/textView2"
android:layout_weight="0.08" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<EditText
android:layout_width="0dp"
android:layout_height="150dp"
android:layout_marginLeft="10dp"
android:gravity="top|left"
android:layout_weight="1.5"
android:background="@drawable/edit"
android:id="@+id/Receive" />
<Button
android:id="@+id/Clear"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="Clean"
android:layout_gravity="bottom"
android:layout_weight="0.3" />
</LinearLayout>
<EditText
android:id="@+id/message"
android:inputType="textUri"
android:layout_width="205dp"
android:layout_height="wrap_content"
android:hint="Message" />
<Button
android:id="@+id/send"
android:layout_width="135dp"
android:layout_height="wrap_content"
android:text="Send"
android:layout_gravity="center_horizontal"
android:layout_weight="0.04" />
<TextView
android:layout_width="104dp"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:inputType="textPersonName"
android:text="By_风筝"
android:ems="10"
android:id="@+id/editText"
android:layout_weight="0.05" />
</LinearLayout>
laylout布局,虽然有点难看,勉勉强强使用吧。其中
android:background="@drawable/edit"
这句,在drawable下新建edit.xml文件,在里面写下:
<?xml version="1.0" encoding="utf-8"?>
<layer-list
xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid
android:color="#EFEFEF"/>
<corners
android:radius="3dip"
/>
<stroke
android:width="0.5px"
android:color="#505050"/>
</shape>
</item>
</layer-list>
以上就是UI的布局了。
接下来看程序,最重要的就是socket通信了:
package com.example.tao.esp;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
public class MainActivity extends Activity implements OnClickListener {//, Runnable
private EditText editText_ip;
private EditText editText_port;
private EditText editText_receive;
private EditText editText_message;
private Socket socket;
private PrintWriter pw;
private BufferedReader br;
private String IP = "192.168.23.2";
private int Port = 5000;
public String rxd;
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case 0x10:
Toast.makeText(getApplicationContext(), "连接成功", Toast.LENGTH_LONG).show();
break;
case 0x11:
editText_receive.setText(editText_receive.getText().toString() + rxd + "\n");
editText_receive.setSelection(editText_receive.getText().length()-1);
Log.e("editText:", "rxd");
break;
case 0x12:
editText_receive.setText("");
break;
}
}
};
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button_send = (Button) findViewById(R.id.send);
button_send.setOnClickListener(this);
Button button_conect = (Button) findViewById(R.id.Connet);
button_conect.setOnClickListener(this);
Button button_close = (Button) findViewById(R.id.Close);
button_close.setOnClickListener(this);
Button button_clean = (Button) findViewById(R.id.Clear);
button_clean.setOnClickListener(this);
editText_ip = (EditText) findViewById(R.id.ip);
editText_port = (EditText) findViewById(R.id.port);
editText_receive = (EditText) findViewById(R.id.Receive);
editText_message = (EditText) findViewById(R.id.message);
}
public void onClick(View view) {
switch (view.getId()) {
case R.id.send:
String str;
str = editText_message.getText().toString();
pw.println(str);
pw.flush();
break;
case R.id.Connet:
IP = editText_ip.getText().toString();
Port = Integer.parseInt(editText_port.getText().toString());
new Thread() {
public void run() {
try {
socket = new Socket(IP, Port);
} catch (IOException e) {
e.printStackTrace();
}
if (socket == null) {
Log.e("socket", "null");
} else {
try {
br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
pw = new PrintWriter(socket.getOutputStream());
if (pw != null && br != null) {
handler.sendEmptyMessage(0x10);
Log.e("接收到:", "成功");
}
} catch (IOException e) {
e.printStackTrace();
}
while (true) {
try {
while ((rxd = br.readLine()) != null) {
handler.sendEmptyMessage(0x11);
Log.e("接收到:", rxd);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
;
}.start();
break;
case R.id.Clear:
handler.sendEmptyMessage(0x12);
break;
case R.id.Close:
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
break;
}
}
}
这里我们一开始new了message,因为手机接受来自服务器的消息的程序写在了一个子线程,子线程里不能更改UI,所以用handler和主线程通信刷新UI。onclick里写了三个buttun的事件,第一为发送,第二为建立socket通信,值得注意的是,readline()是一个阻塞函数,除非接受到带回车键的消息或者数据流中断,才会有返回值。其他的没什么要说的了,都是调用一些函数,百度一下就能知道这个函数的作用。不过最后想说的是,子线程里最好不要用toast,这个可把我害惨了......
好了,这就是安卓手机作为Client的源码,Server我用的网络调试助手,记得先把电脑防火墙关掉,而且手机和电脑在同一个局域网,如果没有网络调试助手的话,可以再写一个Server的app,就是这个程序把连接socket的代码改成开启socket并且监听某个端口即可。
忘了说了,记得要加上网络权限,在AndroidManifest.xml这个文件里加上:
<uses-permission android:name="android.permission.INTERNET" />即可
by 风筝
2017.4.5