【问题标题】:Sharing one service between two activities without destroying it?在两个活动之间共享一项服务而不破坏它?
【发布时间】:2018-02-18 16:44:53
【问题描述】:

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

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

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

我该如何解决这个问题?

代码

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

客户服务

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

【问题讨论】:

  • 可以分享一下相关代码吗?
  • 好的,我编辑了代码

标签: java android android-activity android-service


【解决方案1】:

你说:

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

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

我会将此代码(阅读由Activity A 设置的Intent data)添加到您的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

【讨论】:

  • 活动 A 创建了一个实例,在活动 B 中我创建了另一个实例。谢谢:)你的回答帮助了我。我仔细阅读了指南。我没有使用 startForeground() 方法。目前,我正在活动 A 中使用 startService(intent) 启动服务,并与活动 B 共享意图。当活动 B 启动时,我正在调用 bindService(intent) 方法并创建一个 toast。它向我展示了我在调用 startService(intent) 时共享的相同值。但我会尝试使用 startForeground() 方法。
  • 您上面的评论令人困惑,"It showed me the same values that i have shared"。在您给我们的代码中,不存在这样的 Toast,如果没有我给您的代码,它就无法工作,因为您没有在您的服务中读取意图值并“将它们保存在变量中”代码。
  • 对不起,我忘了编辑帖子,没有很好地表达自己。我编辑了我的帖子。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多