Android-socket-client客户端<2>

————————————————————————————————————————————————————————————————————

前言:参考老师的代码重新修改了一下我的客户端程序,将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");
	} 
}
















  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值