如何将一个Activity绑定到一个Service并从Activity中控制和管理Service

4
我试图将一个Activity绑定到一个LocalService以与之交互。但在我的Activity中,我只能调用在我的LocalBinder中定义的方法而不能调用LocalService中的方法。我做错了什么吗?
并非从头开始,我阅读了另一个问题,并且我已经稍微了解了如何编写一些示例代码,我的代码类似于该示例代码。此外,我已经阅读了一些服务文档,为方便起见,这里是该部分文档的一个小引用:
当应用程序组件通过调用bindService()绑定到服务时,该服务被“绑定”。一个绑定的服务提供了一个客户端-服务器接口,允许组件与服务交互,发送请求,获取结果,甚至可以通过进程间通信(IPC)在进程之间进行交互。只有当另一个应用程序组件绑定到它时,绑定的服务才会运行。多个组件可以同时绑定到服务,但当它们全部解除绑定时,服务将被销毁。
但我无法做到这一点。如上所述,我最好能够使我的Activity调用在LocalBinder中定义的方法。我没有像上面黑色部分那样做任何事情。
如果有帮助的话,这里是代码的相关部分。
要绑定的LocalService:
/**************************************************************************************************
 * Filename: LocalService.java
 * Project name: Local Service Sample
 * Application name: Local Service
 * Description: This file contains the LocalService (extends Service) for our Local Service app
 **************************************************************************************************/

package com.marie.localservicesample;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.UUID;

import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.Intent;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.util.Log;
import android.widget.Toast;

public class LocalService extends Service {
    private NotificationManager mNM;

    // Unique Identification Number for the Notification.
    // We use it on Notification start, and to cancel it.
    private int NOTIFICATION = R.string.local_service_started;

    // just some arbitrary numbers for test purposes
    public static int statusCode = 99;
    public static  int emptyMsg = 549;

    // I get my Extras from onStartCommand and use in ServiceWorker() thread
    public static final String EXTRA_MAC = "com.marie.localservicesample.EXTRA_MAC";
    private String macString;

    public static final String EXTRA_MESSENGER = "com.marie.localservicesample.EXTRA_MESSENGER";
    private Messenger messenger;

    private static final UUID MY_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
    //private static final String macString = "00:06:66:02:D0:EC";

    Boolean stop_receive_data = false;

    // This is the object that receives interactions from clients.  See
    // RemoteService for a more complete example - or not because
    // this is a local service
    private final IBinder mBinder =  new LocalBinder();

    @Override
    public IBinder onBind(Intent intent) {
        Log.i("onBind", "called in LocalService" );
        Log.i("onBind", "intent: " + intent.toString());
        Log.i("onBind", "mBinder: " + mBinder);
        return mBinder;
    }

    @Override
    public void onCreate() {
        mNM = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);

