内容摘要
1.程序架构
2.通信协议
3.服务器源代码
4.客户端源代码
5.运行效果
一、程序架构
在开发一个聊天室程序时,我们可以使用Socket、Remoting、WCF这些具有双向通信的协议或框架。而现在,我正要实现一个C#语言作为服务器 端、Android作为客户端的聊天室。由于服务器端和客户端不是同一语言(C#和java),所有我选择了Socket作为通信协议。
图1.1所示,我们可以看出:android手机客户端A向服务器端发送消息,服务器端收到消息后,又把消息推送到android手机客户端B。
图1.1
二、通信协议
我们知道,在C#语言中使用Socket技术需要 四部曲 ,即 Bind , Listen , Accept , Receive 。然而 Socket编程不像WCF那样面向对象。而且对应每个请求都用同一种方式处理。作为习惯面向对象编程的我来说,编写一个传统的Socket程序很不爽。 绞尽脑汁,我们将数据传输的格式改为json(JavaScript Object Notation 是一种轻量级的数据交换格式),面对对象的问题就解决了。
假设程序的服务契约有两个方法: 登陆 和 发送消息 。调用登陆的方法,就传送方法名(Method Name)为 Logon 的json数据;调用发送消息的方法,就传送方法名为 Send 的json数据。返回的数据中也使用json格式,这样在 android客户端中也能知道是哪个方法的返回值了。
三、服务器源代码
首先需要编写一个处理客户端消息的接口:IResponseManager。
publicinterfaceIResponseManager
{
voidWrite(Socket sender, IList < Socket >cliens, IDictionary < string ,object >param);
}
其次,我们知道,换了是WCF编程的话,就需要在服务契约中写两个方法: 登陆 和 发送消息 。由于这里是Socket编程,我们实现之前写的IResponseManager接口,一个实现作为 登陆 的方法,另一个实现作为 发送消息 的方法。
publicclassLogonResponseManager : IResponseManager
{
publicvoidWrite(System.Net.Sockets.Socket sender, IList < System.Net.Sockets.Socket >cliens, IDictionary < string ,object >param)
{
Console.WriteLine( " 客户端({0})登陆 " , sender.Handle);
var response=newSocketResponse
{
Method=" Logon " ,
DateTime=DateTime.Now.ToString( " yyyy-MM-dd HH:mm:ss " ),
Result=new{ UserName=param[ " UserName " ].ToString() }
};
JavaScriptSerializer jss=newJavaScriptSerializer();
stringcontext=jss.Serialize(response);
Console.WriteLine( " 登陆发送的数据为:{0} " , context);
sender.Send(Encoding.UTF8.GetBytes(context+" \n " ));
}
}
publicclassSendResponseManager : IResponseManager
{
publicvoidWrite(System.Net.Sockets.Socket sender, IList < System.Net.Sockets.Socket >cliens, IDictionary < string ,object >param)
{
Console.WriteLine( " 客户端({0})发送消息 " , sender.Handle);
var msgList=param[ " Message " ]asIEnumerable < object > ;
if(msgList==null )
{
return ;
}
var response=newSocketResponse
{
Method=" Send " ,
DateTime=DateTime.Now.ToString( " yyyy-MM-dd HH:mm:ss " ),
Result=new
{
UserName=param[ " UserName " ].ToString(),
Message=msgList.Select(s=>s.ToString()).ToArray()
}
};
JavaScriptSerializer jss=newJavaScriptSerializer();
stringcontext=jss.Serialize(response);
Console.WriteLine( " 消息发送的数据为:{0} " , context);
Parallel.ForEach(cliens, (item)=>
{
try
{
item.Send(Encoding.UTF8.GetBytes(context+" \n " ));
}
catch{ };
});
}
}
最后在Socket程序中使用反射加 策略模式 调用这两个接口实现类。
var typeName=" SocketServer. "+request.Method+" ResponseManager, SocketServer " ;
Console.WriteLine( " 反射类名为: "+typeName);
Type type=Type.GetType(typeName);
if(type==null )
{
return ;
}
var manager=Activator.CreateInstance(type)asIResponseManager;
manager.Write(sender,this .socketClientSesson.Select(s=>s.Key).ToList(),
request.ParamasIDictionary < string ,object > );
完整的Socket服务器代码如下:
publicclassSocketHost
{
privateIDictionary < Socket,byte [] >socketClientSesson=newDictionary < Socket,byte [] > ();
publicintPort {get ;set ; }
publicvoidStart()
{
var socketThread=newThread(()=>
{
Socket socket=newSocket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPEndPoint iep=newIPEndPoint(IPAddress.Any,this .Port);
// 绑定到通道上
socket.Bind(iep);
// 侦听
socket.Listen( 6 );
// 通过异步来处理
socket.BeginAccept( newAsyncCallback(Accept), socket);
});
socketThread.Start();
Console.WriteLine( " 服务器已启动 " );
}
privatevoidAccept(IAsyncResult ia)
{
Socket socket=ia.AsyncStateasSocket;
var client=socket.EndAccept(ia);
socket.BeginAccept( newAsyncCallback(Accept), socket);
byte [] buf=newbyte [ 1024 ];
this .socketClientSesson.Add(client, buf);
try
{
client.BeginReceive(buf,0 , buf.Length, SocketFlags.None,newAsyncCallback(Receive), client);
stringsessionId=client.Handle.ToString();
Console.WriteLine( " 客户端({0})已连接 " , sessionId);
}
catch(Exception ex)
{
Console.WriteLine( " 监听请求时出错:\r\n "+ex.ToString());
}
}
privatevoidReceive(IAsyncResult ia)
{
var client=ia.AsyncStateasSocket;
if(client==null||! this .socketClientSesson.ContainsKey(client))
{
return ;
}
intcount=client.EndReceive(ia);
byte [] buf=this .socketClientSesson[client];
if(count>0 )
{
try
{
client.BeginReceive(buf,0 , buf.Length, SocketFlags.None,newAsyncCallback(Receive), client);
stringcontext=Encoding.UTF8.GetString(buf,0 , count);
Console.WriteLine( " 接收的数据为: " , context);
this .Response(client, context);
}
catch(Exception ex)
{
Console.WriteLine( " 接收的数据出错:\r\n{0} " , ex.ToString());
}
}
else
{
try
{
stringsessionId=client.Handle.ToString();
client.Disconnect( true );
this .socketClientSesson.Remove(client);
Console.WriteLine( " 客户端({0})已断开 " , sessionId);
}
catch(Exception ex)
{
Console.WriteLine( " 客户端已断开出错 "+ex.ToString());
}
}
}
privatevoidResponse(Socket sender,stringcontext)
{
SocketRequest request=null ;
JavaScriptSerializer jss=newJavaScriptSerializer();
request=jss.Deserialize(context,typeof (SocketRequest))asSocketRequest;
if(request==null )
{
return ;
}
var typeName=" SocketServer. "+request.Method+" ResponseManager, SocketServer " ;
Console.WriteLine( " 反射类名为: "+typeName);
Type type=Type.GetType(typeName);
if(type==null )
{
return ;
}
var manager=Activator.CreateInstance(type)asIResponseManager;
manager.Write(sender,this .socketClientSesson.Select(s=>s.Key).ToList(),
request.ParamasIDictionary < string ,object > );
}
}
最后,json数据传输的实体对象为:
[Serializable]
publicclassSocketRequest
{
publicstringMethod {get ;set ; }
publicstringDateTime {get ;set ; }
publicobjectParam {get ;set ; }
}
[Serializable]
publicclassSocketResponse
{
publicstringMethod {get ;set ; }
publicstringDateTime {get ;set ; }
publicobjectResult {get ;set ; }
}
四、客户端源代码
1.布局文件
logon.xml:
<? xml version="1.0" encoding="utf-8" ?>
< LinearLayoutxmlns:android ="http://schemas.android.com/apk/res/android"
android:orientation ="vertical"android:layout_width ="fill_parent"
android:layout_height ="fill_parent"android:background ="@drawable/background" >
< LinearLayoutandroid:orientation ="vertical"
android:layout_width ="fill_parent"android:layout_height ="60dip"
android:background ="@drawable/logon"/>
< LinearLayoutandroid:orientation ="vertical"
android:layout_width ="fill_parent"android:layout_height ="fill_parent"
android:paddingLeft ="10dp"android:paddingRight ="10dp" >
< Viewandroid:layout_width ="fill_parent"android:layout_height ="20dip"/>
< TextViewandroid:id ="@+id/feedback_title"android:textColor ="#FFFFFF"
android:layout_width ="fill_parent"android:layout_height ="wrap_content"
android:text ="用户名:"/>
< EditTextandroid:id ="@+id/edtUserName"android:layout_width ="fill_parent"
android:layout_height ="wrap_content"/>
< Viewandroid:layout_width ="fill_parent"android:layout_height ="2dip"
android:background ="#FF909090"/>
< TextViewandroid:layout_width ="fill_parent"
android:textColor ="#FFFFFF"android:layout_height ="wrap_content"
android:text ="IP地址:"/>
< EditTextandroid:id ="@+id/edtIp"android:layout_width ="fill_parent"
android:layout_height ="wrap_content"android:digits ="1234567890."
android:text ="192.168.1.101" />
< Viewandroid:layout_width ="fill_parent"android:layout_height ="2dip"
android:background ="#FF909090"/>
< TextViewandroid:layout_width ="fill_parent"
android:textColor ="#FFFFFF"android:layout_height ="wrap_content"
android:text ="端口号:"/>
< EditTextandroid:id ="@+id/edtPort"android:layout_width ="fill_parent"
android:layout_height ="wrap_content"android:inputType ="number"
android:numeric ="integer"android:text ="1234" />
< LinearLayoutandroid:orientation ="horizontal"
android:layout_width ="fill_parent"android:layout_height ="wrap_content"
android:layout_marginTop ="10dp" >
</ LinearLayout >
< RelativeLayoutandroid:layout_width ="fill_parent"
android:layout_height ="fill_parent" >
< Viewandroid:id ="@+id/feedback_content"android:layout_width ="fill_parent"
android:layout_height ="fill_parent"android:maxEms ="10"
android:minEms ="10"android:gravity ="top"
android:layout_marginBottom ="50dip"/>
< Buttonandroid:id ="@+id/btnLogon"android:layout_width ="fill_parent"
android:layout_height ="50dp"android:text ="登陆"android:textSize ="19dp"
android:layout_gravity ="center_horizontal"
android:layout_alignParentBottom ="true"/>
</ RelativeLayout >
</ LinearLayout >
</ LinearLayout >
main.xml:
<? xml version="1.0" encoding="utf-8" ?>
< LinearLayoutxmlns:android ="http://schemas.android.com/apk/res/android"
android:orientation ="vertical"android:layout_width ="fill_parent"
android:layout_height ="fill_parent"android:background ="@drawable/background" >
< ListViewandroid:layout_width ="fill_parent"
android:layout_height ="wrap_content"android:id ="@+id/ltvMessage" >
</ ListView >
< RelativeLayoutandroid:layout_width ="fill_parent"
android:layout_height ="wrap_content" >
< EditTextandroid:layout_width ="fill_parent"
android:layout_height ="wrap_content"android:id ="@+id/edtMessage"
android:hint ="请输入消息"android:layout_alignTop ="@+id/btnSend"
android:layout_toLeftOf ="@+id/btnSend"/>
< Buttonandroid:text ="SEND"android:id ="@+id/btnSend"
android:layout_height ="wrap_content"android:layout_width ="wrap_content"
android:layout_alignParentRight ="true"/>
</ RelativeLayout >
</ LinearLayout >
listview_item.xml:
<? xml version="1.0" encoding="utf-8" ?>
< LinearLayoutxmlns:android ="http://schemas.android.com/apk/res/android"
android:layout_width ="fill_parent"android:layout_height ="wrap_content"
android:orientation ="vertical"android:paddingBottom ="3dip"
android:paddingLeft ="10dip" >
< TextViewandroid:layout_height ="wrap_content"
android:layout_width ="fill_parent"android:id ="@+id/itmMessage"
android:textSize ="20dip" >
</ TextView >
< LinearLayoutandroid:layout_width ="fill_parent"
android:orientation ="horizontal"android:layout_height ="20dip" >
< TextViewandroid:layout_height ="fill_parent"
android:layout_width ="100dip"android:id ="@+id/itmUserName">
</ TextView >
< TextViewandroid:layout_height ="fill_parent"
android:layout_width ="200dip"android:id ="@+id/itmTime">
</ TextView >
</ LinearLayout >
</ LinearLayout >
SocketClient:
packageld.socket;
importjava.io.BufferedReader;
importjava.io.BufferedWriter;
importjava.io.IOException;
importjava.io.InputStreamReader;
importjava.io.OutputStreamWriter;
importjava.net.Socket;
importjava.net.UnknownHostException;
importjava.text.SimpleDateFormat;
importjava.util.Date;
importjava.util.HashMap;
importjava.util.Map;
importorg.json.JSONArray;
importorg.json.JSONException;
importorg.json.JSONObject;
importandroid.os.Handler;
importandroid.os.Message;
importandroid.util.Log;
publicclassSocketClient {
privatestaticSocket client;
privatestaticSocketClient instance=null ;
publicstaticSocketClient getInstance() {
if(instance==null ) {
synchronized(ChartInfo. class ) {
if(instance==null ) {
try{
ChartInfo chartInfo=ChartInfo.getInstance();
client=newSocket(chartInfo.getIp(), chartInfo
.getPort());
instance=newSocketClient();
}catch(UnknownHostException e) {
//TODO Auto-generated catch block
}catch(IOException e) {
//TODO Auto-generated catch block
}
}
}
}
returninstance;
}
privateSocketClient() {
this .initMap();
this .startThread();
}
privatevoidinitMap() {
this .handlerMap=newHashMap < String, Handler > ();
}
publicvoidclose() {
try{
client.close();
}catch(IOException e) {
//TODO Auto-generated catch block
// e.printStackTrace();
}
instance=null ;
}
privatevoidstartThread() {
Thread thread=newThread() {
@Override
publicvoidrun() {
while( true ) {
if(client==null||! client.isConnected()) {
continue ;
}
BufferedReader reader;
try{
reader=newBufferedReader( newInputStreamReader(
client.getInputStream()));
String line=reader.readLine();
Log.d( " initSocket " ," line: "+line);
if(line.equals( "" )) {
continue ;
}
JSONObject json=newJSONObject(line);
String method=json.getString( " Method " );
Log.d( " initSocket " ," method: "+method);
if(method.equals( "" )
||! handlerMap.containsKey(method)) {
Log.d( " initSocket " ," handlerMap not method " );
continue ;
}
Handler handler=handlerMap.get(method);
if(handler==null ) {
Log.d( " initSocket " ," handler is null " );
continue ;
}
Log.d( " initSocket " ," handler: "+method);
Object obj=json.getJSONObject( " Result " );
Log.d( " initSocket " ," Result: "+obj);
Message msg=newMessage();
msg.obj=obj;
handler.sendMessage(msg);
}catch(IOException e) {
}catch(JSONException e) {
}
}
}
};
thread.start();
}
privateMap < String, Handler >handlerMap;
publicvoidputHandler(String methodnName, Handler handler) {
this .removeHandler(methodnName);
this .handlerMap.put(methodnName, handler);
}
publicvoidremoveHandler(String methodnName) {
if( this .handlerMap.containsKey(methodnName)) {
this .handlerMap.remove(methodnName);
}
}
publicvoidlogon(String userName) {
Log.d( " initSocket " ," logon " );
try{
OutputStreamWriter osw=newOutputStreamWriter(client
.getOutputStream());
BufferedWriter writer=newBufferedWriter(osw);
JSONObject param=newJSONObject();
param.put( " UserName " , userName.replace( " \n " ,"" ));
JSONObject json=this .getJSONData( " Logon " , param);
writer.write(json.toString());
writer.flush();
}catch(IOException e) {
//TODO Auto-generated catch block
e.printStackTrace();
}catch(JSONException e) {
//TODO Auto-generated catch block
e.printStackTrace();
}
}
publicvoidsendMessage(String message) {
Log.d( " initSocket " ," Send " );
try{
OutputStreamWriter osw=newOutputStreamWriter(client
.getOutputStream());
BufferedWriter writer=newBufferedWriter(osw);
JSONArray array=newJSONArray();
for(String item : message.split( " \n " )) {
array.put(item);
}
JSONObject param=newJSONObject();
param.put( " Message " , array);
param.put( " UserName " , ChartInfo.getInstance().getUserName());
JSONObject json=this .getJSONData( " Send " , param);
writer.write(json.toString());
writer.flush();
}catch(IOException e) {
//TODO Auto-generated catch block
e.printStackTrace();
}catch(JSONException e) {
//TODO Auto-generated catch block
e.printStackTrace();
}
}
privateJSONObject getJSONData(String methodName, JSONObject param) {
JSONObject json=newJSONObject();
try{
json.put( " Method " , methodName);
SimpleDateFormat format=newSimpleDateFormat(
" yyyy-MM-dd HH:mm:ss " );
json.put( " DateTime " , format.format( newDate()));
json.put( " Param " , param);
returnjson;
}catch(JSONException e) {
returnnull ;
}
}
}
LogonActivity:
packageld.socket;
importorg.json.JSONException;
importorg.json.JSONObject;
importandroid.app.Activity;
importandroid.app.AlertDialog;
importandroid.content.ComponentName;
importandroid.content.DialogInterface;
importandroid.content.Intent;
importandroid.os.Bundle;
importandroid.os.Handler;
importandroid.os.Message;
importandroid.util.Log;
importandroid.view.KeyEvent;
importandroid.view.View;
importandroid.view.View.OnClickListener;
importandroid.widget.Button;
importandroid.widget.EditText;
publicclassLogonActivityextendsActivity {
privateEditText edtUserName;
privateEditText edtIp;
privateEditText edtPort;
privateButton btnLogon;
@Override
protectedvoidonCreate(Bundle savedInstanceState) {
//TODO Auto-generated method stub
super .onCreate(savedInstanceState);
setContentView(R.layout.logon);
this .initViews();
}
privatevoidinitViews() {
this .edtUserName=(EditText)this .findViewById(R.id.edtUserName);
this .edtIp=(EditText)this .findViewById(R.id.edtIp);
this .edtPort=(EditText)this .findViewById(R.id.edtPort);
this .btnLogon=(Button)this .findViewById(R.id.btnLogon);
this .btnLogon.setOnClickListener( newOnClickListener() {
@Override
publicvoidonClick(View v) {
//TODO Auto-generated method stub
//showAlert(edtUserName.getText().toString());
if(edtUserName.getText().toString().equals( "" )) {
showDialog( " 请输入用户名 " );
return ;
}
if(edtIp.getText().toString().equals( "" )) {
showDialog( " 请输入IP地址 " );
return ;
}
if(edtPort.getText().toString().equals( "" )) {
showDialog( " 请输入端口号 " );
return ;
}
intport=Integer.parseInt(edtPort.getText().toString());
ChartInfo chartInfo=ChartInfo.getInstance();
chartInfo.setIp(edtIp.getText().toString());
chartInfo.setPort(port);
SocketClient proxy=SocketClient.getInstance();
if(proxy==null ) {
showDialog( " 未接入互联网 " );
setWireless();
return ;
}
proxy.putHandler( " Logon " ,newHandler() {
@Override
publicvoidhandleMessage(Message msg) {
SocketClient proxy=SocketClient.getInstance();
proxy.removeHandler( " Logon " );
Log.d( " initSocket " ," handleMessage " );
if(msg==null||msg.obj==null ) {
return ;
}
JSONObject json=(JSONObject) msg.obj;
try{
String userName=json.getString( " UserName " );
Log.d( " initSocket " ," userName: "+userName);
ChartInfo.getInstance().setUserName(userName);
Intent itt=newIntent();
itt
.setClass(LogonActivity. this ,
MainActivity. class );
LogonActivity. this .startActivity(itt);
}catch(JSONException e) {
//TODO Auto-generated catch block
e.printStackTrace();
}
}
});
proxy.logon(edtUserName.getText().toString());
}
});
}
privatevoidsetWireless() {
Intent mIntent=newIntent( " / " );
ComponentName comp=newComponentName( " com.android.settings " ,
" com.android.settings.WirelessSettings " );
mIntent.setComponent(comp);
mIntent.setAction( " android.intent.action.VIEW " );
startActivityForResult(mIntent,0 );
}
privatevoidshowDialog(String mess) {
newAlertDialog.Builder( this ).setTitle( " 信息 " ).setMessage(mess)
.setNegativeButton( " 确定 " ,newDialogInterface.OnClickListener() {
publicvoidonClick(DialogInterface dialog,intwhich) {
}
}).show();
}
@Override
publicbooleanonKeyDown( intkeyCode, KeyEvent event) {
if(keyCode==KeyEvent.KEYCODE_BACK&&event.getRepeatCount()==0 ) {
AlertDialog alertDialog=newAlertDialog.Builder(
LogonActivity. this ).setTitle( " 退出程序 " ).setMessage( " 是否退出程序 " )
.setPositiveButton( " 确定 " ,
newDialogInterface.OnClickListener() {
publicvoidonClick(DialogInterface dialog,
intwhich) {
LogonActivity. this .finish();
}
}).setNegativeButton( " 取消 " ,
newDialogInterface.OnClickListener() {
publicvoidonClick(DialogInterface dialog,intwhich) {
return ;
}
}).create();//创建对话框
alertDialog.show();//显示对话框
returnfalse ;
}
returnfalse ;
}
@Override
protectedvoidonDestroy() {
//TODO Auto-generated method stub
super .onDestroy();
SocketClient proxy=SocketClient.getInstance();
if(proxy!=null ) {
proxy.close();
}
}
}
MainActivity:
packageld.socket;
importorg.json.JSONException;
importorg.json.JSONObject;
importandroid.app.Activity;
importandroid.app.AlertDialog;
importandroid.content.DialogInterface;
importandroid.os.Bundle;
importandroid.os.Handler;
importandroid.os.Message;
importandroid.util.Log;
importandroid.view.KeyEvent;
importandroid.view.View;
importandroid.view.WindowManager;
importandroid.view.View.OnClickListener;
importandroid.widget.Button;
importandroid.widget.EditText;
importandroid.widget.ListView;
publicclassMainActivityextendsActivity {
privateEditText edtMessage;
privateButton btnSend;
privateListView ltvMessage;
privateMessageAdapter adapter;
/**Called when the activity is first created.*/
@Override
publicvoidonCreate(Bundle savedInstanceState) {
super .onCreate(savedInstanceState);
setContentView(R.layout.main);
//隐藏键盘
this .getWindow().setSoftInputMode(
WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
Log.d( " initSocket " ," MessageAdapter " );
this .adapter=newMessageAdapter( this );
Log.d( " initSocket " ," adapter is ok " );
this .findThisViews();
this .initHandler();
this .serOnClick();
Log.d( " initSocket " ," onCreate " );
}
privatevoidfindThisViews() {
this .edtMessage=(EditText)this .findViewById(R.id.edtMessage);
this .btnSend=(Button)this .findViewById(R.id.btnSend);
this .ltvMessage=(ListView)this .findViewById(R.id.ltvMessage);
//this.ltvMessage.setEnabled(false);
this .ltvMessage.setAdapter( this .adapter);
}
privatevoidinitHandler() {
Handler handler=newHandler() {
@Override
publicvoidhandleMessage(Message msg) {
if(msg.obj==null ) {
Log.d( " initSocket " ," handleMessage is null " );
return ;
}
Log.d( " initSocket " ," handleMessage " );
try{
JSONObject json=(JSONObject) msg.obj;
String userName=json.getString( " UserName " );
StringBuilder sb=newStringBuilder();
intlength=json.getJSONArray( " Message " ).length();
for( inti=0 ; i<length; i ++ ) {
String item=json.getJSONArray( " Message " ).getString(i);
if(item.equals( "" )) {
continue ;
}
if(length>i+1 ) {
Log.d( " initSocket " ," length: "+length);
Log.d( " initSocket " ," i: "+i);
Log.d( " initSocket " ," item: "+item);
item+=" \n " ;
}
sb.append(item);
}
MessageRecord record=newMessageRecord();
record.setUserName(userName);
record.setMessage(sb.toString());
MainActivity. this .adapter.add(record);
adapter.notifyDataSetChanged();
}catch(JSONException e) {
//TODO Auto-generated catch block
e.printStackTrace();
}
}
};
SocketClient proxy=SocketClient.getInstance();
proxy.putHandler( " Send " , handler);
}
privatevoidserOnClick() {
this .btnSend.setOnClickListener( newOnClickListener() {
@Override
publicvoidonClick(View v) {
//TODO Auto-generated method stub
btnSend.setEnabled( false );
String txt=edtMessage.getText().toString();
if(txt.equals( "" )) {
btnSend.setEnabled( true );
return ;
}
SocketClient proxy=SocketClient.getInstance();
proxy.sendMessage(txt);
edtMessage.setText( "" );
btnSend.setEnabled( true );
}
});
}
@Override
publicbooleanonKeyDown( intkeyCode, KeyEvent event) {
if(keyCode==KeyEvent.KEYCODE_BACK&&event.getRepeatCount()==0 ) {
AlertDialog alertDialog=newAlertDialog.Builder(
MainActivity. this ).setTitle( " 询问 " ).setMessage( " 是否注销登录? " )
.setPositiveButton( " 确定 " ,
newDialogInterface.OnClickListener() {
publicvoidonClick(DialogInterface dialog,
intwhich) {
MainActivity. this .finish();
}
}).setNegativeButton( " 取消 " ,
newDialogInterface.OnClickListener() {
publicvoidonClick(DialogInterface dialog,intwhich) {
return ;
}
}).create();//创建对话框
alertDialog.show();//显示对话框
returnfalse ;
}
returnfalse ;
}
}
五、运行效果
代码下载