【问题标题】:More than one activity starting/binding to a Service多个活动启动/绑定到服务
【发布时间】:2011-06-18 00:23:15
【问题描述】:

根据我所读到的关于Services 的内容,我应该能够将多个活动绑定到同一个服务,但它不起作用。值得我的 BackgroundService 扩展服务。

从我的 MainActivity 我按如下方式启动服务:

Intent backgroundService = new Intent(MainActivity.this, BackgroundService.class);
backgroundService.putExtra(BackgroundService.EXTRA_MESSENGER_MAINACTIVITY, new Messenger(mainHandler));
startService(backgroundService);

然后从另一个活动中,我尝试绑定这个相同的服务,如下所示:

Intent backgroundService = new Intent(RcvMessages.this, BackgroundService.class);
backgroundService.putExtra(BackgroundService.EXTRA_MESSENGER_RCVMESSAGES, new Messenger(rcvHandler));
startService(backgroundService);

我的理解是,每个与服务的绑定都会有它自己的处理程序,如上所示。但它不起作用。只有第一个处理程序有效。我做错了什么?

@Femi 说“您正在将 Messenger 作为 Intent 额外传递给 BackgroundService 类,但没有内置的 Android 代码可以理解如何处理该 Messenger:必须由 BackgroundService 实现提供。 BackgroundService 的代码是什么,它对传递的 Messenger 实例有什么作用?” @Femi 看看我的 BackgroundServe,尤其是 onStartCommand():

/**************************************************************************************************
 * File: BackgroundService.java
 * Application: BackgroundService
 * Description: This file contains the background Service that is launched by the MainActivity's
 *     bind button.
 **************************************************************************************************/

package com.marie.mainactivity;

import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.util.Log;

/*
 * Class: BackgroundService
 * Purpose: Using the onStart() method the BackgroundService gets the reference to the
 *     Messenger instance that was passed to BackgroundService. The messenger is then
 *     used by the ServiceWorker() thread to send messages to the handler that is defined
 *     in the MainActivity class.
 */
public class BackgroundService extends Service {
    private NotificationManager notificationMgr;

    public static final String EXTRA_MESSENGER_MAINACTIVITY = "com.marie.mainactivity.EXTRA_MESSENGER_MAINACTIVITY";
    private Messenger messenger_mainactivity;

    public static final String EXTRA_MESSENGER_RCVMESSAGES = "com.marie.mainactivity.EXTRA_MESSENGER_RCVMESSAGES";
    private Messenger messenger_rcvmessages;

    public static final String EXTRA_SONG = "com.marie.mainactivity.EXTRA_SONG";
    int song = 0;

    @Override
    public void onCreate() {
        super.onCreate();

        notificationMgr = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);

        displayNotificationMessage("starting Background Service");

        Thread thr = new Thread(null, new ServiceWorker(), "BackgroundService");
        thr.start();
    }   

    /*
     * This is the ServiceWorker thread that passes messages to the handler defined in
     * the MainActivity class.
     * NOTE: Instead of passing messages to a handler in MainActivity I would like
     * it to pass messages to a handler defined in the RcvMessages activity.
     */
    class ServiceWorker implements Runnable
    {
        public void run() {
            // do background processing here... something simple

            // send a message to the handler defined in the MainActivity activity
            if (messenger_mainactivity != null)
            {
                try {
                    Message msg1 = Message.obtain();
                    msg1.obj = "SongData";
                    msg1.arg1 = 1000;
                    messenger_mainactivity.send(msg1);
                } catch (RemoteException e) {
                    e.printStackTrace();
                } catch (NullPointerException e) {
                    e.printStackTrace();
                }
            } else {
                Log.e("messenger_mainactivity", "null");
            }

            // send a message to the handler defined in the RcvMessages activity
            if (messenger_rcvmessages != null)
            {
                try {
                    Message msg1 = Message.obtain();
                    msg1.obj = "Song";
                    msg1.arg1 = song;
                    messenger_rcvmessages.send(msg1);
                } catch (RemoteException e) {
                    e.printStackTrace();
                } catch (NullPointerException e) {
                    e.printStackTrace();
                }
            } else {
                Log.e("messenger_rcvmessages", "null");
            }

            // stop the service when done...
            // BackgroundService.this.stopSelf();
            // Or use the unbindBtn in the MainActivity class.
        }
    }

    @Override
    public void onDestroy()
    {
        displayNotificationMessage("stopping Background Service");
        super.onDestroy();
    }

    /*
    @Override
    public void onStart(Intent intent, int startId) {
        super.onStart(intent, startId);
    }
    */

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

        Bundle extras = intent.getExtras();
        Messenger messenger;

        messenger = (Messenger)extras.get(EXTRA_MESSENGER_MAINACTIVITY);
        if (messenger != null) {
            messenger_mainactivity = messenger;
        }

        messenger = (Messenger)extras.get(EXTRA_MESSENGER_RCVMESSAGES);
        if (messenger != null) {
            messenger_rcvmessages = messenger;
            song = extras.getInt(EXTRA_SONG);
        }

        return START_NOT_STICKY;
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    private void displayNotificationMessage(String message)
    {
        Notification notification = new Notification(R.drawable.note, message, System.currentTimeMillis());

        PendingIntent contentIntent = PendingIntent.getActivity(this, 0, new Intent(this, MainActivity.class), 0);

        notification.setLatestEventInfo(this, "Background Service", message, contentIntent);

        notificationMgr.notify(R.id.app_notification_id, notification);
    }
}

