如何将活动绑定到服务并从活动中控制和管理服务

时间:2011-07-17 09:43:03

标签: android multithreading service interface local

我正在尝试将Activity绑定到LocalService以与其进行交互。但在我的Activity中,我只能调用我的LocalBinder中定义的方法而不是我的LocalService。我做错了什么?

没有开始划痕我读了另一个question,我已经读了一些code some sample code,我的代码类似于示例代码。此外,为了方便起见,我一直在阅读一些Service Documentation,这是文档该部分的一个小引用:

“当应用程序组件通过调用bindService()绑定它时,服务被”绑定“。 绑定服务提供了一个客户端 - 服务器接口,允许组件与服务交互,发送请求,获取结果, ,甚至跨进程间通信(IPC)进行处理。绑定服务只在另一个应用程序组件绑定到它时运行。多个组件可以立即绑定到服务,但当他们所有人都解开时,服务就会被破坏。“

但我做不到。如上所述,我能做的最好的事情就是在我的LocalBinder中定义我的Activity调用方法。我没有像上面用黑色突出显示的那部分一样。

如果它有帮助,我的代码的相关部分。

要绑定的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);
    }
}

绑定到LocalService的活动:

/**************************************************************************************************
 * 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 个答案:

答案 0 :(得分:6)

请参阅local service example

只需将他们拥有的活页夹类代码复制到您的服务中,而不是为其创建单独的文件:(在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直接访问您的服务。