/*************************************************************************************************
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;
-
}
-
-
}
(2)TcpClient.java
-
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();
-
}
-
-
}
-
}
(3)activity_main.xml
(4)AndroidManifest.xml
-
<?xml version="1.0" encoding="utf-8"?>
-
<manifest xmlns: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>
阅读(2518) | 评论(0) | 转发(0) |