2013-02-14 18 views
0

我正在開發一個基於套接字的應用程序,在這個應用程序中,我不斷更新房間的狀態,例如多少個燈開關。我有7種這樣的房間,我需要更新每個房間的狀態。使用多個服務或在單個服務中執行所有操作哪個更好?

所以我的問題是我應該爲每個房間創建一個單獨的服務,否則我應該在單個服務中執行所有操作?就性能而言,哪種方式會更方便。

這是我單人房的服務類。

public class UpdateUiService extends Service 
{ 
    @Override 
    public void onCreate() { 
     super.onCreate(); 
     intent = new Intent(BROADCAST_ACTION); 
     try { 
      s = new Socket("192.168.1.19,502); 
      i = s.getInputStream(); 
      o = s.getOutputStream(); 
      System.out.println("connected"); 
     } catch (UnknownHostException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } catch (IOException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 
    } 

    @Override 
    public void onStart(Intent intent, int startId) { 
     handler.removeCallbacks(sendUpdatesToUI); 
     handler.postDelayed(sendUpdatesToUI, 1000); // 1 second 

    } 

    private Runnable sendUpdatesToUI = new Runnable() { 
     public void run() { 
      DisplayLoggingInfo(); 
      handler.postDelayed(this, Integer.parseInt(interval_dinning)); 
     } 
    }; 

    private void DisplayLoggingInfo() { 
     try { 
      byte[] data1 = new byte[1024], packet1 = 
      { 
       (byte) 0x00,(byte) 0x00,(byte) 0x00, 
       (byte) 0x00,(byte) 0x00,(byte) 0x06, 
       (byte) 0x01,(byte) 0x01,(byte) 0x00, 
       (byte) 0x00,(byte) 0x00,(byte) 0x19 
      }; 

      o.write(packet1); 
      i.read(data1, 0, 1024); 

      byte_to_hex = ConversionMethods.bytesToHex(data1).substring(18, 26); 

      char[] arr = byte_to_hex.toCharArray(); 
      for (int i = 0; i < arr.length - 1; i += 2) { 
       char temp = arr[i]; 
       arr[i] = arr[i + 1]; 
       arr[i + 1] = temp; 
      } 

      swapped_result = new String(arr); 
      result = ConversionMethods.hexStringToNBitBinary(swapped_result, 32); 
      int counter_ = 0; 
      for(int i=0; i<result.length(); i++) 
      { 
       if(result.charAt(i) == '1') 
       { 
        counter_++;   
       } 
      } 
      status=Integer.toString(counter_); 

     } catch (UnknownHostException e) { 
      e.printStackTrace(); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 

     intent.putExtra("counter", String.valueOf(++counter)); 
     intent.putExtra("status", status); 
     sendBroadcast(intent); 
    } 
} 

而我開始這項服務,並獲得廣播意圖的活動,我想要顯示此值。這裏是update UI from background service的參考鏈接。

如何使用多線程實現此目的。我的最終目標是讀取套接字並獲得結果。

請指點我一個正確的方向。任何建議和想法將不勝感激。

感謝

+0

你在問什麼?如何更改服務以連接到不同的遠程地址? – Jin35 2013-02-21 12:44:38

+0

@ Jin35我有不同的房間,每個房間都使用不同的IP連接,所以我想知道不同房間的狀態,以上實施僅適用於單間。如果我更改IP,它會給我其他房間的狀態。 – juned 2013-02-21 13:19:47

回答

1

問題

一)它不是從你的代碼是什麼開始你的服務明顯。它啓動一次還是多次?

根據目前的代碼,它看起來會發送一些東西到IP,讀取結果,發送一個廣播,就是這樣。

所以,問題是,你需要更新燈光狀態一次,還是需要不斷/定期更新燈光狀態?

理念

一)在這種情況下,如果你需要更新燈狀態了一次,並且它是從UI和更新UI觸發,你將與AsyncTask這是專門爲此設計好得多。

您是否想要7個併發AsyncTask(如果要並行更新燈光狀態),或者您可以有一個AsyncTask,它將連續更新燈光狀態並在每個燈光後向UI線程報告已更新。 b)在這種情況下,如果您需要連續跟蹤燈光狀態,那麼您最好使用服務。但是,您需要在此服務中有一個長時間運行的線程。所以,你應該在onStart中啓動一個線程。

