Android Service+Socket 聯網交互

   android中,聯網操做有http鏈接和socket鏈接兩大類。因爲項目須要,咱們採起的是Socket鏈接。鑑於平時鏈接頻繁,所以把Socket鏈接放到Service裏,須要從服務器端獲取數據時,只要調用Service中相應方法便可。

Service大體結構是:

public class InternetService extends Service implements Runnable {

    private Socket socket;

    private BufferedReader reader;//

    private PrintWriter writer;//

    private Binder binder;

    private Thread td;// 線程,獲取服務器端發送來的消息

    private String workStatus;// 當前工做情況,null表示正在處理,success表示處理成功,failure表示處理失敗

    private String currAction; //標記當前請求頭信息,在獲取服務器端反饋的數據後,進行驗證,以避免出現反饋信息和當前請求不一致問題。好比如今發送第二個請求,但服務器端此時才響應第一個請求
    
  /**
     * 向服務器發送請求
     * 
     * @param action
     *            
     */
    public void sendRequest(String action) {
        try {
            workStatus = null;
            JSONObject json = new JSONObject();
            json.put("action", action);
            currAction=action;
            sendMessage(json);
        } catch (Exception ex) {
            workStatus = Constant.TAG_FAILURE;
            ex.printStackTrace();
        }
    }
    /**
     *  返回當前workStatus的值
     * /
public StringgetWorkStatus()
{
   return workStatus ;
}

    /**
     * 處理服務器端反饋的數據
     * 
     * @param json
     *            
     */
    private void  dealUploadSuperviseTask(JSONObject json)
    {
        try{
            workStatus=json.getString("result");
        }catch(Exception ex)
        {
            ex.printStackTrace();
            workStatus=Constant.TAG_FAILURE;
        }
    }

    /**
     * 退出程序時,關閉Socket鏈接
     */
    public void closeConnection() {

        JSONObject json = new JSONObject();// 向服務器端發送斷開鏈接請求
        try {
            json.put("action", "exit");
            sendMessage(json);// 向服務器端發送斷開鏈接請求
            Log.v("qlq", "the request is " + json.toString());
        } catch (Exception ex) {

            ex.printStackTrace();
        }
    }