这是整个代码:

/**************************************************************************************************
 * File: MainActivity.java
 * Application: BackgroundService
 * Description: This file contains the main activity that is run when the BackgroundService
 *     application is launched.
 **************************************************************************************************/

package com.marie.mainactivity;

import com.marie.mainactivity.BackgroundService;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.Messenger;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

/*
 * Class: MainActivity
 * Purpose: Using a button, the MainActivity class starts the backgroundService and
 *     the RcvMessages activity. Using another button MainActivity stops the backgroundService.
 *     NOTE: RcvMessages is only a stub that does nothing but display a simple message.
 * Handler: MainActivity defines and provides a reference to "handler" for the backgroundService.
 */
public class MainActivity extends Activity {
    private static final String TAG = "MainActivity";

    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        /*
         * The bind button: bindBtn
         * Clicking this button starts the background Service and launches the
         * RcvMessages activity. NOTE: RcvMessages is only a stub so far.
         */
        Button bindBtn = (Button)findViewById(R.id.bindBtn);
        bindBtn.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View arg0) {
                // Start the background Service for sending canned messages to the handler as a test.
                Log.d(TAG, "starting service");
                Intent backgroundService = new Intent(MainActivity.this, BackgroundService.class);
                backgroundService.putExtra(BackgroundService.EXTRA_MESSENGER_MAINACTIVITY, new Messenger(mainHandler));
                startService(backgroundService);

                // Start the RcvMessages activity to receive messages from the handler. But how???
                Intent messages = new Intent(MainActivity.this, RcvMessages.class);
                messages.putExtra(RcvMessages.EXTRA_SONG, 10);
                startActivity(messages);
            }
        });

        /*
         * The unbind button: unbindBtn
         * Clicking this button stops the background Service.
         */
        Button unbindBtn = (Button)findViewById(R.id.unbindBtn);
        unbindBtn.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View arg0) {

                // Stop the background Service
                Intent backgroundService = new Intent(MainActivity.this, BackgroundService.class);
                stopService(backgroundService);
            }
        });
    }

    /*
     * This is the handler to be passed to the background Service via a Messenger.
     * NOTE: I want it to send messages to my RcvMessages activity.
     */
    private Handler mainHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            // simple handler test (does not send messages to RcvMessages activity
            String obj = (String) msg.obj;
            int arg1 = msg.arg1;
            Log.i("handleMessge_mainactivity", "obj: " + obj + " " + "arg1: " + arg1);  
        }
    };
}


/**************************************************************************************************
 * File: BackgroundService.java
 * Application: BackgroundService
 * Description: This file contains the background Service that is launched by the MainActivity's
 *     bind button.
 **************************************************************************************************/

package com.marie.mainactivity;

import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.util.Log;

/*
 * Class: BackgroundService
 * Purpose: Using the onStart() method the BackgroundService gets the reference to the
 *     Messenger instance that was passed to BackgroundService. The messenger is then
 *     used by the ServiceWorker() thread to send messages to the handler that is defined
 *     in the MainActivity class.
 */
public class BackgroundService extends Service {
    private NotificationManager notificationMgr;

    public static final String EXTRA_MESSENGER_MAINACTIVITY = "com.marie.mainactivity.EXTRA_MESSENGER_MAINACTIVITY";
    private Messenger messenger_mainactivity;

    public static final String EXTRA_MESSENGER_RCVMESSAGES = "com.marie.mainactivity.EXTRA_MESSENGER_RCVMESSAGES";
    private Messenger messenger_rcvmessages;

    public static final String EXTRA_SONG = "com.marie.mainactivity.EXTRA_SONG";
    int song = 0;

    @Override
    public void onCreate() {
        super.onCreate();

        notificationMgr = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);

        displayNotificationMessage("starting Background Service");