一般來說,它應該(比如說在10秒內一次)調用一些會引起所有通信等的方法。在這個方法中,你可以刺激X線程(每個房間一個線程),並在這些線程中執行所有操作(寫入套接字,讀取,解析等),或者可以在第一個線程中執行所有這些操作。您在這裏與AsyncTask具有相同的選擇,以並行或串行方式執行此操作。

c)此外,您可能希望保持所有套接字處於活動狀態並重新使用它們,以便在需要更新燈光狀態時每5秒不重新連接。

一般評論

a)你正在使用它被廢棄在onStart()。你應該使用onStartCommand()

b)我明白它可能是一個原型,但你顯示的這段代碼質量相當低。如果你不清理,就會有很多的bug,在未來追逐:

你有代碼:

  • 很多神奇數字
  • 名不副實的功能(如DisplayLoggingInfo ,它不顯示任何東西,而是讀/寫插槽,做一些轉換和發送廣播)
  • 長方法(DisplayLoggingInfo)

更新1

以下是您的示例應用程序。 請注意,這是一個原型。您可能有興趣添加更多支票,將其分爲更多課程等。

MyService.java

package com.example.servicesample; 

import android.app.Service; 
import android.content.Intent; 
import android.os.IBinder; 
import java.lang.Thread; 
import android.support.v4.content.LocalBroadcastManager; 

public class MyService extends Service implements Runnable { 
    public static final String ROOM_STATUS_BROADCAST = "com.example.room_status_broadcast"; 
    public static final String ROOM_STATUS_BROADCAST_EXTRA_ROOM_NUMBER = "roomnumber"; 
    public static final String ROOM_STATUS_BROADCAST_EXTRA_STATUS = "status"; 

    static final int NUM_ROOMS = 7; 
    static final int TIME_FOR_A_REST = 5000; //ms 

    Thread mThread = null; 
    Boolean mRunning = false; 

    @Override 
    public void onCreate() { 
    } 

    @Override 
    public IBinder onBind(Intent intent) { 
     return null; 
    } 

    @Override 
    public int onStartCommand(Intent intent, int flags, int startId) { 
     start(); 

     return START_STICKY; 
    } 

    @Override 
    public void onDestroy() { 
     stop(); 
    } 

    private synchronized void start() 
    { 
     if (mThread != null) 
      return; 

     mRunning = true; 
     mThread = new Thread(this); 
     mThread.start(); 
    } 

    private synchronized void stop() 
    { 
     if (mThread == null) 
      return; 

     mRunning = true; 

     try 
     { 
      mThread.join(); 
     } catch (InterruptedException e) {} 
     mThread = null; 
    } 


    public void run() 
    { 
     while (mRunning) 
     { 
      for (int i = 0; i < NUM_ROOMS; i++) 
       updateRoomStatus(i); 

      try 
      { 
       Thread.sleep(TIME_FOR_A_REST); 
      } catch (InterruptedException e) {}    
     } 
    } 

    Boolean getRoomStatus(int roomNumber) 
    { 
     // Do real communication here (instea of just assigning true) 
     // It makes sense to move all communication to a separate class from here 
     Boolean newRoomStatus = true; 

     return newRoomStatus; 
    } 

    void updateRoomStatus(int roomNumber) 
    { 
     Boolean newRoomStatus = getRoomStatus(roomNumber); 
     broadcastRoomStatus(roomNumber, newRoomStatus); 
    } 

    void broadcastRoomStatus(int roomNumber, Boolean newRoomStatus) 
    { 
     Intent intent = new Intent(ROOM_STATUS_BROADCAST); 
     intent.putExtra(ROOM_STATUS_BROADCAST_EXTRA_ROOM_NUMBER, roomNumber); 
     intent.putExtra(ROOM_STATUS_BROADCAST_EXTRA_STATUS, newRoomStatus); 
     LocalBroadcastManager.getInstance(this).sendBroadcast(intent); 
    } 

} 

MyActivity.java

package com.example.servicesample; 

