如何在Android应用程序中处理活动变化并保持客户端与服务器的连接,并将数据发送到服务器?

22

我最初在我的活动中实现了一个异步任务,用于向服务器发送数据。但当我切换活动时,连接就会丢失。为了解决这个问题,我的方法是实现一个服务来集中处理网络操作并将数据发送到服务器,下面是该服务的代码:

import java.io.BufferedWriter;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.Socket;

import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.util.Log;
import android.widget.Toast;

public class SocketService extends Service {
  public static final String SERVERIP = ""; //your computer IP address should be written here
  public static final int SERVERPORT = 5000;
  PrintWriter out;
  Socket socket;
  InetAddress serverAddr;

@Override
public IBinder onBind(Intent intent) {
    // TODO Auto-generated method stub
    System.out.println("I am in Ibinder onBind method");
      return myBinder;
}

  private final IBinder myBinder = new LocalBinder();
  TCPClient mTcpClient = new TCPClient();

  public class LocalBinder extends Binder {
        public SocketService getService() {
            System.out.println("I am in Localbinder ");
            return SocketService.this;

        }
    }

  @Override
    public void onCreate() {
        super.onCreate();
        System.out.println("I am in on create");     
    }

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

  public void sendMessage(String message){
        if (out != null && !out.checkError()) {
            System.out.println("in sendMessage"+message);
            out.println(message);
            out.flush();
        }
    }

    @Override
    public int onStartCommand(Intent intent,int flags, int startId){
        super.onStartCommand(intent, flags, startId);
        System.out.println("I am in on start");
      //  Toast.makeText(this,"Service created ...", Toast.LENGTH_LONG).show();
        Runnable connect = new connectSocket();
        new Thread(connect).start();
        return START_STICKY;
    }


    class connectSocket implements Runnable {

        @Override
        public void run() {


            try { 
                 //here you must put your computer's IP address.
                serverAddr = InetAddress.getByName(SERVERIP);
                Log.e("TCP Client", "C: Connecting...");
                //create a socket to make the connection with the server

                socket = new Socket(serverAddr, SERVERPORT);

                 try {


                     //send the message to the server
                     out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())), true);


                     Log.e("TCP Client", "C: Sent.");

                     Log.e("TCP Client", "C: Done.");


                    } 
                 catch (Exception e) {

                     Log.e("TCP", "S: Error", e);

                 }
            } catch (Exception e) {

                Log.e("TCP", "C: Error", e);

            }

        }

    }


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


    }

Rotator.java是我绑定到此服务的活动。以下是我活动中的几个代码片段。

private ServiceConnection mConnection = new ServiceConnection() {
            //EDITED PART
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        // TODO Auto-generated method stub
         mBoundService = ((SocketService.LocalBinder)service).getService();

    }

    @Override
    public void onServiceDisconnected(ComponentName name) {
        // TODO Auto-generated method stub
         mBoundService = null;
    }

  };


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


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

@Override
public void onCreate(Bundle savedInstanceState)
{
      super.onCreate(savedInstanceState);
      gestureDetector = new GestureDetector(this, new GestureListener());
      setContentView(R.layout.activity_rotator);


      //Binding the activity to the service to perform client-server operations
      //start service on create
        startService(new Intent(Rotator.this,SocketService.class));
        doBindService();
                  ...........
                  ...........
}   


@Override
protected void onDestroy() {
    super.onDestroy();
    doUnbindService();
}
现在,由于此服务在后台运行,如果我想将一些数据发送到服务器,则使用以下内容。
 if(mBoundService!=null)
{
    mBoundService.sendMessage("right");
}
2个回答

8

代码是正确的。唯一的错误是我在onServiceConnected()方法和onCreate()方法中尝试启动服务两次。

我将我的代码更改为仅在启动器活动的onCreate()方法中启动服务。其余的活动通过使用doBindService()方法直接绑定到服务。


你刚刚节省了我的时间。 - BSKANIA
你的上面的代码很完美,或者说你在上面的代码中启动了两次服务?你改变了上面的代码吗?我看到你使用startservice方法和doBindservice方法分别启动了一次。请修正一下。我读完后有些困惑。 - sam_k
@sam_k 我只在MainActivity中使用了startService方法来启动服务。其余的活动只是在onCreate中使用doBindService()方法。上面的代码已经编辑为正确的代码。我不明白你的困惑。 - gfernandes
即使过了这么多年,你的代码仍然拯救了我。就我个人而言,从技术上讲,在 onServiceConnected 被调用之前,该服务并没有绑定,这就是为什么我不会在此之前将 mIsBound = true。除此之外,它完美地运行。 - nulldroid

2
当服务绑定到Activity上时,当Activity停止时,服务也会被杀死,就像一个仅为Activity提供后台支持的服务。因此,要使其保持运行,请在您的Service类中实现onStartCommand()方法并返回this.START_STICKY。并在该方法中管理您的服务。

我已经在我的服务代码中完成了这个。但是我不知道如何将数据发送到异步任务以将其发送到服务器。 - gfernandes
在该活动中,mTcpClient始终为空。 - gfernandes
不,查看一下Service的安卓文档,如果你正在使用Binder将其绑定到Activity,那么它会自动关闭。尝试从Binder中移除它,而是在onStartCommand()中尝试一下。这就是我告诉你的。 - AbdulHannan
@AbdulHannan,您可以绑定并启动服务,这样当活动更改时,服务就不会被杀死。 - Piotr

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