    /**
     * 鏈接服務器
     */
    private void connectService() {
        try {
            socket = new Socket();
            SocketAddress socAddress = new InetSocketAddress(127.0.0,
                    8000));
            socket.connect(socAddress, 3000);

            reader = new BufferedReader(new InputStreamReader(
                    socket.getInputStream(), "GBK"));

            writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(
                    socket.getOutputStream(), "GBK")), true);

        } catch (SocketException ex) {
            Log.v("QLQ", "socketException ");
            ex.printStackTrace();
            workStatus = Constant.TAG_CONNECTFAILURE;// 若是是網絡鏈接出錯了,則提示網絡鏈接錯誤
            return;
        } catch (SocketTimeoutException ex) {
            ex.printStackTrace();
            workStatus = Constant.TAG_CONNECTFAILURE;// 若是是網絡鏈接出錯了,則提示網絡鏈接錯誤
            return;
        } catch (Exception ex) {
            ex.printStackTrace();
            workStatus = Constant.TAG_CONNECTFAILURE;// 若是是網絡鏈接出錯了,則提示網絡鏈接錯誤
            return;
        }
    }
    /**
     * 向服務器發送傳入的JSON數據信息
     * 
     * @param json
     */
    private void sendMessage(JSONObject json) {
        if (!isNetworkConnected())// 若是當前網絡鏈接不可用,直接提示網絡鏈接不可用,並退出執行。
        {
            Log.v("QLQ", "workStatus is not connected!111");
            workStatus = Constant.TAG_CONNECTFAILURE;
            return;
        }
        if (socket == null)// 若是未鏈接到服務器,建立鏈接
            connectService();
        if (!InternetService.this.td.isAlive())// 若是當前線程沒有處於存活狀態,重啓線程
            (td = new Thread(InternetService.this)).start();
        if (!socket.isConnected() || (socket.isClosed())) // isConnected()返回的是是否曾經鏈接過,isClosed()返回是否處於關閉狀態,只有當isConnected()返回true,isClosed()返回false的時候,網絡處於鏈接狀態
        {
            Log.v("QLQ", "workStatus is not connected!111222");
            for (int i = 0; i < 3 && workStatus == null; i++) {// 若是鏈接處於關閉狀態,重試三次,若是鏈接正常了,跳出循環
                socket = null;
                connectService();
                if (socket.isConnected() && (!socket.isClosed())) {
                    Log.v("QLQ", "workStatus is not connected!11333");
                    break;
                }
            }
            if (!socket.isConnected() || (socket.isClosed()))// 若是此時鏈接仍是不正常,提示錯誤,並跳出循環
            {
                workStatus = Constant.TAG_CONNECTFAILURE;
                Log.v("QLQ", "workStatus is not connected!111444");
                return;
            }

        }

        if (!socket.isOutputShutdown()) {// 輸入輸出流是否關閉
            try {
                writer.println(json.toString());
            } catch (Exception e) {
                // TODO Auto-generated catch block
                Log.v("QLQ", "workStatus is not connected!55555666666");
                e.printStackTrace();
                workStatus = Constant.TAG_FAILURE;
            }
        } else {
            workStatus = Constant.TAG_CONNECTFAILURE;
        }
    }

    /**
     * 處理服務器端傳來的消息,並經過action頭信息判斷,傳遞給相應處理方法
     * 
     * @param str
     */
    private void getMessage(String str) {
        try {
            JSONObject json = new JSONObject(str);
            String action = json.getString("action");// 提取JSON的action信息,獲取當前JSON響應的是哪一個操做。
            if(!currAction.equals(action))
                return;
            if (action.equals("getCategory")) {
                dealUploadSuperviseTask(json);
            } 
        } catch (Exception ex) {
            ex.printStackTrace();
            workStatus=Constant.TAG_FAILURE;
        }
    }
    
    
    
    public class InterBinder extends Binder {

        public InternetService getService() {
            return InternetService.this;
        }
    }

    @Override
    public IBinder onBind(Intent intent) {
        // TODO Auto-generated method stub
        binder = new InterBinder();
        td = new Thread(InternetService.this);// 啓動線程
        td.start();

        return binder;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        // connectService();
    }

    @Override
    public void onStart(Intent intent, int startId) {
        super.onStart(intent, startId);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.v("QLQ", "Service is on destroy");
    }

    @Override
    public boolean onUnbind(Intent intent) {
        Log.v("QLQ", "service on onUnbind");
        return super.onUnbind(intent);
    }

    /**
     * 循環,接收從服務器端傳來的數據
     */
    public void run() {
        try {
            while (true) {
                Thread.sleep(500);// 休眠0.5s
                if (socket != null && !socket.isClosed()) {// 若是socket沒有被關閉
                    if (socket.isConnected()) {// 判斷socket是否鏈接成功
                        if (!socket.isInputShutdown()) {
                            String content;
                            if ((content = reader.readLine()) != null) {
                                getMessage(content);
                            }
                        }
                    }
                }
            }
        } catch (Exception ex) {

            try {
                socket.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
            workStatus = Constant.TAG_CONNECTFAILURE;// 若是出現異常,提示網絡鏈接出現問題。
            ex.printStackTrace();
        }
    }

}
在前臺頁面上,因爲前臺和後臺要進行數據交互,所以須要使用bindService方法綁定服務。
InternetService innetService ;
public ServiceConnection internetServiceConnection = new ServiceConnection() {

        public void onServiceConnected(ComponentName arg0, IBinder service) {
            innetService = ((InternetService.InterBinder) service).getService();
        }

        public void onServiceDisconnected(ComponentName arg0) {

            innetService = null;
        }

    };

而後在onCreate裏,執行
bindService(new Intent(BasicActivity.this, InternetService.class),
                internetServiceConnection, Context.BIND_AUTO_CREATE);//BasicActivity是我本身爲全部Activity定義的基類,這段代碼也是寫在BasicActivity裏。

因爲服務綁定後必需要解除,所以在onDestroy中應加上代碼
unbindService(internetServiceConnection);

之因此定義workStatus,是爲了讓前臺知道當前聯網操做是否成功。
而定義currAction,則是爲了標識好當前請求內容,因爲服務器端反饋的信息上也有action頭信息標識當前返回的數據對應哪一種請求,因此,在發送請求時設置currAction,接收到服務器端反饋數據後,驗證和currAction是否一致,若是不一致的話,就不做處理,表示「未等到但願的數據」,若是一致,才能執行下一步操做。這樣能夠防止數據匹配錯誤。
至於定義BasicActivity,則是由於軟件中不少頁面除了中間顯示的內容外,頭部按鈕欄等都一致,此外還有不少共用的代碼等,所以定義一個BasicActivity,做爲他們的父類,減小代碼量,這也是java多態的一種體現。java

相關文章
相關標籤/搜索