在两个活动之间共享一项服务而不破坏它?

时间:2018-02-18 16:44:54

标签: java android android-activity android-service

我正在开发一个与树莓派进行通信的应用程序。应用程序通过套接字连接与服务器通信。

我目前能够建立通信并将其保存在服务中。但我的目标是从活动A改为活动B.问题是,我的应用程序在切换活动时会破坏服务。有办法避免这种情况吗?

活动A启动服务,当我启动活动B时,我将其绑定到活动以调用服务类中的方法。但它不是同一个实例。

我怎么能解决这个问题?

代码

ConnectActivity

package com.example.domen.twitchdronev3;

import android.content.Intent;
import android.os.Parcelable;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

public class ConnectActivity extends AppCompatActivity {

    private int port = 3000;
    private String ip = "localhost";
    private Intent serviceIntent, activityIntent;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_connect);

        Toast.makeText(getApplicationContext(), "Starte App...", Toast.LENGTH_LONG).show();

        activityIntent = new Intent(this, ControllActivity.class);
        serviceIntent = new Intent(this, ClientService.class);

        serviceIntent.putExtra("ip", ip);
        serviceIntent.putExtra("port", port);

        Button btnActivity = (Button) findViewById(R.id.changeActivity);
        btnActivity.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                startService(serviceIntent);
                activityIntent.putExtra("Intent", (Parcelable) serviceIntent);
                startActivity(activityIntent);
            }
        });
    }

    // destroys the Activity
    @Override
    public void onDestroy() {
        super.onDestroy();
        Toast.makeText(getApplicationContext(), "Destroy (ConnectActivity)", Toast.LENGTH_LONG).show();
    }

    // Activity stopping
    @Override
    protected void onStop() {
        super.onStop();
    }
}

ControllActivity

package com.example.domen.twitchdronev3;

import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

public class ControllActivity extends AppCompatActivity {

    public static final String TAG = "ControllActivity";

    private ClientService clientservice;
    private Intent serviceIntent;
    private boolean isBound;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_controll);

        Bundle extras = getIntent().getExtras();
        serviceIntent = extras.getParcelable("Intent");

        Button btnDisconnect = (Button) findViewById(R.id.btnDisconnect);
        btnDisconnect.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View view) {
                doBindToService();
            }
        });
    }

    // destroys the Activity
    @Override
    public void onDestroy(){
        super.onDestroy();
        Toast.makeText(getApplicationContext(), "Destroy (ControllActivity)", Toast.LENGTH_LONG).show();
        doUnbindToService();
        stopService(serviceIntent);
    }

    // Functions to BIND and UNBIND the SERVICE
    // bind to Service
    public void doBindToService(){
        if(!isBound) {
            Toast.makeText(this, "(doBindToService) Binding...", Toast.LENGTH_LONG).show();
            isBound = bindService(serviceIntent, myConnection, Context.BIND_AUTO_CREATE);
        }
    }

    // Unbind to Service
    public void doUnbindToService(){
        Toast.makeText(this, "(doUnbindToService) Unbinding...", Toast.LENGTH_LONG).show();
        unbindService(myConnection);
        isBound = false;
    }

    private ServiceConnection myConnection = new ServiceConnection(){
        public static final String TAG = "ConnectActivity";

        @Override
        public void onServiceConnected(ComponentName className, IBinder service){
            Log.i(TAG, "BOUND SERVICE CONNECTED");
            clientservice = ((ClientService.ClientBinder) service).getService();
            isBound = true;
        }

        @Override
        public void onServiceDisconnected(ComponentName name){
            Log.i(TAG, "BOUND SERVICE DISCONNECTED");
            clientservice = null;
            isBound = false;
        }
    };
}

ClientService

package com.example.domen.twitchdronev3;

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

import java.io.IOException;
import java.io.PrintWriter;
import java.net.Socket;

/**
 * Created by ViTrex on 12.02.2018.
 */

public class ClientService extends Service {

    private static final String TAG = "ClientService";
    private final IBinder mBinder = new ClientBinder();

    private PrintWriter out;
    private Socket socket;

    private String ip = "";
    private int port = 0;

    private Thread backgroundThread;

    // the class used for the client binder
    public class ClientBinder extends Binder {
        ClientService getService() {
            // returns the instance of ClientService
            // so the client can access the public methods
            return ClientService.this;
        }
    }

    //SETTER
    public void setIP(String ip) {
        this.ip = ip;
    }

    public void setPort(int port) {
        this.port = port;
    }

    //GETTER
    public String getIP() {
        return this.ip;
    }

    public int getPort() {
        return this.port;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Log.i(TAG, "onCreate...");
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Toast.makeText(this, "onStartCommand", Toast.LENGTH_LONG).show();

        if(intent != null){
            setIP(intent.getStringExtra("ip"));
            setPort(intent.getIntExtra("port", 3000));
        }

        return START_NOT_STICKY;
    }

    @Override
    public IBinder onBind(Intent intent) {
        Log.i(TAG, "onBind called...");
        Toast.makeText(this, getIP() + " " + getPort(), Toast.LENGTH_LONG).show();
        backgroundThread = new Thread(new Runnable() {
            @Override
            public void run() {
                buildConnection();
            }
        });
        backgroundThread.start();
        return mBinder;
    }

    private void buildConnection() {
        Log.i(TAG, "Try to build up a connection ...");
        synchronized (this) {
            try {
                this.socket = new Socket(getIP(), getPort());
                this.out = new PrintWriter(this.socket.getOutputStream(), true);
                Log.i(TAG, "Connected");
            } catch (IOException ioe) {
                Log.i(TAG, ioe.getMessage());
                this.socket = null;
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.i(TAG, "Close Service");
        Thread dummy = backgroundThread;
        backgroundThread = null;
        if (dummy != null)
            dummy.interrupt();

        if (this.socket != null) {
            try {
                this.out.close();
                this.socket.close();
                Log.i(TAG, "Close Socket");
            } catch (IOException ioe) {
                Log.i(TAG, "ERROR: Close Socket");
            }
        }
    }
}

1 个答案:

答案 0 :(得分:0)

你说:

  

活动A启动服务,当我启动活动B时,我绑定   它调用服务类中的方法的活动。但它   不是同一个例子。

  • 你怎么知道 同一个实例大概是你的意思 of < / em> service实例)?
  • 我认为你的代码是o.k.要在旧设备上运行(它在我的设备上运行pre-API26,我认为权限在此之后发生了变化,因此可能需要更多代码。请参阅注意在这个答案的最后)。
  • 你不想要START_STICKY吗?

我会将此代码(请Intent data设置的Activity A)添加到您的ClientService.java

@Override
public int onStartCommand(Intent intent, int flags, int startId) 
{

    String a_ip   = intent.getStringExtra("ip");
    int    a_port = intent.getIntExtra("port",-1);  
    Log.i(TAG, "onStartCommand called...with " + "ip:" + a_ip + "and port:"+ a_port);   
    setIP(a_ip);
    setPort(a_port);        

    return START_NOT_STICKY;//don't you want START_STICKY ?
    }
  

注意:如果您的应用针对API级别26或更高级别,系统会强制执行   除非应用程序限制使用或创建后台服务   本身就在前台。如果应用需要创建前景   服务,应用程序应调用StartForegroundService()。那种方法   创建后台服务,但该方法向系统发出信号   该服务将自己推向前台。一旦   服务已经创建,服务必须调用它的startForeground()   方法在五秒钟内。来自here