import android.os.Bundle; 
import android.app.Activity; 
import android.content.Intent; 
import android.support.v4.content.LocalBroadcastManager; 
import android.util.Log; 
import android.view.Menu; 
import com.example.servicesample.MyService; 
import android.content.BroadcastReceiver; 
import android.content.Context; 
import android.content.IntentFilter; 

public class MainActivity extends Activity { 

    private IntentFilter mIntentFilter = new IntentFilter(MyService.ROOM_STATUS_BROADCAST); 


    private BroadcastReceiver mReceiver = new BroadcastReceiver() { 

     @Override 
     public void onReceive(Context context, Intent intent) { 
      MainActivity.this.receivedBroadcast(intent);  
     } 
    }; 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_main); 

     startMyService(); 
    } 

    @Override 
    public boolean onCreateOptionsMenu(Menu menu) { 
     // Inflate the menu; this adds items to the action bar if it is present. 
     getMenuInflater().inflate(R.menu.activity_main, menu); 
     return true; 
    } 

    void startMyService() 
    { 
     // You can move this code to be executed on a button click or something else 
     // It will start a service 
     startService(new Intent(this, MyService.class)); 
    } 

    @Override 
    protected void onResume() 
    { 
     super.onResume(); 

     LocalBroadcastManager.getInstance(this).registerReceiver(mReceiver, mIntentFilter); 
    } 

    @Override 
    protected void onPause() 
    { 
     LocalBroadcastManager.getInstance(this).unregisterReceiver(mReceiver); 

     super.onPause(); 
    } 

    private void receivedBroadcast(Intent i) { 
     Integer roomNumber = i.getIntExtra(MyService.ROOM_STATUS_BROADCAST_EXTRA_ROOM_NUMBER, 0); 
     Boolean roomStatus = i.getBooleanExtra(MyService.ROOM_STATUS_BROADCAST_EXTRA_STATUS, false); 

     // Let's do here whatever we want with received status (as example, update UI) 
     Log.d("SomeTag", "Room number "+roomNumber.toString() + " got new status " + roomStatus.toString()); 
    } 

} 

AndroidManifest.xml中

<?xml version="1.0" encoding="utf-8"?> 
<manifest xmlns:android="http://schemas.android.com/apk/res/android" 
    package="com.example.servicesample" 
    android:versionCode="1" 
    android:versionName="1.0" > 

    <uses-sdk 
     android:minSdkVersion="8" 
     android:targetSdkVersion="16" /> 

    <application 
     android:allowBackup="true" 
     android:icon="@drawable/ic_launcher" 
     android:label="@string/app_name" 
     android:theme="@style/AppTheme" > 
     <activity 
      android:name="com.example.servicesample.MainActivity" 
      android:label="@string/app_name" > 
      <intent-filter> 
       <action android:name="android.intent.action.MAIN" /> 

       <category android:name="android.intent.category.LAUNCHER" /> 
      </intent-filter> 
     </activity> 

     <service android:name=".MyService"/> 

    </application> 

</manifest> 
+0

首先感謝您的回答,我現在的代碼會給我只有一個房間的狀態,我想要7這種房間,我想要連接使用不同的IP地址的所有房間的狀態。是的,我想不斷地做這個檢查。 – juned 2013-02-22 05:23:15

+0

@juned:然後在Service中使用一個線程(或多個線程)(Idea b)。 – 2013-02-22 15:12:38

+0

是的,但我認爲相同,但我如何使用多線程實現這一點,你能給我簡單的例子來讀取可用於任何活動的結果嗎? – juned 2013-02-23 06:49:42

0

如果您在每個房間一個Service之間詢問的性能,或一個Service所有房間 - 我會考慮7 servi ces非常過分。有一點你需要明白的是Service不是一個新的Thread。服務運行在與您的Activity相同的線程上。你想要做的是讓一個服務監聽多個套接字上的連接,然後爲每個建立的連接(空間)創建一個新線程。正如其他人所建議的那樣,AsyncTask是處理後臺進程的好方法,因爲它爲主線程提供了回調。但是它有一些限制,例如它可以處理的線程數。如果我們在每個房間談論一個線程 - 這應該不成問題。如果不是這種情況,請考慮爲每個房間連接使用一個阻塞線程。

相關問題