/*************************************************************************************************
PROJECT: wifi遥控小车
HARDWARE: STC89C52RC单机, L239D直流电机驱动器, ESP8266安信可wifi模块
SOFTWARE: Eclipse安卓开发环境
AUTHOR: DDDDD
DATE: 2014-12-5
*************************************************************************************************/
这个小项目有软件和硬件两大块,这里主要阐述在开发android客户端中遇到的问题
1、需要几个普通的Button,控制前进后退等。
findViewById()这个函数将定义的button变量和xml文件中的button控件绑定起来
upBtn = (Button)findViewById(R.id.upbtn);
setOnClickListener()为button控件添加监听器,这样button被按下后监听器就会执行里面的函数
downBtn.setOnClickListener(new runButtonListenner());
如果为每一个button都绑定一个监听器,程序很不友好。最常用的方法就是为所有同种类型的button设置同一个监听器。
upBtn.setOnClickListener(new runButtonListenner());
downBtn.setOnClickListener(new runButtonListenner());
leftBtn.setOnClickListener(new runButtonListenner());
rightBtn.setOnClickListener(new runButtonListenner());
stopBtn.setOnClickListener(new runButtonListenner());
在监听器里,利用switch语句来判断是哪个button被按下,onclick函数喊传入参数v,通过调用参数v的getId方法获取按钮
class runButtonListenner implements OnClickListener
{
@Override
public void onClick(View v)
{
// TODO Auto-generated method stub
switch(v.getId())
{
case R.id.upbtn:
break;
case R.id.upbtn:
break;
}
}
2、 连接服务器的按钮应该是个开关型按钮,按下和松开是两种状态。在android里有ToggleButton类,这就是个按钮控件,但是个人感觉用着
很不舒服,因此就自定义了一个开关型的button。其实就是一个普通的button,通过判断语句来实现开关的功能,关于这一部分功能可以参
考我的源代码
3、 socket编程,这个项目里TCP服务器已经由硬件实现,android只需要实现TCP客户端
(1) socket是要访问网络的,因此需要在AndroidManifset中申明网络访问权限
这句话代表访问网络权限,加在application标签后
(2) 在开发时遇到一个问题,android4.0以上的版本不支持在同一个线程里访问网络,因此必须创建一个新线程
//创建一个线程,将ip和端口号传入,在新的线程里创建socket
TcpClientThread tcpClientThread = new TcpClientThread(ip, port);
//启动线程
tcpClientThread.start();
由于创建socket时IP和端口应该由外部输入,不能定死,因此需要在创建新线程时传递参数。这样就需要
在 新的线程 类中有带参数的构造函数
public class TcpClientThread extends Thread
{
String ip = null;
int port = 0;
//在构造函数里得到参数ip 和port
public TcpClientThread(String Ip, int Port)
{
// TODO Auto-generated constructor stub
ip = Ip;
port = Port;
}
@Override
//run方法会自动调用
public void run()
{
}
}
(3) 创建线程的函数 new Socket(dstName, dstPort)是一个阻塞的过程,如果服务器没有启动,那么程序就会一直等待,
因此用下面这种方法来创建一个socket
//创建一个socket
socket = new Socket();
//获取socket地址
SocketAddress socketAddress = new InetSocketAddress(ip, port);
//连接socket
socket.connect(socketAddress);
4、源代码
(1)MainActivity.java
(2)TcpClient.java
(3)activity_main.xml
(4)AndroidManifest.xml
PROJECT: wifi遥控小车
HARDWARE: STC89C52RC单机, L239D直流电机驱动器, ESP8266安信可wifi模块
SOFTWARE: Eclipse安卓开发环境
AUTHOR: DDDDD
DATE: 2014-12-5
*************************************************************************************************/

这个小项目有软件和硬件两大块,这里主要阐述在开发android客户端中遇到的问题
1、需要几个普通的Button,控制前进后退等。
findViewById()这个函数将定义的button变量和xml文件中的button控件绑定起来
upBtn = (Button)findViewById(R.id.upbtn);
setOnClickListener()为button控件添加监听器,这样button被按下后监听器就会执行里面的函数
downBtn.setOnClickListener(new runButtonListenner());
如果为每一个button都绑定一个监听器,程序很不友好。最常用的方法就是为所有同种类型的button设置同一个监听器。
upBtn.setOnClickListener(new runButtonListenner());
downBtn.setOnClickListener(new runButtonListenner());
leftBtn.setOnClickListener(new runButtonListenner());
rightBtn.setOnClickListener(new runButtonListenner());
stopBtn.setOnClickListener(new runButtonListenner());
在监听器里,利用switch语句来判断是哪个button被按下,onclick函数喊传入参数v,通过调用参数v的getId方法获取按钮
class runButtonListenner implements OnClickListener
{
@Override
public void onClick(View v)
{
// TODO Auto-generated method stub
switch(v.getId())
{
case R.id.upbtn:
break;
case R.id.upbtn:
break;
}
}
2、 连接服务器的按钮应该是个开关型按钮,按下和松开是两种状态。在android里有ToggleButton类,这就是个按钮控件,但是个人感觉用着
很不舒服,因此就自定义了一个开关型的button。其实就是一个普通的button,通过判断语句来实现开关的功能,关于这一部分功能可以参
考我的源代码
3、 socket编程,这个项目里TCP服务器已经由硬件实现,android只需要实现TCP客户端
(1) socket是要访问网络的,因此需要在AndroidManifset中申明网络访问权限
这句话代表访问网络权限,加在application标签后
(2) 在开发时遇到一个问题,android4.0以上的版本不支持在同一个线程里访问网络,因此必须创建一个新线程
//创建一个线程,将ip和端口号传入,在新的线程里创建socket
TcpClientThread tcpClientThread = new TcpClientThread(ip, port);
//启动线程
tcpClientThread.start();
由于创建socket时IP和端口应该由外部输入,不能定死,因此需要在创建新线程时传递参数。这样就需要
在 新的线程 类中有带参数的构造函数
public class TcpClientThread extends Thread
{
String ip = null;
int port = 0;
//在构造函数里得到参数ip 和port
public TcpClientThread(String Ip, int Port)
{
// TODO Auto-generated constructor stub
ip = Ip;
port = Port;
}
@Override
//run方法会自动调用
public void run()
{
}
}
(3) 创建线程的函数 new Socket(dstName, dstPort)是一个阻塞的过程,如果服务器没有启动,那么程序就会一直等待,
因此用下面这种方法来创建一个socket
//创建一个socket
socket = new Socket();
//获取socket地址
SocketAddress socketAddress = new InetSocketAddress(ip, port);
//连接socket
socket.connect(socketAddress);
4、源代码
(1)MainActivity.java
点击(此处)折叠或打开
- package com.example.tcp_client;
-
- import java.io.IOException;
- import java.io.OutputStream;
-
- import android.os.Bundle;
- import android.app.Activity;
- import android.app.AlertDialog;
- import android.content.DialogInterface;
- import android.view.Menu;
- import android.view.View;
- import android.view.View.OnClickListener;
- import android.widget.Button;
- import android.widget.EditText;
- import android.widget.TextView;
-
- public class MainActivity extends Activity
- {
- //按钮控件,有前后左右,停车
- private Button upBtn = null;
- private Button downBtn = null;
- private Button leftBtn = null;
- private Button rightBtn = null;
- private Button stopBtn = null;
- //按钮控件,连接或者断开服务器
- private Button tcpBtn = null;
- //EditText 输入服务器ip和端口号
- private EditText ipEdit = null;
- private EditText portEdit = null;
- //TextView 显示信息
- private TextView tcpInfoText = null;
- private TextView carInfoText = null;
-
- private String IP = null;
- private int PORT;
- //如果已经连接到服务器,那么按钮上就应该显示断开服务器
- private String linked = "断开服务器";
- //如果服务器已经断开,那么按钮上就应该显示;连接服务器
- private String unlink = "连接服务器";
- //检测自定义ToggleButton的状态,false代表还没按下,true代表按下
- private boolean isChecked = false;
- //自定义的TcpClient类实体
- private TcpClient tcpClient = null;
- //输出流,用于socket
- static OutputStream outStream = null;
- @Override
- protected void onCreate(Bundle savedInstanceState)
- {
- super.onCreate(savedInstanceState);
- //指定布局文件
- setContentView(R.layout.activity_main);
- //将控件找到
- upBtn = (Button)findViewById(R.id.upbtn);
- downBtn = (Button)findViewById(R.id.downbtn);
- leftBtn = (Button)findViewById(R.id.leftbtn);
- rightBtn = (Button)findViewById(R.id.rightbtn);
- stopBtn = (Button)findViewById(R.id.stopBtn);
- //为控件绑定监听器Listener
- upBtn.setOnClickListener(new runButtonListenner());
- downBtn.setOnClickListener(new runButtonListenner());
- leftBtn.setOnClickListener(new runButtonListenner());
- rightBtn.setOnClickListener(new runButtonListenner());
- stopBtn.setOnClickListener(new runButtonListenner());
- //连接服务器的按钮式一个button控件,自定义为ToggleButton
- tcpBtn = (Button)findViewById(R.id.tcpToggleBtn);
- tcpBtn.setOnClickListener(new switchButtonListener());
- tcpBtn.setText(unlink);
-
- ipEdit = (EditText)findViewById(R.id.ipEdit);
- portEdit = (EditText)findViewById(R.id.portEdit);
- tcpInfoText = (TextView)findViewById(R.id.tcpInfoText);
- carInfoText = (TextView)findViewById(R.id.carInfoText);
-
-
- }
- //关于小车状态按钮的监听器
- class runButtonListenner implements OnClickListener
- {
- @Override
- public void onClick(View v)
- {
- // TODO Auto-generated method stub
- switch(v.getId())
- {
- case R.id.upbtn:
- if(outStream != null)
- {
- tcpClient.sendBuffer(outStream, "#up*");
- carInfoText.setText("小车正在前进");
- }
- break;
- case R.id.downbtn:
- if(outStream != null)
- {
- tcpClient.sendBuffer(outStream, "#dn*");
- carInfoText.setText("小车正在后退");
- }
- break;
- case R.id.leftbtn:
- if(outStream != null)
- {
- tcpClient.sendBuffer(outStream, "#zz*");
- carInfoText.setText("小车正在左转");
- }
- break;
- case R.id.rightbtn:
- if(outStream != null)
- {
- tcpClient.sendBuffer(outStream, "#yz*");
- carInfoText.setText("小车正在右转");
- }
- break;
- case R.id.stopBtn:
- if(outStream != null)
- {
- tcpClient.sendBuffer(outStream, "#sp*");
- carInfoText.setText("小车已经停车");
- }
- default:
- break;
-
- }
- }
-
- }
- //自定义ToggleButton控件的监听器,按下和松开是两种显示状态
- class switchButtonListener implements OnClickListener
- {
- @Override
- public void onClick(View v)
- {
- // TODO Auto-generated method stub
- //每次点击按钮之后,按钮的状态就应该取反
- isChecked = !isChecked;
- //如果按下按钮,ToggleButton的状态时true
- if(isChecked)
- {
- //从ip的EditText获取IP
- IP = ipEdit.getText().toString();
- //如果没有输入IP,那么获取的字符串长度就是0,按钮的状态还是false
- if(IP.length() == 0)
- {
- //没有IP,ToggleButton的状态还是false
- isChecked = false;
- //弹出提示对话框,提示用户输入IP
- new AlertDialog.Builder(MainActivity.this)
- .setTitle("提示")
- .setIcon(android.R.drawable.ic_dialog_info)
- .setMessage("请输入服务器IP地址")
- .setPositiveButton("确定", new DialogInterface.OnClickListener(){
-
- @Override
- public void onClick(DialogInterface arg0, int arg1) {
- // TODO Auto-generated method stub
-
- }})
- .show();
- }
- else
- {
- //如果没有输入端口号,那么从端口edit获取的字符串长度也是0
- if(portEdit.getText().toString().length() == 0)
- {
- //没有端口号,ToggleButton的状态还是false
- isChecked = false;
- //弹出对话框,提示用户输入端口
- new AlertDialog.Builder(MainActivity.this)
- .setTitle("提示")
- .setIcon(android.R.drawable.ic_dialog_info)
- .setMessage("请输入服务器端口号")
- .setPositiveButton("确定", new DialogInterface.OnClickListener(){
-
- @Override
- public void onClick(DialogInterface arg0, int arg1) {
- // TODO Auto-generated method stub
-
- }})
- .show();
- }
- try{
- //将获取的端口号转为一个整数
- PORT = Integer.parseInt(portEdit.getText().toString());
- }catch (Exception e){
- e.printStackTrace();
- }
- //创建TcpClient实体
- tcpClient = new TcpClient();
- //创建socket,并且获取到一个outputStream
- tcpClient.createTcpCient(IP, PORT);
- if(outStream != null)
- {
- //如果得到了OutputStream,在信息框提示连接成功自定义ToggleButton就显示
- tcpInfoText.setText("OK,连接服务器成功");
- //已经连接到服务器,ToggleButton显示“断开连接”
- tcpBtn.setText(linked);
- }
- else
- {
- //没有得到OutputStream,自定义ToggleButton的属性还是false
- isChecked = false;
- }
- }
- }
- else
- {
- //如果ToggleButton的状态是false,那么就断开socket
- try
- {
- TcpClient.socket.close();
- } catch (IOException e)
- {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- //释放资源
- outStream = null;
- tcpClient = null;
- //将ToggleButton的内容设置为“连接服务器”
- tcpBtn.setText(unlink);
- //信息edit提示服务器断开
- tcpInfoText.setText("注意,服务器已断开");
- }
-
- }
-
- }
-
- @Override
- public boolean onCreateOptionsMenu(Menu menu)
- {
- // Inflate the menu; this adds items to the action bar if it is present.
- getMenuInflater().inflate(R.menu.main, menu);
- return true;
- }
-
- }
点击(此处)折叠或打开
- package com.example.tcp_client;
-
- import java.io.IOException;
- import java.io.OutputStream;
- import java.io.UnsupportedEncodingException;
- import java.net.InetSocketAddress;
- import java.net.Socket;
- import java.net.SocketAddress;
-
- public class TcpClient
- {
- public static Socket socket = null;
-
- public void createTcpCient(String ip, int port)
- {
- //创建一个线程,将ip和端口号传入,在新的线程里创建socket
- TcpClientThread tcpClientThread = new TcpClientThread(ip, port);
- //启动线程
- tcpClientThread.start();
- }
-
- public class TcpClientThread extends Thread
- {
- String ip = null;
- int port = 0;
- //在构造函数里得到参数ip 和port
- public TcpClientThread(String Ip, int Port)
- {
- // TODO Auto-generated constructor stub
- ip = Ip;
- port = Port;
- }
-
- @Override
- //run方法会自动调用
- public void run()
- {
- // TODO Auto-generated method stub
- super.run();
- try{
- //创建一个socket
- socket = new Socket();
- //获取socket地址
- SocketAddress socketAddress = new InetSocketAddress(ip, port);
- //连接socket
- socket.connect(socketAddress);
- //从socket获取一个outputstream
- MainActivity.outStream = socket.getOutputStream();
- //将buffer的内容写入outputstream
- }catch (IOException e){
- e.printStackTrace();
- }
- }
- }
- //通过socket发送数据
- public void sendBuffer(OutputStream outputStream, String buf)
- {
- byte buffer[] = null;
- try
- {
- //将String转为byte类型
- buffer = buf.getBytes("ISO-8859-1");
- } catch (UnsupportedEncodingException e)
- {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- try
- {
- //输出数据
- outputStream.write(buffer, 0, buffer.length);
- outputStream.flush();
- } catch (IOException e)
- {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
-
- }
- }
点击(此处)折叠或打开
- RelativeLayout 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:paddingBottom="@dimen/activity_vertical_margin"
- android:paddingLeft="@dimen/activity_horizontal_margin"
- android:paddingRight="@dimen/activity_horizontal_margin"
- android:paddingTop="@dimen/activity_vertical_margin"
- tools:context=".MainActivity" >
-
- Button
- android:id="@+id/upbtn"
- style="?android:attr/buttonStyleSmall"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignLeft="@+id/downbtn"
- android:text="前进" />
- Button
- android:id="@+id/leftbtn"
- style="?android:attr/buttonStyleSmall"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_below="@+id/upbtn"
- android:layout_marginRight="28dp"
- android:layout_toLeftOf="@+id/upbtn"
- android:text="左转" />
- Button
- android:id="@+id/rightbtn"
- style="?android:attr/buttonStyleSmall"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignBaseline="@+id/stopBtn"
- android:layout_alignBottom="@+id/stopBtn"
- android:layout_marginLeft="24dp"
- android:layout_toRightOf="@+id/stopBtn"
- android:text="右转" />
-
- Button
- android:id="@+id/stopBtn"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignBottom="@+id/leftbtn"
- android:layout_alignLeft="@+id/upbtn"
- android:layout_alignRight="@+id/upbtn"
- android:layout_below="@+id/upbtn"
- android:text="停车" />
-
- Button
- android:id="@+id/downbtn"
- style="?android:attr/buttonStyleSmall"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_below="@+id/stopBtn"
- android:layout_centerHorizontal="true"
- android:text="后退" />
-
- EditText
- android:id="@+id/ipEdit"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:hint = "请输入服务器IP"
- android:inputType="none"
- android:layout_below="@+id/downbtn"
- />
- EditText
- android:id="@+id/portEdit"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:hint = "请输入服务器端口"
- android:inputType="none"
- android:layout_below="@+id/ipEdit"
- />
- TextView
- android:id="@+id/tcpInfoText"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_below="@+id/tcpToggleBtn"
- android:singleLine="false"
- />
- TextView
- android:id="@+id/carInfoText"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_below="@+id/tcpInfoText"
- android:singleLine="false"
- />
-
- Button
- android:id="@+id/tcpToggleBtn"
- style="@android:style/MediaButton"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignLeft="@+id/portEdit"
- android:layout_alignRight="@+id/portEdit"
- android:layout_below="@+id/portEdit"
- android:textOn="断开服务器"
- android:textOff="连接服务器"
- />
-
-
- /RelativeLayout>
点击(此处)折叠或打开
- ?xml version="1.0" encoding="utf-8"?>
- manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.example.tcp_client"
- android:versionCode="1"
- android:versionName="1.0" >
-
- uses-sdk
- android:minSdkVersion="8"
- android:targetSdkVersion="18" />
-
- application
- android:allowBackup="true"
- android:icon="@drawable/ic_launcher"
- android:label="@string/app_name"
- android:theme="@style/AppTheme" >
- activity
- android:name="com.example.tcp_client.MainActivity"
- android:label="@string/app_name" >
- intent-filter>
- action android:name="android.intent.action.MAIN" />
-
- category android:name="android.intent.category.LAUNCHER" />
- /intent-filter>
- /activity>
- /application>
- uses-permission android:name="android.permission.INTERNET"/>
- /manifest>