Android之高仿QQ聊天

    國慶這幾天,閑著無聊,仿照QQ2012,做瞭一個基於socket的聊天工具,由於代碼比較多,我就不在文章中貼出代碼,需要的朋友可以點擊上面下載,謝謝,有什麼問題或者bug,歡迎給我留言。

        首先說一下我的整體思路:整個聊天是通過服務器轉發的,這樣處理起來比較簡單,但是服務器壓力會特別大。建議在真正做項目的時候,服務器隻處理用戶註冊、登錄以及判斷用戶是否掉線等,至於聊天、傳文件以及視頻等就在用戶之間單獨建立連接,這樣可以大大減少服務器的壓力,我這裡就沒考慮這麼多瞭。

        第一:我們定義一個超級消息對象(記得要序列化),它包含:消息類型、具體的消息對象、發送給誰以及來自誰。服務器和客戶端就是通過發送這個超級消息對象來進行通訊的。

        第二:服務器,在接受用戶連接之後,馬上把socket丟入線程池中,這樣可以支持多用戶並發訪問,然後根據用戶的socket對象,分別建立一條讀消息線程和寫消息線程(在這裡,寫消息線程要先建立,我們需要傳遞給讀消息線程,因為我們在讀完消息之後會給用戶回復消息)。在讀消息線程裡面根據消息類型處理超級消息對象,分別是:註冊、登錄、下線、轉發消息、文件、刷新好友列表等。後臺數據庫處理的話,我們通過dao模式,這樣很方便,而且會使代碼顯得簡潔、明瞭、有條理,總之是各種好,哈哈。最後要註意一點:因為我們是轉發消息,所以在用戶登錄成功後,我們需要把該用戶的寫消息線程根據用戶的ID存入一個Map中,以便在轉發消息的時候,可以根據用戶ID取出對應的寫消息線程,從而實現轉發消息。

       第三:客戶端,跟服務器類似,隻是沒有線程池,在用戶連接上服務器之後,也是根據連接後的socket對象,分別建立一條讀消息線程和寫消息線程。然後在代碼中哪裡需要發消息,就通過get方法獲取寫消息線程,哪裡需要讀消息,就通過get方法獲取讀消息線程。

        第四:關於寫消息線程處理,因為服務器或者客戶端,不可能時時需要寫消息,因此我們如果用一個死循環去處理寫線程,明顯的是不明智的,因此我做瞭一個簡單的處理,在寫消息的死循環中先wait(),當我們調用寫消息線程的setMessage方法後,就notify喚醒寫線程,發送完消息之後,繼續wait(),這裡我貼出核心代碼:

[java] 

<span style="font-size:14px;">  public void setMsg(TranObject msg) { 
        this.msg = msg; 
        synchronized (this) { 
            notify(); 
        } 
    } 
 
    @Override 
    public void run() { 
        try { 
            while (isStart) { 
                if (msg != null) { 
                    oos.writeObject(msg); 
                    oos.flush(); 
                    if (msg.getType() == TranObjectType.LOGOUT) {// 如果是發送下線的消息,就直接跳出循環 
                        break; 
                    } 
                    synchronized (this) { 
                        wait();// 發送完消息後,線程進入等待狀態 
                    } 
                } 
            } 
            oos.close();// 循環結束後,關閉輸出流和socket 
            if (socket != null) 
                socket.close(); 
        } catch (InterruptedException e) { 
            e.printStackTrace(); 
        } catch (IOException e) { 
            e.printStackTrace(); 
        } 
    }</span> 

        第五:具體手機客戶端的處理,因為android有自己的特點,也有自己的優勢,所以我們要充分利用它的優勢,避開他的缺點來處理消息,我說一下我在這個小項目中處理消息的思路:我在用戶啟動程序的時候,開啟一個獲取消息的service,在該service中建立連接,然後通過一個接口去監聽讀消息線程收到的消息,在收到消息的同時,把該超級消息對象通過廣播發送出去,然後自定義一個抽象的MyActivity繼承Activity,在MyActivity裡面通過一個廣播接收者接收service中發送過來的消息,並通過一個抽象方法傳遞給子Activity,我們的其他activity如果要處理收消息,就可以繼承我們自定義的MyActivity,然後實現那個抽象方法,就可以瞭,這樣很好的處理瞭不同的activity接收消息的缺點,而且後臺處理也很方便,我不知道騰訊QQ在這個方面是怎麼處理的,這是我個人的想法而已。下面貼出MyActivity的代碼:

[java]

<span style="font-size:14px;">/**
 * 自定義一個抽象的MyActivity類,每個Activity都繼承他,實現消息的接收(優化性能,減少代碼重復)
 * 
 * @author way
 * 
 */ 
public abstract class MyActivity extends Activity { 
    /**
     * 廣播接收者,接收GetMsgService發送過來的消息
     */ 
    private BroadcastReceiver MsgReceiver = new BroadcastReceiver() { 
 
        @Override 
        public void onReceive(Context context, Intent intent) { 
            TranObject msg = (TranObject) intent 
                    .getSerializableExtra(Constants.MSGKEY); 
            if (msg != null) {//如果不是空,說明是消息廣播 
                // System.out.println("MyActivity:" + msg); 
                getMessage(msg);// 把收到的消息傳遞給子類 
            } else {//如果是空消息,說明是關閉應用的廣播 
                close(); 
            } 
        } 
    }; 
 
    /**
     * 抽象方法,用於子類處理消息,
     * 
     * @param msg
     *            傳遞給子類的消息對象
     */ 
    public abstract void getMessage(TranObject msg); 
 
    /**
     * 子類直接調用這個方法關閉應用
     */ 
    public void close() { 
        Intent i = new Intent(); 
        i.setAction(Constants.ACTION); 
        sendBroadcast(i); 
        finish(); 
    } 
 
    @Override 
    public void onStart() {// 在start方法中註冊廣播接收者 
        super.onStart(); 
        IntentFilter intentFilter = new IntentFilter(); 
        intentFilter.addAction(Constants.ACTION); 
        registerReceiver(MsgReceiver, intentFilter);// 註冊接受消息廣播 
 
    } 
 
    @Override 
    protected void onStop() {// 在stop方法中註銷廣播接收者 
        super.onStop(); 
        unregisterReceiver(MsgReceiver);// 註銷接受消息廣播 
    } 

</span> 
 

       好瞭,大概思路就是這樣的,下面根據具體的測試截圖,說說我的思路:

1.桌面快捷方式                                                                         2.歡迎界面

       

 

3.正在登陸                                                                                 4.登陸成功後的好友列表,通過ActivityGroup實現

      

 

5.好友列表是自定義的ExpandableListView,可以下拉刷新        6.群組功能未實現

                 

 

7.聊天主界面,                                                                             8.程序後臺運行的界面

        

 

9.好友上線提醒                                                                         10.未進入聊天界面,來消息提醒

      

 

11.後臺運行來消息時提醒,有聲音有振動

 

 

12.後臺數據庫,密碼通過MD5方式加密瞭,用戶註冊成功後,即生成一個以用戶id命名的表,用來保存好友。

 

 

13.服務器運行提示

 

 

14.註冊成功後的提示窗

 

 

最後來幾張聊天截圖,好瞭今天就到這裡,大傢有什麼好的建議,歡迎提,謝謝

 

You May Also Like