修订2:如何从一个后台服务/线程的数据传递到比创建的后台服务MainActivity其他活动后台、线程、数据、MainActivity

2023-09-12 09:40:35 作者:去尼玛的天荒地老

我已经为测试如何使用一个处理器或处理器从后台服务/线程的数据传递到的其他活动的以外的其他创建的后台服务MainActivity一个简单的Andr​​oid应用程序。我已经得到了服务,螺纹,并在MainActivity的处理工作。最后一步是获得一个处理程序,以将数据传递到的一些其它活性的其它比MainActivity。我可以得到服务将消息传递给了MainActivity的处理程序,但我不知道如何得到它的数据传递到的其他活动的。

为什么会有人要做到这一点?我想这比简单的MP3播放器,但它实际上比作是一个很好的FM收音机。该MainActivity使用一个后台服务,可以让我选择一个FM电台。当我启动游戏活动应当绑定到同一个后台服务这样我就可以继续聆听,而它(从善意的角度)显示图形均衡器的音频或动画。基本上,我不知道如何绑定到从多个活动的后台服务。

我的code最初是基于服务示例页304上临Android的2 ,并帮助极大地由 CommonsWare示例应用程序。

请看看我现在的code。它包括描述什么,我试图做的,我有将数据传递到三个仔细评价文件的困难的其他活动的除了MainActivity:

