Android TCP套接字服务

5

根据我之前在这里提出的建议,我正在尝试将我编写的应用程序的套接字连接推入一个服务中。昨天我花了大部分时间研究服务并实际模拟了几个(一个远程,一个本地)。

我的问题分为两个部分:

1)在使用本地服务和远程服务后,我仍然不确定哪种服务最适合我的情况。这很大程度上是由于我猜我仍然不太明白在另一个“进程”中运行会给我带来什么优势。无论如何,我都会为套接字连接生成一个新线程,因此不会与UI发生任何线程争用。那么将服务放在另一个进程中能让我做什么呢?这样做我可能会看到更好的性能吗?我有一些不同的活动,但只有其中一个需要套接字连接,我将在每次打开该活动时重建它。所以对我来说使用本地服务是否是正确的选择?

2)我将在我的服务中将套接字“监听器”(DataInputStream().readLine() 在while循环内)用于从服务器传递下来的任何新数据。在昨天的实验中,我无法弄清楚如何将读取的数据实时传递给实际的“客户端”(通过远程服务绑定的客户端或本地客户端本身)。

非常感谢第一部分的建议,以及第二部分的帮助(代码示例?:))

TIA

编辑:添加了我的服务代码 - 使用本地服务

服务类:

   public class SocketService extends Service {

    Socket s;
    PrintStream os;

    @Override
    public IBinder onBind(Intent arg0) {
        // TODO Auto-generated method stub
        return myBinder;
    }

    private final IBinder myBinder = new LocalBinder();

    public class LocalBinder extends Binder {
        public SocketService getService() {
            return SocketService.this;
        }
    }


    @Override
    public void onCreate() {
        super.onCreate();
        s = new Socket();
    }

    public void IsBoundable(){
        Toast.makeText(this,"I bind like butter", Toast.LENGTH_LONG).show();
    }

    public void onStart(Intent intent, int startId){
        super.onStart(intent, startId);
        Toast.makeText(this,"Service created ...", Toast.LENGTH_LONG).show();
        Runnable connect = new connectSocket();
        new Thread(connect).start();
    }

    class connectSocket implements Runnable {

        @Override
        public void run() {
            SocketAddress socketAddress = new InetSocketAddress("192.168.1.104", 4505);
            try {               
                s.connect(socketAddress);
            } catch (IOException e) {
                e.printStackTrace();
            }

        }

    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        try {
            s.close();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        s = null;
    }
}

调用服务的活动:

public class SocketServiceController extends Activity {

        private SocketService mBoundService;
        private Boolean mIsBound;
        public SocketServiceController ssc;
       @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            ssc = this;
            setContentView(R.layout.main);

            Button start = (Button)findViewById(R.id.serviceButton);
            Button stop = (Button)findViewById(R.id.cancelButton);

            start.setOnClickListener(startListener);
            stop.setOnClickListener(stopListener);

       }

       private ServiceConnection mConnection = new ServiceConnection() {
            public void onServiceConnected(ComponentName className, IBinder service) {
                mBoundService = ((SocketService.LocalBinder)service).getService();

            }
            public void onServiceDisconnected(ComponentName className) {
                mBoundService = null;
            }
        };

        private void doBindService() {
            bindService(new Intent(SocketServiceController.this, SocketService.class), mConnection, Context.BIND_AUTO_CREATE);
            mIsBound = true;
            mBoundService.IsBoundable();
        }


        private void doUnbindService() {
            if (mIsBound) {
                // Detach our existing connection.
                unbindService(mConnection);
                mIsBound = false;
            }
        }

        @Override
        protected void onDestroy() {
            super.onDestroy();
            doUnbindService();
        }


       private OnClickListener startListener = new OnClickListener() {
        public void onClick(View v){
            startService(new Intent(SocketServiceController.this,SocketService.class));
            doBindService(); 

        }               
       };

       private OnClickListener stopListener = new OnClickListener() {
            public void onClick(View v){
                stopService(new Intent(SocketServiceController.this,SocketService.class));
            }               
          };
}

嗨……我正在尝试实现相同的服务绑定器概念,但是我在绑定服务时遇到了问题。即使我执行了你提到的上述代码,我仍然无法绑定到服务。你能告诉我出了什么问题吗? - Arun Abraham
嗨....我已解决我的问题...我必须使用getApplicationContext(),因为我是从选项卡活动中调用的...无论如何,我还有一个疑问...即使我正在做类似于你的事情...我们可以保持套接字打开并每次侦听消息吗?还是应该在每次接收或发送消息时关闭和重新打开...? - Arun Abraham
1个回答

8
这在很大程度上是因为我猜我仍然不太明白在另一个“进程”中运行会给我带来什么优势。 一般来说,没有。如果您希望其他应用程序与服务通信,则创建远程服务。如果仅由您自己的应用程序使用,请使用本地服务。 此外,远程服务与在应用程序内创建单独进程无关。 那样做会导致更差的性能,因为会消耗额外的内存。 服务的生命周期与活动无关,无论是本地还是远程。 听起来可能是本地服务。 使用本地绑定模式,并让活动调用服务上的API注册(和取消注册)事件侦听器。通过侦听器将数据传递给活动。

@Kyle:“监听器是要放在客户端还是服务本身内部”-- 客户端将创建监听器并将其传递给服务,使用一些常见的Java接口或其他东西。但是,这仅在您的客户端绑定到服务(例如,bindService()和onBind())时才有效,而这不是您的服务当前的结构方式。 - CommonsWare
@CommonsWare 再次感谢您的回复。昨天我玩弄了一下,以为已经解决了问题...但显然不是这样。我已经更新了我的OP,包括服务类中的代码以及调用服务的活动中的代码。我试图使用实例“mBoundService”调用服务上的方法“IsBoundable”,它应该只是向我发出一个toast。我想这是我需要将侦听器传递给服务的方式,但是当我调用该方法时,我会强制关闭。如果我不调用它,据我所知,它似乎正确地绑定了。有什么想法吗? - Kyle
我还是卡在这里。我阅读了您在此处的反馈:https://dev59.com/0kzSa4cB1Zd3GeqPno0p,针对类似问题,您说bindService()方法应该使用BIND_AUTO_CREATE标志启动我的服务。但它没有启动我的服务。我意识到这与我的原始问题有些脱节,但这让我想知道我的mBoundService是否真正被绑定。我知道服务没有启动,因为它没有连接到我的套接字服务器,而当我使用startservice()时,它会连接。 - Kyle
@Kyle:这是一个使用本地服务和本地绑定模式的项目示例:http://github.com/commonsguy/cw-android/tree/master/Service/WeatherPlus/ - CommonsWare
谢谢。我和他/她基本上做了同样的事情,但我的mBoundService没有工作。当我将bindService()方法调用设置到活动的onCreate()方法中时,它就解决了问题...为什么在按钮点击时不起作用呢?我现在会尝试处理监听器,并报告任何我遇到的问题。再次感谢。 - Kyle
显示剩余10条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接