        Thread thr = new Thread(null, new ServiceWorker(), "BackgroundService");
        thr.start();
    }   

    /*
     * This is the ServiceWorker thread that passes messages to the handler defined in
     * the MainActivity class.
     * NOTE: Instead of passing messages to a handler in MainActivity I would like
     * it to pass messages to a handler defined in the RcvMessages activity.
     */
    class ServiceWorker implements Runnable
    {
        public void run() {
            // do background processing here... something simple

            // send a message to the handler defined in the MainActivity activity
            if (messenger_mainactivity != null)
            {
                try {
                    Message msg1 = Message.obtain();
                    msg1.obj = "SongData";
                    msg1.arg1 = 1000;
                    messenger_mainactivity.send(msg1);
                } catch (RemoteException e) {
                    e.printStackTrace();
                } catch (NullPointerException e) {
                    e.printStackTrace();
                }
            } else {
                Log.e("messenger_mainactivity", "null");
            }

            // send a message to the handler defined in the RcvMessages activity
            if (messenger_rcvmessages != null)
            {
                try {
                    Message msg1 = Message.obtain();
                    msg1.obj = "Song";
                    msg1.arg1 = song;
                    messenger_rcvmessages.send(msg1);
                } catch (RemoteException e) {
                    e.printStackTrace();
                } catch (NullPointerException e) {
                    e.printStackTrace();
                }
            } else {
                Log.e("messenger_rcvmessages", "null");
            }

            // stop the service when done...
            // BackgroundService.this.stopSelf();
            // Or use the unbindBtn in the MainActivity class.
        }
    }

    @Override
    public void onDestroy()
    {
        displayNotificationMessage("stopping Background Service");
        super.onDestroy();
    }

    /*
    @Override
    public void onStart(Intent intent, int startId) {
        super.onStart(intent, startId);
    }
    */

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

        Bundle extras = intent.getExtras();
        Messenger messenger;

        messenger = (Messenger)extras.get(EXTRA_MESSENGER_MAINACTIVITY);
        if (messenger != null) {
            messenger_mainactivity = messenger;
        }

        messenger = (Messenger)extras.get(EXTRA_MESSENGER_RCVMESSAGES);
        if (messenger != null) {
            messenger_rcvmessages = messenger;
            song = extras.getInt(EXTRA_SONG);
        }

        return START_NOT_STICKY;
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    private void displayNotificationMessage(String message)
    {
        Notification notification = new Notification(R.drawable.note, message, System.currentTimeMillis());

        PendingIntent contentIntent = PendingIntent.getActivity(this, 0, new Intent(this, MainActivity.class), 0);

        notification.setLatestEventInfo(this, "Background Service", message, contentIntent);

        notificationMgr.notify(R.id.app_notification_id, notification);
    }
}


/**************************************************************************************************
 * File: RcvMessages.java
 * Application: BackgroundService
 * Description: This file contains stub code that displays a test message in an EditText.
 **************************************************************************************************/

package com.marie.mainactivity;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.Messenger;
import android.text.InputType;
import android.util.Log;
import android.widget.EditText;

/*
 * Class: RcvMessages
 * Purpose: RcvMessages is stub code that I want to extend in some way to receive messages from
 *     the background Service.
 *     NOTE: I don't know who to do this.
 */
public class RcvMessages extends Activity {

    public static final String EXTRA_SONG = "com.marie.mainactivity.EXTRA_SONG";
    EditText myText;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.messages);

        myText = (EditText)findViewById(R.id.my_text);

        myText.setSingleLine();
        myText.setInputType(InputType.TYPE_NULL);

        // Display a simple test message for now.
        // myText.setText("RcvMessages here");
    }

    @Override
    public void onStart(){
        super.onStart();
        Bundle extras = getIntent().getExtras();
        int song = (Integer) extras.get(EXTRA_SONG);
        //myText.setText("song " + song);

        // Start the background Service for sending canned messages to the handler as a test.
        Intent backgroundService = new Intent(RcvMessages.this, BackgroundService.class);
        backgroundService.putExtra(BackgroundService.EXTRA_MESSENGER_RCVMESSAGES, new Messenger(rcvHandler));
        backgroundService.putExtra(BackgroundService.EXTRA_SONG, song);
        bindService(backgroundService);
    }

    private void bindService(Intent backgroundService) {
        // TODO Auto-generated method stub

    }

    @Override
    public void onStop() {
        super.onStop();
        myText.setText("");
    }

    /*
     * This is the handler to be passed to the background Service via a Messenger.
     * NOTE: I want it to send messages to my RcvMessages activity.
     */
    private Handler rcvHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            // simple handler test
            String song = (String) msg.obj;
            int songNum = msg.arg1;
            Log.i("handleMessage_rcvmessages", "songNum: " + songNum);  

            myText.setText(song + " " + songNum);
        }
    };

}

【问题讨论】:

  • 当你这样做时会发生什么?
  • @James 只有一个处理程序有效。

标签: android multithreading service background handler


【解决方案1】:

您没有绑定到正在尝试启动服务的服务(使用bindService 完成)。如果您想绑定,您应该使用 bindService 并从 javadoc 和您指定的链接中阅读该行为。

就独立的Handlers 不工作而言:这取决于BackgroundService 的实现。

【讨论】:

  • @Femi 你能否提供一些细节。 “这取决于 BackgroundService 的实现”是什么意思?
  • 您正在将 Messenger 作为 Intent 额外传递给 BackgroundService 类,但没有内置的 Android 代码可以理解如何处理该 Messenger:这必须由 BackgroundService 实现提供。 BackgroundService 的代码是什么,它对传递的 Messenger 实例有什么作用?
  • @Femi 我会相应地修改我的问题。
  • 添加BackgroundService的来源。
  • @Femi 所有 3 个文件都在那里:MainActivity.java 然后是 BackgroundService.java 然后是 RcvMessages.java。
【解决方案2】:

我可以像这样成功地将活动绑定到我的服务:

bindService(new Intent(Binding.this, LocalService.class), mConnection, Context.BIND_AUTO_CREATE);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-27
    • 1970-01-01
    相关资源
    最近更新 更多