您的位置:首页 > 移动开发 > Android开发

Android-socket-client客户端<2>

2015-12-20 22:17 579 查看
————————————————————————————————————————————————————————————————————

前言:参考老师的代码重新修改了一下我的客户端程序,将socket封装成了一个类,还自定义了一个接口,其中的接口函数当做回调函数。



MySocket.java:声明了一个MySocket的类,提供了自己定义的一些网络连接,传输等接口函数,继承了系统的Socket类。

NetworkInterface.java:自己定义了一个接口类,里面定义了几个接口函数:(作为MySocket类中函数的回调函数)

public void NetConnected();  //网络连接成功
public void NetConnectFail();//网络连接失败
public void NetReceived(String msg);//网络接收到数据
public void NetSent();//网络发送数据成功

NetworkProber.java:NetworkProber这个类是用来检查网络是否可用的,是GPS还是WIFI,目前代码中并没用到。

MainActivity.java:实现了主要的代码,调用自定义的socket类去实现socket客户端与服务器之间发送信息

总结:1.这个代码体现了面向对象的语言好处,把一个自己需要的东西封装成了一个类,等我要用的时候,不用再重复去敲具体的实现代码,只需要调用我们类中的接口函数就好。

         2. 这里定义接口是为了使用其接口方法当做回调函数;

首先我们看一下接口的使用: (定义了一个该接口类型的变量,就会发现自动实现了我们的接口函数)



是不是跟我们定义一个按键的响应一样,它会自动出现onclick这个函数



然后就是回调:这里我举一个代码中的小例子看,(在MySocket中定义的一个连接网络的方法,它用到了一个线程,这个线程中就用到了接口定义的函数当做回调函数)



你们可以看到当连接成功的时候会自动去调用NetConnected()这个函数,这个函数是我们在NetInterface.java中看到的定义的接口函数;当连接失败的时候调用NetConnectFail()这个函数.



然后在ui线程去点连接:



当你一点击连接,它就会调用MyNetConnect这个方法,去使用线程去连接,当成功的时候会回调那个成功的接口函数,失败则回调我们那个失败的接口函数。我们之所以用这2个回调函数,是因为我们当连接失败的时候我们需要知道,成功了我们也需要知道,而这2个回调函数的作用就在于我们来通知用户。



上面这2个回调函数的实现就是来告诉我们连接是成功还是失败(通过handler,具体看代码)

通过上面的解释,我想大家应该能明白回调的意思了吧,首先回调函数不是一种具体的函数,什么函数都可以做为回调函数,就比如这里我定义的接口函数<所以我上面把NetConnectFail() NetConnected()叫做接口函数或者回调函数>。老师打了一个比喻说就相当于我们语文中用插入符号插入一些话,一句话写完,你或许想加一点什么东西,就需要用那个符号插入我们想要的话,这就相当于回调。

如果还不能理解的话,可以把我的代码仔细看一看,看看NetConnectFail() NetConnected()这2个函数是如果调用的,如果实现的,应该差不多了吧。

*****************************************************************************************************************************************************************************************

贴上效果图:(服务端仍然用的那个串口小助手)



*****************************************************************************************************************************************************************************************

贴上代码:(记得在AndroidMainifest.xml中添加权限,这里我就不贴了,上篇中有)

(布局文件)

<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:background="@drawable/bk"
tools:context="${relativePackage}.${activityClass}"
>

<EditText
android:id="@+id/ip"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBottom="@+id/con_btn"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:layout_toLeftOf="@+id/con_btn"
android:layout_toStartOf="@+id/con_btn"
android:hint="请输入服务器ip地址"
android:textColorHint="#ffffff"
android:ems="10"
/>

<EditText
android:id="@+id/editText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="@+id/send_btn"
android:layout_alignParentEnd="true"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:layout_alignParentStart="true"
android:ems="10"
android:hint="编辑内容"
android:textColorHint="#000000" >
<requestFocus />
</EditText>

<Button
android:id="@+id/send_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:layout_marginBottom="28dp"
android:text="发送"
android:textStyle="bold"
android:background="@drawable/btn"
/>

<Button
android:id="@+id/con_btn"
style="?android:attr/buttonStyleSmall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_toLeftOf="@+id/discon_btn"
android:layout_toStartOf="@+id/discon_btn"
android:text="连接"
android:textStyle="bold" />

<Button
android:id="@+id/discon_btn"
style="?android:attr/buttonStyleSmall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBottom="@+id/con_btn"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:layout_alignParentTop="true"
android:text="断开"
android:textStyle="bold"

