鉴于自己的痛苦,研究一个socket在多个界面切换时保持链接的问题,令我纠结很久,现在我提供客户端的源码给有需要的人参考。
1、ApplicationUtil类:
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;
import android.app.Application;
public class ApplicationUtil extends Application{
private Socket socket;
private DataOutputStream out = null;
private DataInputStream in = null;
public void init() throws IOException, Exception{
this.socket = new Socket("192.168.1.104",10202);
this.out = new DataOutputStream(socket.getOutputStream());
this.in = new DataInputStream(socket.getInputStream());
}
public Socket getSocket() {
return socket;
}
public void setSocket(Socket socket) {
this.socket = socket;
}
public DataOutputStream getOut() {
return out;
}
public void setOut(DataOutputStream out) {
this.out = out;
}
public DataInputStream getIn() {
return in;
}
public void setIn(DataInputStream in) {
this.in = in;
}
}
AndroidMainifest.xml中application的配置:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.login"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="10"
android:targetSdkVersion="15" />
<application
android:name="com.util.ApplicationUtil"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name=".LoginActivity"
android:label="@string/title_activity_main" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".MainActivity"/>
</application>
<!-- 振动需要的权限 -->
<uses-permission android:name="android.permission.VIBRATE"/>
<!-- 声明网络权限 -->
<uses-permission android:name="android.permission.INTERNET"/>
</manifest>
2、LoginActivity类:
import java.io.BufferedWriter;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
import com.login.R;
import com.util.ApplicationUtil;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
public class LoginActivity extends Activity{
private EditText usernameT;
private EditText passwordT;
private Button loginButton;
private Socket socket;
private DataOutputStream out;
private DataInputStream in;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.login);
usernameT = (EditText) findViewById(R.id.username);
passwordT = (EditText) findViewById(R.id.password);
loginButton = (Button) findViewById(R.id.login);
loginButton.setOnClickListener(new OnClickListener(){
public void onClick(View v) {
ApplicationUtil appUtil = (ApplicationUtil) LoginActivity.this.getApplication();
try {
appUtil.init();
Socket socket = appUtil.getSocket();
out = appUtil.getOut();
in = appUtil.getIn();
} catch (IOException e1) {
e1.printStackTrace();
} catch (Exception e1) {
e1.printStackTrace();
}
String username = usernameT.getText().toString();
String password = passwordT.getText().toString();
MD5 md5 = new MD5();
String ss = md5.MD5(username+"|"+password);
try {
//发送数据
String str = "[login]|"+ss;
out.writeBytes(str);
out.flush();
System.out.println("str ===> "+str);
//创建一个缓冲字节数
int r = in.available();
while(r==0){
r = in.available();
}
byte[] b = new byte[r];
in.read(b);
String result = new String(b,"utf-8");
System.out.println("result = "+result);
if(result.equals("登陆成功0")){
Intent intent = new Intent();
intent.setClass(LoginActivity.this, MainActivity.class);
startActivity(intent);
}
else
{
Intent intent = new Intent();
intent.setClass(LoginActivity.this, MainActivity.class);
startActivity(intent);
}
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
});
}
}
3、MainActivity类:
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import com.image.TestActivity;
import com.login.R;
import com.util.ApplicationUtil;
import android.media.RingtoneManager;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.provider.MediaStore.Audio;
import android.app.Activity;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
public class MainActivity extends Activity {
private EditText mess;
private Socket socket;
private Handler handler;
private DataInputStream in;
private NotificationManager nm;
private Notification n;
private int messageNotificationID = 0;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.success);
mess = (EditText) findViewById(R.id.message);
ApplicationUtil appUtil = (ApplicationUtil) MainActivity.this.getApplication();
socket = appUtil.getSocket();
in = appUtil.getIn();
handler = new Handler(){
@Override
public void handleMessage(Message msg) {
//如果来自子线程
if(msg.what == 0x123){
mess.append(msg.obj.toString()+"\n");
//消息通知
mynoti();
}
}
};
//调用线程
myThread();
}
//JAVA可以设置读写缓冲区的大小-setReceiveBufferSize(int size), setSendBufferSize(int size)。
public void myThread(){
Thread oneThread = new Thread(new Runnable(){
public boolean isRunning = true;
public void run() {
while(isRunning){
try {
Thread.sleep(1000);
//创建一个缓冲字节数
int r = in.available();
while(r==0){
r = in.available();
}
byte[] b = new byte[r];
in.read(b);
String content = new String(b,"utf-8");
//每当读到来自服务器的数据后,发送消息通知程序页面显示数据
Message msg = new Message();
msg.what = 0x123;
msg.obj = content;
Log.v("ho", content);
handler.sendMessage(msg);
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
oneThread.start();
}
public void mynoti(){
NotificationManager mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
// 创建一个通知
Notification mNotification = new Notification();
//用系统自带的铃声
mNotification.sound = Uri.withAppendedPath(Audio.Media.INTERNAL_CONTENT_URI, "6");
// mNotification.sound = Uri.parse("file:///sdcard/wen.mp3");
//mNotification.defaults=Notification.DEFAULT_SOUND;
//Notification.FLAG_INSISTENT; //让声音、振动无限循环,直到用户响应
//Notification.FLAG_AUTO_CANCEL; //通知被点击后,自动消失
//Notification.FLAG_NO_CLEAR; //点击'Clear'时,不清楚该通知(QQ的通知无法清除,就是用的这个)
mNotification.flags = Notification.FLAG_NO_CLEAR; ;
//通知时发出的振动
//第一个参数: 振动前等待的时间
//第二个参数: 第一次振动的时长、以此类推
long[] vir = {0,100,200,300};
mNotification.vibrate = vir;
mNotificationManager.notify(messageNotificationID, mNotification);
messageNotificationID++;
}
}
4、MD5类:
import java.security.MessageDigest;
public class MD5 {
// MD5加码。32位
public static String MD5(String inStr) {
MessageDigest md5 = null;
try {
md5 = MessageDigest.getInstance("MD5");
} catch (Exception e) {
System.out.println(e.toString());
e.printStackTrace();
return "";
}
char[] charArray = inStr.toCharArray();
byte[] byteArray = new byte[charArray.length];
for (int i = 0; i < charArray.length; i++)
byteArray[i] = (byte) charArray[i];
byte[] md5Bytes = md5.digest(byteArray);
StringBuffer hexValue = new StringBuffer();
for (int i = 0; i < md5Bytes.length; i++) {
int val = ((int) md5Bytes[i]) & 0xff;
if (val < 16)
hexValue.append("0");
hexValue.append(Integer.toHexString(val));
}
return hexValue.toString();
}
}
6、login.xml和success.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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:orientation="vertical">
<TableLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
>
<TableRow>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="账号:"
/>
<EditText
android:id="@+id/username"
android:layout_width="200dp"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginTop="10dp"
android:layout_marginRight="10dp"
android:hint="账号"
/>
</TableRow>
<TableRow>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="密码:"
/>
<EditText
android:id="@+id/password"
android:password="true"
android:layout_width="200dp"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginTop="10dp"
android:layout_marginRight="10dp"
android:hint="密码"
/>
</TableRow>
</TableLayout>
<Button
android:id="@+id/login"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginTop="10dp"
android:layout_marginRight="10dp"
android:text="登录"
/>
</LinearLayout>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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:orientation="vertical">
<TextView
android:id="@+id/success"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="不断接受信息,并提示"
/>
<EditText
android:id="@+id/message"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:cursorVisible="false"
/>
</LinearLayout>
以上都是客户端,服务端就自己写,socket代码差不多。
运行效果: