仿qq聊天及定位等
聊天其實就是要實現消息推送,而推送消息就需要保持連接(長連接)。在之前項目裏雖然實現了即時聊天,但是一種很本的方法。去掉了其中的網絡訪問。地圖試用的百度API
還是先放上圖,在說下做法。






具體做法就是,開啟一個服務,在後台每隔10秒鍾訪問一起(Socket)服務器,如果有數據,則返回數據,客戶端進行解析,然後發送廣播,即可接收到消息。
發送消息,則是由服務器提供接口來發送。然後,服務器與客戶端建立一個簡單的通信協議。
如:MSG|發送人ID|2012-2-12 07:25:12|發送類型 MSG是個標識,類型包括文本(包含表情),圖片,語音,位置等。
圖片和語音的發送,都是通過FTP先上傳文件到服務器,然後把本地存儲的路徑發送給對方。
在聊天的頁麵中,用戶的頭像都是在本地存的。包括聊天的信息,也是本地數據庫存的。這樣就能記錄信息。也可以擴展把聊天記錄導出。
在本地創建的 消息數據庫中。要定義好聊天信心的字段,包括自己ID,好友ID,消息類型,文本內容,時間,是否已讀等(可擴展)
01
02
03
04
05
06
07
08
09
|
private
String table = "CREATE TABLE IF NOT EXISTS message("
+
"_id integer PRIMARY KEY,"
+
"TtmType integer ,"
+
"TtmTuID integer ,"
+
"TtmToUserId integer ,"
+
"TtmContent text ,"
+
"TtmTime varchar(200) ,"
+
"isRead integer ,"
+
"isReplyLocation integer )" ;
|
這樣再次進入聊天頁麵就可以把數據庫的內容讀出來,匹配到適配器
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
|
public
List<DetailEntity> getdatas( int
TtmTuID, int TtmToUserId) {
List<DetailEntity> de = new
ArrayList<DetailEntity>();
SQLiteDatabase database = dbmanger.getWritableDatabase();
Cursor cursor = database
.rawQuery(
"select * from message where (TtmTuID = ? and TtmToUserId = ?) or (TtmToUserId = ? and TtmTuID = ?) order by _id" ,
new
String[] { String.valueOf(TtmTuID),
String.valueOf(TtmToUserId),
String.valueOf(TtmTuID),
String.valueOf(TtmToUserId)});
while (cursor.moveToNext()) {
de.add( new
DetailEntity(cursor.getInt( 1 ), cursor.getInt( 2 ), cursor
.getInt( 3 ), cursor.getString( 4 ), cursor.getString( 5 ),cursor.getInt( 6 ),cursor.getInt( 7 )));
}
cursor.close();
database.close();
return de;
}
|
圖片的查看和語音的播放,都需要從數據庫裏取出文件保存的路徑,不然的會顯示和播放都不正確。
仔細看源碼的話發現,在進入頁麵適配數據的時候已經從數據庫讀取內容了,而在適配器中查看圖片,又重新讀取了一次,
主要是因為,不這樣做還是不能正確顯示和播放。 對這個問題很費解。
進入到聊天頁麵,換取到數據,很據數據類型來加載對應的layout,當然還要判斷用戶ID,信息的讀取是根據用戶ID來獲取的
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
|
messageList = MessageSQLService.getInstance( this ).getdatas(
Integer.valueOf(UserInfomation.getUserID(TalkMessageAct. this )),
Integer.valueOf(TFuid));
for
( int i =
0 ; i < messageList.size(); i++) {
switch
(messageList.get(i).getTtmType()) {
case
1 :
int id = Integer.valueOf(messageList.get(i).getTtmTuID());
if (id == Integer.valueOf(TFuid)) {
} else
if (id == Integer.valueOf(UserInfomation
.getUserID(TalkMessageAct. this ))) {
}
break ;
case
2 :
int ids = Integer.valueOf(messageList.get(i).getTtmTuID());
if (ids == Integer.valueOf(TFuid)) {
} else
if (ids == Integer.valueOf(UserInfomation
.getUserID(TalkMessageAct. this ))) {
}
break ;
case
3 :
int idsx = Integer.valueOf(messageList.get(i).getTtmTuID());
if (idsx == Integer.valueOf(TFuid)) {
} else
if (idsx == Integer.valueOf(UserInfomation
.getUserID(TalkMessageAct. this ))) {
}
break ;
case
5 :
break ;
case
6 :
int idsxx = Integer.valueOf(messageList.get(i).getTtmTuID());
if (idsxx == Integer.valueOf(TFuid)) {
} else
if (idsxx == Integer.valueOf(UserInfomation
.getUserID(TalkMessageAct. this ))) {
}
break ;
}
} |
之前在測試中,用socket實現不了長連接。主要是因為不加上 socket.shutdownOutput();就收不到消息,而加上了即接收完消息斷了連接。所以每隔10秒就要訪問次Socket服務器
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
|
socket =
new Socket(Constants.SOCKET_IP, Constants.SOCKET_PORT);
if
(socket.isConnected()) {
out = new
PrintWriter( new
BufferedWriter(
new
OutputStreamWriter(socket.getOutputStream())), true );
out.write( "Lgn|" +
UserInfomation.getUserID(TalkMessageServer. this )+ "|" +
UserInfomation.getUserPW(TalkMessageServer. this ));
out.flush();
socket.shutdownOutput();
}
reader =
new BufferedReader( new
InputStreamReader(
socket.getInputStream()));
while
((line = reader.readLine()) != null ) {
if (line !=
null ) {
//截取字符,讀取信息的操作
}
|
雖然實現了,但在實際的應用中,效果不好。費電,丟包。
當然了,現在正在往長連接方向該,也修改了通信協議(很規範),(SocketChannel,Selector)
最後放上源碼

最後更新:2017-04-03 14:54:25