        // Display a notification about us starting.  We put an icon in the status bar.
        showNotification();
    }

    // Call this at the end of onStartCommand() after we got the Extras
    public void afterStartCommand() {
        Thread thr = new Thread(null, new ServiceWorker(), "LocalService");
        thr.start();  
    }

    /*
     * This is the ServiceWorker thread that passes messages to the handler defined in
     * the Controller activity.
     */
    class ServiceWorker implements Runnable
    {
        public void run() {
            // do background processing here... something simple
            Looper.prepare();

            BluetoothAdapter btAdapter = BluetoothAdapter.getDefaultAdapter();
            BluetoothDevice btDevice = btAdapter.getRemoteDevice(macString);
            BluetoothSocket btSocket = null;
            InputStream btIstream = null;
            OutputStream btOstream = null;
            try {
                btSocket = btDevice.createRfcommSocketToServiceRecord(MY_UUID);
            } catch (IOException e1) {
                e1.printStackTrace();
            }
            try {
                btSocket.connect();
            } catch (IOException e1) {
                e1.printStackTrace();
            }
            try {
                btIstream = btSocket.getInputStream();
                btOstream = btSocket.getOutputStream();
            } catch (IOException e1) {
                e1.printStackTrace();
            }
            try {
                int data = btIstream.read();

                // reset the bluetooth device
                while (data != 63) {
                    Log.d("LocalService", "resetting bluetooth device");
                    btOstream.write('r');
                    data = btIstream.read();
                }

                StringBuffer strBuffer = new StringBuffer("");
                Boolean dataBegin = false;

                int ndxPlus = 0;

                while (data != -1) {
                    char printableB = (char) data;
                    if (data < 32 || data > 126) {
                        //printableB = ' ';
                    }               
                    //Log.d("LocalService", Character.toString(printableB) + "(" + data + ")");

                    if (data == 63) {
                        btOstream.write('$');
                        btOstream.write(',');
                    }
                    if (data == 45) {
                        btOstream.write('1');
                        btOstream.write(',');
                        dataBegin = true;
                    }
                    if (dataBegin == true) {
                        strBuffer = strBuffer.append(Character.toString(printableB));
                    }
                    if (data == 13) {
                        dataBegin = false;
                        //Log.d("LocalServiceDataString", strBuffer.toString());

                        // send data to the handler to plot the data
                        Message msg = Message.obtain();
                        msg.what = Controller.MESSAGE_MAC;
                        msg.obj = strBuffer;
                        try {
                            messenger.send(msg);
                        } catch (RemoteException e) {
                            e.printStackTrace();
                        }

                        strBuffer = new StringBuffer("");
                        if (ndxPlus < 0) {
                            btOstream.write('+');
                            ndxPlus++;
                        }
                    }

                    data = btIstream.read();
                    if (stop_receive_data) data = -1;

                }

            } catch (IOException e1) {
                e1.printStackTrace();
            }
            try {
                btSocket.close();
            } catch (IOException e1) {
                e1.printStackTrace();
            }

            LocalService.this.stopSelf();
            Looper.loop();
            // stop the service when done...
            // Or use the unbindBtn in the MainActivity class?
        }
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.i("LocalService", "Received start id " + startId + ": " + intent);

        Bundle extras = intent.getExtras();

        messenger = (Messenger)extras.get(EXTRA_MESSENGER);
        macString = extras.getString(EXTRA_MAC);

        afterStartCommand();

        // We want this service to continue running until it is explicitly
        // stopped, so return sticky.
        return START_STICKY;
    }

    @Override
    public void onDestroy() {
        // Cancel the persistent notification.
        mNM.cancel(NOTIFICATION);
        stop_receive_data = true;
        // Tell the user we stopped.
        Toast.makeText(this, R.string.local_service_stopped, Toast.LENGTH_SHORT).show();
    }

    /**
     * Show a notification while this service is running.
     */
    private void showNotification() {
        // In this sample, we'll use the same text for the ticker and the expanded notification
        CharSequence text = getText(R.string.local_service_started);

        // Set the icon, scrolling text and timestamp
        Notification notification = new Notification(R.drawable.stat_sample, text, System.currentTimeMillis());

        // The PendingIntent to launch our activity if the user selects this notification
        PendingIntent contentIntent = PendingIntent.getActivity(this, 0, new Intent(this, Controller.class), 0);

        // Set the info for the views that show in the notification panel.
        notification.setLatestEventInfo(this, getText(R.string.local_service_label), text, contentIntent);

        // Send the notification.
        mNM.notify(NOTIFICATION, notification);
    }
}

绑定到本地服务的活动:

/**************************************************************************************************
 * Filename: Binding.java
 * Project name: Local Service Sample
 * Application name: Local Service
 * Description: This file contains the Binding class for our Local Service application
 **************************************************************************************************/
package com.marie.localservicesample;

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

/*
 * Example of binding and unbinding to the local service.
 * This demonstrates the implementation of a service which the client will
 * bind to, receiving an object through which it can communicate with the service.
 */

public class Binding extends Activity {
    private ILocalBinder mBoundService;
    private boolean mIsBound;

