使用多个服务或在单个服务中执行所有操作哪个更好?

问题描述:

我正在开发一个基于套接字的应用程序,在这个应用程序中,我不断更新房间的状态,例如多少个灯开关。我有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

问题

一)它不是从你的代码是什么开始你的服务明显。它启动一次还是多次?

根据目前的代码,它看起来会发送一些东西到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

如果您在每个房间一个Service之间询问的性能,或一个Service所有房间 - 我会考虑7 servi ces非常过分。有一点你需要明白的是Service不是一个新的Thread。服务运行在与您的Activity相同的线程上。你想要做的是让一个服务监听多个套接字上的连接,然后为每个建立的连接(空间)创建一个新线程。正如其他人所建议的那样,AsyncTask是处理后台进程的好方法,因为它为主线程提供了回调。但是它有一些限制,例如它可以处理的线程数。如果我们在每个房间谈论一个线程 - 这应该不成问题。如果不是这种情况,请考虑为每个房间连接使用一个阻塞线程。