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);
    } 
}

我正在启动此服务并在我想显示此值的活动中获得广播意图。这是从后台服务更新 UI的参考链接。

我如何使用多线程来实现这一点。我的最终目标是读取套接字并获得状态结果就是这样。

请指出正确的方向。任何建议和想法将不胜感激。

谢谢

4

2 回答 2

1

问题

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>
于 2013-02-21T23:52:47.747 回答
0

如果您询问Service每个房间配备一个或Service所有房间配备一个之间的性能 - 我会认为 7 项服务非常过分。您需要了解的一件事是 aService不是新的Thread. 服务与您的Activity. 您要做的是让一个服务侦听多个套接字上的连接,然后为每个已建立的连接(房间)创建一个新线程。正如其他人所建议的那样, anAsyncTask是处理后台进程的好方法,因为它提供了对主线程的回调。但是,它确实有限制——例如它可以处理的线程数。如果我们在每个房间谈论一个线程 - 这应该不是问题。如果不是这种情况,请考虑为每个房间连接使用阻塞线程。

于 2013-02-27T21:24:25.970 回答