    private ServiceConnection mConnection = new ServiceConnection() {
        public void onServiceConnected(ComponentName className, IBinder service) {
            // This is called when the connection with the service has been
            // established, giving us the service object we can use to
            // interact with the service.  Because we have bound to a explicit
            // service that we know is running in our own process, we can
            // cast its IBinder to a concrete class and directly access it.
            mBoundService = (ILocalBinder)service;

            int statusCode = mBoundService.getStatusCode();

            Log.d("Binding.java","called onServiceConnected. statusCode: " + statusCode);

            Toast.makeText(Binding.this, R.string.local_service_connected,
                    Toast.LENGTH_SHORT).show();
        }

        public void onServiceDisconnected(ComponentName className) {
            // This is called when the connection with the service has been
            // unexpectedly disconnected -- that is, its process crashed.
            // Because it is running in our same process, we should never
            // see this happen.
            mBoundService = null;

            Log.d("Binding", "called onServiceDisconnected");

            Toast.makeText(Binding.this, R.string.local_service_disconnected,
                    Toast.LENGTH_SHORT).show();
        }
    };

    void doBindService() {
        // Establish a connection with the service.  We use an explicit
        // class name because we want a specific service implementation that
        // we know will be running in our own process (and thus won't be
        // supporting component replacement by other applications).
        bindService(new Intent(Binding.this, LocalService.class), mConnection, Context.BIND_AUTO_CREATE);
        mIsBound = true;
    }

    void doUnbindService() {
        if (mIsBound) {
            int statusCode = mBoundService.getStatusCode();
            if (statusCode != 0) Log.d("doUnbindService", "Binding.java statusCode: " + statusCode);

            // Tell the user we did an unbind
            Toast.makeText(this, R.string.local_service_unbound, Toast.LENGTH_SHORT).show();

            // Detach our existing connection.
            unbindService(mConnection);
            mIsBound = false;
        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.local_service_binding);

        // Watch for button clicks.
        Button button = (Button)findViewById(R.id.bind);
        button.setOnClickListener(mBindListener);
        button = (Button)findViewById(R.id.unbind);
        button.setOnClickListener(mUnbindListener);
    }

    private OnClickListener mBindListener = new OnClickListener() {
        public void onClick(View v) {
            doBindService();
        }
    };

    private OnClickListener mUnbindListener = new OnClickListener() {
        public void onClick(View v) {
            doUnbindService();
        }
    };

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

我的 ILocalBinder 和 LocalBinder:

/**************************************************************************************************
 * Filename: ILocalBinder.java
 * Project name: Local Service Sample
 * Application name: Local Service
 * Description: This file contains an example interface for my LocalBinder
 **************************************************************************************************/

package com.marie.localservicesample;

public interface ILocalBinder {

    public int getStatusCode();
}

/**************************************************************************************************
 * Filename: LocalBinder.java
 * Project name: Local Service Sample
 * Application name: Local Service
 * Description: This file contains the LocalBinder class for our Local Service application
 **************************************************************************************************/

package com.marie.localservicesample;

import android.os.Binder;

import com.marie.localservicesample.LocalService;

/**
 * Class for clients to access.  Because we know this service always
 * runs in the same process as its clients, we don't need to deal with
 * IPC.
 */
public class LocalBinder extends Binder implements ILocalBinder {
    @Override
    public int getStatusCode() {
        return LocalService.statusCode;
    }

}

谢谢!

1个回答

7

请查看本地服务示例

只需将其绑定类代码复制到您的服务中,而不是为其创建单独的文件:(在LocalService类声明内部)

public class LocalService {
    // This is the object that receives interactions from clients.  See
    // RemoteService for a more complete example.
    private final IBinder mBinder = new LocalBinder();

    /**
     * Class for clients to access.  Because we know this service always
     * runs in the same process as its clients, we don't need to deal with
     * IPC.
     */
    public class LocalBinder extends Binder {
        LocalService getService() {
            return LocalService.this;
        }
    }

    ...
}

然后:

public void onServiceConnected(ComponentName className, IBinder service) {
    // This is called when the connection with the service has been
    // established, giving us the service object we can use to
    // interact with the service.  Because we have bound to a explicit
    // service that we know is running in our own process, we can
    // cast its IBinder to a concrete class and directly access it.
    mBoundService = ((LocalService.LocalBinder)service).getService();

现在,您可以直接使用mBoundService访问您的服务。

你能帮我解决这个问题吗?https://stackoverflow.com/questions/51508046/binding-a-jobintentservice-to-a-activity - Rajesh K

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