使用多个服务或在单个服务中执行所有操作哪个更好?
我正在开发一个基于套接字的应用程序,在这个应用程序中,我不断更新房间的状态,例如多少个灯开关。我有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的参考链接。
如何使用多线程实现此目的。我的最终目标是读取套接字并获得结果。
请指点我一个正确的方向。任何建议和想法将不胜感激。
感谢
问题
一)它不是从你的代码是什么开始你的服务明显。它启动一次还是多次?
根据目前的代码,它看起来会发送一些东西到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>
如果您在每个房间一个Service
之间询问的性能,或一个Service
所有房间 - 我会考虑7 servi ces非常过分。有一点你需要明白的是Service
不是一个新的Thread
。服务运行在与您的Activity
相同的线程上。你想要做的是让一个服务监听多个套接字上的连接,然后为每个建立的连接(空间)创建一个新线程。正如其他人所建议的那样,AsyncTask
是处理后台进程的好方法,因为它为主线程提供了回调。但是它有一些限制,例如它可以处理的线程数。如果我们在每个房间谈论一个线程 - 这应该不成问题。如果不是这种情况,请考虑为每个房间连接使用一个阻塞线程。
你在问什么?如何更改服务以连接到不同的远程地址? – Jin35 2013-02-21 12:44:38
@ Jin35我有不同的房间,每个房间都使用不同的IP连接,所以我想知道不同房间的状态,以上实施仅适用于单间。如果我更改IP,它会给我其他房间的状态。 – juned 2013-02-21 13:19:47