/**************************************************************************************************  *文件:MainActivity.java  *应用:BackgroundService  *说明:此文件包含运行BackgroundService时的主要活动  *应用程序启动。  ************************************************** ************ / 包com.marie.mainactivity; 进口com.marie.mainactivity.BackgroundService; 进口android.app.Activity; 进口android.content.Intent; 进口android.os.Bundle; 进口android.os.Handler; 进口android.os.Message; 进口android.os.Messenger; 进口android.util.Log; 进口android.view.View; 进口android.view.View.OnClickListener; 进口android.widget.Button; / *  *类别:MainActivity  *用途:使用一个按钮,MainActivity类开始backgroundService和  *在RcvMessages活动。使用另一个按钮MainActivity停止backgroundService。  *注:RcvMessages只是一个存根,什么也不做,但显示一个简单的信息。  *处理器:MainActivity定义,并提供了一​​个参考,以处理为backgroundService。  * / 公共类MainActivity延伸活动{     私有静态最后字符串变量=MainActivity;     @覆盖     公共无效的onCreate(包savedInstanceState)     {         super.onCreate(savedInstanceState);         的setContentView(R.layout.main);         Log.d(TAG,启动服务);         / *          *绑定按钮:bindBtn          *单击此按钮启动后台服务,并将启动          * RcvMessages活动。注:RcvMessages只是一个存根至今。          * /         按钮bindBtn =(按钮)findViewById(R.id.bindBtn);         bindBtn.setOnClickListener(新OnClickListener(){             @覆盖             公共无效的onClick(查看为arg0){                 //启动后台服务发送罐头消息处理程序进行测试。                 意图backgroundService =新的意图(MainActivity.this,com.marie.mainactivity.BackgroundService.class);                 backgroundService.putExtra(BackgroundService.EXTRA_MESSENGER,新的信使(处理));                 startService(backgroundService);                 //开始从处理器接收消息的RcvMessages活动。但如何???                 意向留言=新的意图(MainActivity.this,com.marie.mainactivity.RcvMessages.class);                 startActivity(消息);             }         });         / *          *将解除绑定按钮:unbindBtn          *单击此按钮停止后台服务。          * /         按钮unbindBtn =(按钮)findViewById(R.id.unbindBtn);         unbindBtn.setOnClickListener(新OnClickListener(){             @覆盖             公共无效的onClick(查看为arg0){                 //停止后台服务                 意图backgroundService =新的意图(MainActivity.this,BackgroundService.class);                 stopService(backgroundService);             }         });     }     / *      *这是要传递到通过信使背景服务的处理程序。      *注:我想它来发送邮件到我的RcvMessages活动。      * /     私人处理程序处理程序=新的处理程序(){         @覆盖         公共无效的handleMessage(信息MSG){             //简单的处理器测试(不将消息发送到RcvMessages活动             字符串的obj =(字符串)msg.obj;             Log.i(handleMessge,物镜:+物镜);         }     }; } / ******************* *************************************************  *文件:BackgroundService.java  *应用:BackgroundService  *说明:此文件包含由MainActivity的启动后台服务  *绑定按钮。  ************************************************** ************ / 包com.marie.mainactivity; 进口android.app.Notification; 进口android.app.NotificationManager; 进口android.app.PendingIntent; 进口android.app.Service; 进口android.content.Intent; 进口android.os.Bundle; 进口android.os.IBinder; 进口android.os.Message; 进口android.os.Messenger; 进口android.os.RemoteException; / *  *类别:BackgroundService  *目的:使用ONSTART()方法BackgroundService获取参考  *传递给BackgroundService的使者实例。使者随后  *使用的ServiceWorker()线程将消息发送到已定义的处理程序  *在MainActivity类。  * / 公共类BackgroundService延伸服务{     私人NotificationManager notificationMgr;     公共静态最后弦乐EXTRA_MESSENGER =com.marie.mainactivity.EXTRA_MESSENGER;     私人信使信使;     @覆盖     公共无效的onCreate(){         super.onCreate();         notificationMgr =(NotificationManager)getSystemService(NOTIFICATION_SERVICE);         displayNotificationMessage(启动后台服务);         螺纹THR =新主题(NULL,新ServiceWorker(),BackgroundService);         thr.start();     }     / *      *这是ServiceWorker线程传递消息中定义的处理程序      *在MainActivity类。      *注意:不要在MainActivity传递消息到一个处理的,我想      *这将消息传递给在RcvMessages活动定义的处理程序。      * /     类ServiceWorker实现Runnable     {         公共无效的run(){             //后台处理在这里...简单的东西             //发送消息到在MainActivity类中定义的处理程序             尝试 {                 消息MSG1 = Message.obtain();                 msg1.obj =你好1;                 messenger.send(MSG1);             }赶上(RemoteException的E){                 e.printStackTrace();             }             //完成时停止服务...             // BackgroundService.this.stopSelf();             //或者使用unbindBtn在MainActivity类。         }     }     @覆盖     公共无效的onDestroy()     {         displayNotificationMessage(停止后台服务);         super.onDestroy();     }     / *      * ONSTART是我们得到我们参考的使者,使      *我们将消息发送到在MainActivity类中定义的处理程序。      * /     @覆盖     公共无效ONSTART(意向意图,诠释startId){         super.onStart(意向,startId);         捆绑额外= intent.getExtras();         信使=(信使)extras.get(EXTRA_MESSENGER);     }     @覆盖     公众的IBinder onBind(意向意图){         返回null;     }     私人无效displayNotificationMessage(字符串消息)     {         通知通知=新的通知(R.drawable.note,消息,System.currentTimeMillis的());         PendingIntent contentIntent = PendingIntent.getActivity(此,0,新意图(本,MainActivity.class),0);         notification.setLatestEventInfo(这一点,后台服务,邮件,contentIntent);         notificationMgr.notify(R.id.app_notification_id,通知);     } } / ******************* *************************************************  *文件:RcvMessages.java  *应用:BackgroundService  *说明:此文件包含存根code,显示在一个EditText测试消息。  ************************************************** ************ / 包com.marie.mainactivity; 进口android.app.Activity; 进口android.os.Bundle; 进口android.text.InputType; 进口android.widget.EditText; / *  *类别:RcvMessages  *用途:RcvMessages是,我想以某种方式从接收邮件扩展存根code  *后台服务。  *注:我不知道是谁做的这一点。  * / 公共类RcvMessages延伸活动{     会将myText的EditText;     / **第一次创建活动时调用。 * /     @覆盖     公共无效的onCreate(包savedInstanceState){         super.onCreate(savedInstanceState);         的setContentView(R.layout.messages);         =会将myText(的EditText)findViewById(R.id.my_text);         myText.setSingleLine();         myText.setInputType(InputType.TYPE_NULL);         //显示,现在一个简单的测试消息。         myText.setText(RcvMessages这里);     } }

使用后台服务,线程和处理器(S)将数据传递给任何帮助的除了创建该backgraound服务将大大AP preciated的MainActivity一些其他活动的。

解决方案

处理程序与特定线程关联,所以只要你在UI线程创建的所有你需要做的是共享的处理程序。我会把你的处理器在我的应用程序类。你可以把整个使者在那里,如果你想要的。然后,你可以通过((MyApplication的)getApplication())。getHandler访问处理程序的任何活动()。当活动开始或暂停,您可以将其注册为一个回调。

因此​​,像这样

 公共类MyApplication的扩展应用{
   处理程序H =新的处理程序(){
      公共无效的handleMessage(消息M){
        如果(realCallback!= NULL){
           realCallback.handleMessage(米);
        }
      }
   };
   Handler.Callback realCallback = NULL;
   ......
   公共处理器getHandler(){
      返回H;
   }

   公共无效setCallback(Handler.Callback C){
      realCallback = C;
   }
}
 
银行业 数据中台 的再思考

在任何需要做的接收通过使者请求活性

 公共类MyActivity扩展活动实现Handler.Callback

......

公共无效的OnStart(){
   ((所有MyApplication)getApplication())setCallback(本)。
}

公共无效的onPause(){
   ((所有MyApplication)getApplication())setCallback(空)。
}

公共无效的handleMessage(信息MSG){
  // ....做的东西....
}
 

}

这只是一个想法。您可能需要将其调整到您的需要。

不要忘了设置在AndroidManifest.xml中所有MyApplication 名称

I've created a simple Android application for testing how to use a handler or handlers to pass data from a background Service/thread to some other activity other than the MainActivity that created the background service. I've got the Service, thread, and a handler working in the MainActivity. The last step is to get a handler to pass data to some other activity other than the MainActivity. I can get the Service to pass messages to the MainActivity's handler, but I don't know how to get it to pass data to some other activity.

Why would anyone want to do this? I thought this compared to a simple MP3 player, but what it actually compares to is a nice FM radio. The MainActivity uses a background Service that allows me to select an FM station. When I launch the Play activity it should bind to the same background Service so I can continue to listen while it (the nice part) displays a graphic equalizer or animation of the the audio. Basically, I don't know how to bind to the background Service from more than one activity.

My code was originally based on a Service example page 304 in Pro Android 2 and was helped tremendously by a CommonsWare Sample Application.

Please have a look at my current code. It consists of three carefully commented files that describe what I am trying to do and the difficulties I am having passing data to some other activity in addition to the MainActivity:

/**************************************************************************************************
 * 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);

        Log.d(TAG, "starting service");

        /*
         * 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.
                Intent backgroundService = new Intent(MainActivity.this, com.marie.mainactivity.BackgroundService.class);
                backgroundService.putExtra(BackgroundService.EXTRA_MESSENGER, new Messenger(handler));
                startService(backgroundService);

                // Start the RcvMessages activity to receive messages from the handler. But how???
                Intent messages = new Intent(MainActivity.this, com.marie.mainactivity.RcvMessages.class);
                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 handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            // simple handler test (does not send messages to RcvMessages activity
            String obj = (String) msg.obj;
            Log.i("handleMessge", "obj: " + obj);  
        }
    };
}

/**************************************************************************************************
 * 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;

/*
 * 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 = "com.marie.mainactivity.EXTRA_MESSENGER";
    private Messenger messenger;

    @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 class
            try {
                Message msg1 = Message.obtain();
                msg1.obj = "Hello 1";
                messenger.send(msg1);
            } catch (RemoteException e) {
                e.printStackTrace();
            }

            // 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();
    }

    /*
     * onStart is where we get our reference the Messenger that allows
     * us to send messages to the handler defined in the MainActivity class.
     */
    @Override
    public void onStart(Intent intent, int startId) {
        super.onStart(intent, startId);

        Bundle extras = intent.getExtras();
        messenger = (Messenger)extras.get(EXTRA_MESSENGER);
    }

    @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.os.Bundle;