/>

<!-- 设置textview下拉属性 scrollbars “滚动条出现到消失的时间=5000ms” -->

<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="@+id/editText"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:layout_below="@+id/port"
android:scrollbarFadeDuration="5000"
android:scrollbarStyle="insideOverlay"
android:scrollbars="vertical"
android:textColorHint="#ffffff"
android:hint="数据收发区"
/>

<EditText
android:id="@+id/port"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_below="@+id/ip"
android:layout_toLeftOf="@+id/con_btn"
android:layout_toStartOf="@+id/con_btn"
android:ems="10"
android:hint="请输入服务器端口号"
android:textColorHint="#ffffff"
android:inputType="number"
/>

<TextView
android:id="@+id/text_status"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBottom="@+id/port"
android:layout_alignLeft="@+id/con_btn"
android:layout_alignTop="@+id/port"
android:layout_toLeftOf="@+id/discon_btn"
android:hint="状态:"
android:textColorHint="#545454"
android:textSize="18sp" />

<TextView
android:id="@+id/text_status1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBottom="@+id/port"
android:layout_alignParentRight="true"
android:layout_below="@+id/con_btn"
android:textSize="17sp" />

</RelativeLayout>


MySocket.java:
package com.lzj_socket;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;

import android.util.Log;

public class MySocket {

private Socket socketFd = null;
/*
* 不同方法的网络收发接口函数
* DataOutputStream 发送字节流数据
* DataInputStream 接收字节流数据
*
* BufferedReader 接收字符流数据
* BufferedWriter 发送字符流数据
* */

private DataOutputStream socketWriter = null;//DataOutputStream 用于推送消息  
private BufferedReader socketReader = null;//BufferedReader 用于接收消息

private NetworkInterface netCallback = null; // 定义外部接口函数变量(回调函数)
private static final String bm="gb2312"; //中文字符编码格式

//该类提供给外部的接口函数
public MySocket(){ //不带参数的构造函数
};

//该类提供给外部的接口函数
public MySocket(NetworkInterface callback){ //带参数的构造函数
netCallback = callback; //设置外部接口函数
}

/*
* 该类提供给外部的接口函数---网络连接接口函数
*
* 传入参数:
* ip : 服务器IP地址
* port : 服务器端口号
* timeout:连接超时时间,即如果连接不上多长时间结束连接动作
*/
public void MyNetConnect(String ip, int port , int timeout){
myNetConnThread netConnect = new myNetConnThread(ip, port, timeout);
netConnect.start();
}

/*
* 该类提供给外部的接口函数 -- 网络接收数据线程启动
*
* 传入参数:无
*/
public void MyNetReceiver(){
myNetRecvThread netRecvThread = new myNetRecvThread();
netRecvThread.start();
}

/*
* 该类提供给外部的接口函数---网络数据发送函数
*
* 传入参数:
* msg : 需要发送的字符数据流
*/
public void MyNetSendMsg(String msg){
if(null != socketWriter && null != msg){
//发送信息到服务端
try {
socketWriter.write(msg.getBytes(bm));
socketWriter.flush(); // 清空发送缓存
netCallback.NetSent(); // 调用接口函数,通知上层发送成功
Log.e("MySocket", "Send-> "+msg);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}

/*
* 该类提供给外部的接口函数 -- 网络资源释放
* 网络连接如果不使用了,是必须释放所占用的连接资源
* 传入参数:无
*/
public void MyNetRelease(){
try {
if(null != socketFd){
socketWriter.close();
socketReader.close();
socketFd.close();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//该类内部使用的网络连接线程方法
class myNetConnThread extends Thread{
private String strIP = null;
private int iPort = 0, iTimeout = 5000;

public myNetConnThread(String ip, int port , int timeout){// 线程类myNetConnThread的带参构造函数
strIP = ip; iPort = port; iTimeout = timeout;
}

public void run(){
try {
socketFd = new Socket();
//连接指定的服务器
socketFd.connect(new InetSocketAddress(strIP, iPort), iTimeout);
socketFd.setSoTimeout(iTimeout); //设置网络收发超时时间

OutputStream outStream = socketFd.getOutputStream();
socketWriter = new DataOutputStream(outStream);

//InputStream inputStream = socketFd.getInputStream();
//socketReader = new DataInputStream(inputStream);

socketReader = new BufferedReader(new InputStreamReader(socketFd.getInputStream(),bm));
netCallback.NetConnected();// 调用接口函数,通知上层连接成功
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
netCallback.NetConnectFail();
}

}
}
//该类内部使用的网络接收线程方法
class myNetRecvThread extends Thread{
public void run(){
if(null != socketReader){
//读取发来服务器信息
while(true){
try {
Thread.sleep(100);
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
try {

if(socketReader.ready()){
/*
* readLine()为阻塞函数,如果接收的数据流没有结束符(回车换行符)‘\n or \r’
*该函数会一直等待(即阻塞在当前代码处),直到到达所设置的超时时间后抛出错误提示
**/
String data = socketReader.readLine();
netCallback.NetReceived(data); // 调用接口函数,通知上层有数据接收成功
}

} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
Log.e("MySocket", "receiver error");
return ;
}
}
}
}
}
}

NetworkInterface.java:
package com.lzj_socket;

public interface NetworkInterface {
/*
* 定义接口函数
*/
public void NetConnected();  //网络连接成功
public void NetConnectFail();//网络连接失败
public void NetReceived(String msg);//网络接收到数据
public void NetSent();//网络发送数据成功
}


MainActivity.java:

package com.lzj.example.msocketclient;

import com.lzj_socket.NetworkInterface;
import com.lzj_socket.MySocket;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.text.method.ScrollingMovementMethod;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

@SuppressLint("HandlerLeak")
public class MainActivity extends Activity {
private EditText ip=null,port=null;
private EditText editTest=null;
private TextView text=null,status=null;
private Button   send_btn=null,con_btn=null,discon_btn=null;
private MySocket myNet = null;//自定义的网络接口类
private NetworkInterface netCallback = null; // 自定义的网络接口函数

public Handler myHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
if(msg.what == 1){
Toast.makeText(MainActivity.this,"连接成功" ,Toast.LENGTH_SHORT).show();
status.setText("已连接");
}else if(msg.what == 2){
Toast.makeText(MainActivity.this,"连接失败" ,Toast.LENGTH_SHORT).show();
status.setText("未连接");
}else if (msg.what == 3) {
Bundle bundle = msg.getData();
text.append("服务器:"+bundle.getString("msg")+"\n");
}
}
};

protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_lmain);
ip=(EditText)findViewById(R.id.ip);
port=(EditText)findViewById(R.id.port);
editTest=(EditText)findViewById(R.id.editText);
text=(TextView)findViewById(R.id.textView);
status=(TextView)findViewById(R.id.text_status1);

status.setText("未连接");
text.setMovementMethod(ScrollingMovementMethod.getInstance());

con_btn=(Button)findViewById(R.id.con_btn);
con_btn.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
String Ip = ip.getText().toString();
int Port = Integer.parseInt(port.getText().toString());
myNet.MyNetConnect(Ip, Port, 3000);
send_btn.setEnabled(true);
editTest.setEnabled(true);
}
});

