问题
a)从您的代码中,您的服务启动的内容并不明显。是启动一次还是多次。
根据当前的代码,看起来它会向 ip 发送一些东西,读取结果,发送一个广播,就是这样。
那么,问题是,您需要只更新一次灯光状态还是需要不断/定期更新它们?
想法
a) 在这种情况下,如果您只需要更新一次灯光状态并且它是从 UI 触发并更新 UI,那么使用专门为此设计的AsyncTask会更好。
由您决定是否要拥有 7 个并发 AsyncTask(如果您想并行更新灯光状态),或者您可以拥有一个 AsyncTask,它将连续更新灯光状态并在每个灯光更新后向 UI 线程报告。
b)在这种情况下,如果您需要持续跟踪灯的状态,那么您最好使用服务。但是,您需要在此服务中有一个长时间运行的线程。所以,你应该在 onStart 中启动一个线程。
通常,它应该(假设每 10 秒一次)调用一些会导致所有通信的方法等等。
在该方法中,您可以启动 X 个线程(每个房间一个),并在这些线程中执行所有操作(写入套接字、读取、解析等),或者您可以在第一个线程中执行所有这些操作。您在这里可以选择与 AsyncTask 相同的选择来并行或串行执行此操作。
c) 此外,当您需要更新灯光状态时,您可能希望保持所有套接字处于活动状态并重用它们以不每 5 秒重新连接一次。
普通的留言
a)您正在使用已弃用的 onStart() 。你应该使用 onStartCommand()
b)我知道它可能是一个原型,但是您展示的这段代码质量很低。如果你不清理它,你将来会有很多错误要追逐:
你有代码:
- 很多神奇的数字
- 命名错误的函数(例如 DisplayLoggingInfo,它不显示任何内容,而是读/写套接字,进行一些转换并发送广播)
- 长方法(DisplayLoggingInfo)
更新 1
这是适合您的示例应用程序。请注意,这是一个原型。您可能有兴趣添加更多检查,将其分离到更多类等等。
我的服务.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);
}
}
我的活动.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>