import android.text.InputType;
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 {

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

Any help using a background Service, thread, and handler(s) to pass data to some other activity in addition to the MainActivity that created the backgraound Service would be greatly appreciated.

解决方案

The Handler is associated with specific thread, so for as long as you create it in UI thread all you need to do is to share the handler. I would put your handler in my Application class. And you can put the whole Messenger there, if you want. Then you can access handler in any activity via ((MyApplication)getApplication()).getHandler(). When activity starts or pauses, you can register it as a callback.

So something like this

public class MyApplication extends Application {
   Handler h = new Handler() {
      public void handleMessage(Message m) {
        if (realCallback!=null) {
           realCallback.handleMessage(m);
        }
      }
   };
   Handler.Callback realCallback=null;
   ......
   public Handler getHandler() {
      return h;
   }

   public void setCallback(Handler.Callback c) {
      realCallback = c;
   }
}

In any activity that needs to do receive requests via messenger

public class MyActivity extends Activity implements Handler.Callback

......

public void onStart() {
   ((MyApplication)getApplication()).setCallback(this);
}

public void onPause() {
   ((MyApplication)getApplication()).setCallback(null);
}

public void handleMessage(Message msg) {
  //.... Do stuff ....
}

}

This is just an idea. You may need to tune it to your needs.

And don't forget to set MyApplication name in AndroidManifest.xml