send_btn=(Button) findViewById(R.id.send_btn);
send_btn.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
myNet.MyNetSendMsg(editTest.getText().toString().trim());
text.append("本机:"+editTest.getText().toString()+"\n");
}
});

discon_btn=(Button)findViewById(R.id.discon_btn);
discon_btn.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
myNet.MyNetRelease();
Toast.makeText(MainActivity.this,"断开连接" ,Toast.LENGTH_SHORT).show();
status.setText("未连接");
send_btn.setEnabled(false);
editTest.setEnabled(false);
}
});
send_btn.setEnabled(false);
editTest.setEnabled(false);

/*网络接口函数初始化---提示信息*/
netCallback = new NetworkInterface(){
public void NetConnected() {
Message message = new Message();
message.what = 1;
myHandler.sendMessage(message);
myNet.MyNetReceiver();

}

@Override
public void NetConnectFail() {
Message message = new Message();
message.what = 2;
myHandler.sendMessage(message);

}

@Override
public void NetReceived(String msg) {
Message message = new Message();
message.what = 3; // 设置消息what标签
Bundle bundle = new Bundle();
bundle.clear();
bundle.putString("msg", msg);
message.setData(bundle);//设置消息内容
//发送消息 修改UI线程中的组件
myHandler.sendMessage(message);

}

@Override
public void NetSent() {
Toast.makeText(MainActivity.this,"信息发送成功" ,Toast.LENGTH_SHORT).show();
}
};
myNet = new MySocket(netCallback);
}
protected void onDestroy(){
super.onDestroy();
myNet.MyNetRelease(); // 释放网络连接资源
Log.d("lzj", "Connect Release");
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: