我努力使自己的MusicPlayer为Android。 当我来到一个问题是运行在后台一些事情。 主要业务管理GUI和到现在为止所有的歌曲播放。 我想图形用户界面和音乐播放类分开。 我希望把音乐管理部分服务,留下其他的东西,因为他们现在的样子。
我的问题是,我不能活动和服务之间的通信组织作为大量的沟通是他们之间发生的事情,包括在两个方向上移动的物体。 我想,我搜索在这里堆栈溢出但每次我有问题时的许多技术。 我需要的服务能够将对象发送到活动,反之亦然。 当我添加小工具我也希望它能够与服务进行通信。
任何提示赞赏,如果你需要的源代码的地方在下面评论,但是现在在这个过渡成为混乱。
是否有任何这更高级教程不是调用,从服务返回的随机数的一种方法? :P
编辑:可能的解决方案是使用RoboGuice库,并与注射移动对象
Answer 1:
我已经实现使用绑定和回调接口活动和服务之间的通信。
用于将数据发送到I使用的粘合剂的服务,这retruns服务instace到活动,然后将活动可以访问在服务的公共方法。
从服务将数据发送回的活动,我用回调接口就像你正在使用,当你想片段和活动之间进行通信。
下面是每个一些代码样品:下面的示例示出了活动和服务双向关系:活动有2个按钮:第一个按钮将启动和停止该服务。 第二个按钮将启动运行在该服务的计时器。
该服务将通过与计时器回调进度更新活动。
我的活动:
//Activity implements the Callbacks interface which defined in the Service
public class MainActivity extends ActionBarActivity implements MyService.Callbacks{
ToggleButton toggleButton;
ToggleButton tbStartTask;
TextView tvServiceState;
TextView tvServiceOutput;
Intent serviceIntent;
MyService myService;
int seconds;
int minutes;
int hours;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
serviceIntent = new Intent(MainActivity.this, MyService.class);
setViewsWidgets();
}
private void setViewsWidgets() {
toggleButton = (ToggleButton)findViewById(R.id.toggleButton);
toggleButton.setOnClickListener(btListener);
tbStartTask = (ToggleButton)findViewById(R.id.tbStartServiceTask);
tbStartTask.setOnClickListener(btListener);
tvServiceState = (TextView)findViewById(R.id.tvServiceState);
tvServiceOutput = (TextView)findViewById(R.id.tvServiceOutput);
}
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName className,
IBinder service) {
Toast.makeText(MainActivity.this, "onServiceConnected called", Toast.LENGTH_SHORT).show();
// We've binded to LocalService, cast the IBinder and get LocalService instance
MyService.LocalBinder binder = (MyService.LocalBinder) service;
myService = binder.getServiceInstance(); //Get instance of your service!
myService.registerClient(MainActivity.this); //Activity register in the service as client for callabcks!
tvServiceState.setText("Connected to service...");
tbStartTask.setEnabled(true);
}
@Override
public void onServiceDisconnected(ComponentName arg0) {
Toast.makeText(MainActivity.this, "onServiceDisconnected called", Toast.LENGTH_SHORT).show();
tvServiceState.setText("Service disconnected");
tbStartTask.setEnabled(false);
}
};
View.OnClickListener btListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
if(v == toggleButton){
if(toggleButton.isChecked()){
startService(serviceIntent); //Starting the service
bindService(serviceIntent, mConnection, Context.BIND_AUTO_CREATE); //Binding to the service!
Toast.makeText(MainActivity.this, "Button checked", Toast.LENGTH_SHORT).show();
}else{
unbindService(mConnection);
stopService(serviceIntent);
Toast.makeText(MainActivity.this, "Button unchecked", Toast.LENGTH_SHORT).show();
tvServiceState.setText("Service disconnected");
tbStartTask.setEnabled(false);
}
}
if(v == tbStartTask){
if(tbStartTask.isChecked()){
myService.startCounter();
}else{
myService.stopCounter();
}
}
}
};
@Override
public void updateClient(long millis) {
seconds = (int) (millis / 1000) % 60 ;
minutes = (int) ((millis / (1000*60)) % 60);
hours = (int) ((millis / (1000*60*60)) % 24);
tvServiceOutput.setText((hours>0 ? String.format("%d:", hours) : "") + ((this.minutes<10 && this.hours > 0)? "0" + String.format("%d:", minutes) : String.format("%d:", minutes)) + (this.seconds<10 ? "0" + this.seconds: this.seconds));
}
}
这里是服务:
public class MyService extends Service {
NotificationManager notificationManager;
NotificationCompat.Builder mBuilder;
Callbacks activity;
private long startTime = 0;
private long millis = 0;
private final IBinder mBinder = new LocalBinder();
Handler handler = new Handler();
Runnable serviceRunnable = new Runnable() {
@Override
public void run() {
millis = System.currentTimeMillis() - startTime;
activity.updateClient(millis); //Update Activity (client) by the implementd callback
handler.postDelayed(this, 1000);
}
};
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
//Do what you need in onStartCommand when service has been started
return START_NOT_STICKY;
}
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
//returns the instance of the service
public class LocalBinder extends Binder{
public MyService getServiceInstance(){
return MyService.this;
}
}
//Here Activity register to the service as Callbacks client
public void registerClient(Activity activity){
this.activity = (Callbacks)activity;
}
public void startCounter(){
startTime = System.currentTimeMillis();
handler.postDelayed(serviceRunnable, 0);
Toast.makeText(getApplicationContext(), "Counter started", Toast.LENGTH_SHORT).show();
}
public void stopCounter(){
handler.removeCallbacks(serviceRunnable);
}
//callbacks interface for communication with service clients!
public interface Callbacks{
public void updateClient(long data);
}
}
Answer 2:
更新日期:2016年7月10日
IMO我认为使用广播接收器自定义事件是提到不处理的设备旋转活动娱乐以及可能的内存泄漏的使者更好的办法。
您可以在活动中创建自定义广播接收器的事件,那么你也可以使用信使。
在您的Activity
创建的MessageHandler类作为
public static class MessageHandler extends Handler { @Override public void handleMessage(Message message) { int state = message.arg1; switch (state) { case HIDE: progressBar.setVisibility(View.GONE); break; case SHOW: progressBar.setVisibility(View.VISIBLE); break; } } }
现在你可以拥有它的实例作为
public static Handler messageHandler = new MessageHandler();
启动您的Service
与该Handler对象作为一个额外的数据,
Intent startService = new Intent(context, SERVICE.class) startService.putExtra("MESSENGER", new Messenger(messageHandler)); context.startService(startService);
在您Service
您的意图接收该对象并初始化Messenger
在服务变量
private Messenger messageHandler; Bundle extras = intent.getExtras(); messageHandler = (Messenger) extras.get("MESSENGER"); sendMessage(ProgressBarState.SHOW);
然后写一个方法sendMessage
将消息发送到活动。
public void sendMessage(ProgressBarState state) { Message message = Message.obtain(); switch (state) { case SHOW : message.arg1 = Home.SHOW; break; case HIDE : message.arg1 = Home.HIDE; break; } try { messageHandler.send(message); } catch (RemoteException e) { e.printStackTrace(); } }
作为消息从服务接收到上面的示例代码显示和隐藏一个进度条中的活动。
Answer 3:
意图是Activitiy和服务之间的沟通很好的解决方案。
在您的服务获得意图的快速解决方案继承IntentService类。 它处理表示为使用队列和工作线程意图异步请求。
从服务到活动通信您可以播放意图,但不是从环境中使用正常sendBroadcast(),一个比较有效的方法是使用LocalBroadcastManager从支持库。
例如服务。
public class MyIntentService extends IntentService {
private static final String ACTION_FOO = "com.myapp.action.FOO";
private static final String EXTRA_PARAM_A = "com.myapp.extra.PARAM_A";
public static final String BROADCAST_ACTION_BAZ = "com.myapp.broadcast_action.FOO";
public static final String EXTRA_PARAM_B = "com.myapp.extra.PARAM_B";
// called by activity to communicate to service
public static void startActionFoo(Context context, String param1) {
Intent intent = new Intent(context, MyIntentService.class);
intent.setAction(ACTION_FOO);
intent.putExtra(EXTRA_PARAM1, param1);
context.startService(intent);
}
public MyIntentService() {
super("MyIntentService");
}
@Override
protected void onHandleIntent(Intent intent) {
if (intent != null) {
final String action = intent.getAction();
if (ACTION_FOO.equals(action)) {
final String param1 = intent.getStringExtra(EXTRA_PARAM_A);
// do something
}
}
}
// called to send data to Activity
public static void broadcastActionBaz(String param) {
Intent intent = new Intent(BROADCAST_ACTION_BAZ);
intent.putExtra(EXTRA_PARAM_B, param);
LocalBroadcastManager bm = LocalBroadcastManager.getInstance(this);
bm.sendBroadcast(intent);
}
}
例如活动
public class MainActivity extends ActionBarActivity {
// handler for received data from service
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(MyIntentService.BROADCAST_ACTION_BAZ)) {
final String param = intent.getStringExtra(EXTRA_PARAM_B);
// do something
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
IntentFilter filter = new IntentFilter();
filter.addAction(MyIntentService.BROADCAST_ACTION_BAZ);
LocalBroadcastManager bm = LocalBroadcastManager.getInstance(this);
bm.registerReceiver(mBroadcastReceiver, filter);
}
@Override
protected void onDestroy() {
LocalBroadcastManager bm = LocalBroadcastManager.getInstance(this);
bm.unregisterReceiver(mBroadcastReceiver);
super.onDestroy();
}
// send data to MyService
protected void communicateToService(String parameter) {
MyIntentService.startActionFoo(this, parameter);
}
}
Answer 4:
我认为这是正确答案的一个问题。 我没有足够的声誉对此发表评论。
就在答案:活动调用bindService()来获取指向服务就可以了。 由于保持连接时,服务内容被保存。
错误的答案:服务指针到活动类回调是不错的方法。 活动实例活动方面时也许不是NULL被释放=>例外这里。
对于错误的答案的解决方案:服务发送意图活动。 和活动接收器经由广播接收器的意图。
注:在同一进程中这种情况下,服务和活动,你应该使用LocalBroadcastManager发送意图。 它使性能和安全性更好
Answer 5:
在这种情况下,最好的办法是从你的不同的动作做服务广播和您的活动接受它交流。 您可以创建自定义播放和发送定义完全一样,变化的特定事件的一些代码,准备等..
Answer 6:
这是活性和服务之间的通信的简单例子
活动
MyReceiver myReceiver; //my global var receiver
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.layourAwesomexD);
registerReceiver();
}
//When the activity resume, the receiver is going to register...
@Override
protected void onResume() {
super.onResume();
checkStatusService(); // verficarStatusServicio(); <- name change
registerReceiver();
}
//when the activity stop, the receiver is going to unregister...
@Override
protected void onStop() {
unregisterReceiver(myReceiver); //unregister my receiver...
super.onStop();
}
//function to register receiver :3
private void registerReceiver(){
//Register BroadcastReceiver
//to receive event from our service
myReceiver = new MyReceiver();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(MyService.SENDMESAGGE);
registerReceiver(myReceiver, intentFilter);
}
// class of receiver, the magic is here...
private class MyReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context arg0, Intent arg1) {
//verify if the extra var exist
System.out.println(arg1.hasExtra("message")); // true or false
//another example...
System.out.println(arg1.getExtras().containsKey("message")); // true or false
//if var exist only print or do some stuff
if (arg1.hasExtra("message")) {
//do what you want to
System.out.println(arg1.getStringExtra("message"));
}
}
}
public void checkStatusService(){
if(MyService.serviceStatus!=null){
if(MyService.serviceStatus == true){
//do something
//textview.text("Service is running");
}else{
//do something
//textview.text("Service is not running");
}
}
}
服务
public class MyService extends Service {
final static String SENDMESAGGE = "passMessage";
public static Boolean serviceStatus = false;
@Override
public void onCreate() {
super.onCreate();
serviceStatus=true;
}
@Nullable
@Override
public IBinder onBind(Intent intent) {return null;}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
//you service etc...
passMessageToActivity("hello my friend this an example of send a string...");
return START_STICKY;
}
@Override
public void onDestroy() {
super.onDestroy();
passMessageToActivity("The service is finished, This is going to be more cooler than the heart of your ex...");
System.out.println("onDestroy");
serviceStatus=false;
}
private void passMessageToActivity(String message){
Intent intent = new Intent();
intent.setAction(SENDMESAGGE);
intent.putExtra("message",message);
sendBroadcast(intent);
}
}
- 如果我们不注销广播接收器,我们将有一个错误,你需要注销活动时去的onPause,的onStop,...的onDestroy
- 如果您没有注册广播接收器,当你回的活动,也不会听从服务什么...该服务将信息发送到广播接收器,而是因为它没有注册也不会得到任何东西。
- 当你创建一个以上的服务,以下服务会在开始
onStartCommand
。 - 你可以传递信息意图的服务与您在得到它
onStartCommand
- 差异有关
return
在onStartCommand
: START_STICKY和START_REDELIVER_INTENT之间的区别? 检查谷歌的官方网站: 服务
Answer 7:
看看Android文档
http://developer.android.com/guide/components/bound-services.html#Binder
Answer 8:
非常简单但功能强大的方法是使用EventBus你可以把它添加到您的gradle这个构建和享受轻松发布/订阅模式。
Answer 9:
最简单而有效的方式将使用EventBus从GreenRobot。
使用简单的3个步骤:
1定义事件
public static class MessageEvent { /* Additional fields if needed */ }
2准备的用户:声明和标注你的订阅方法,选择指定线程模式:
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(MessageEvent event) {/* Do something */};
注册和注销你的用户。 例如在Android,活动和片段通常应该寄存器根据它们的生命周期:
@Override
public void onStart() {
super.onStart();
EventBus.getDefault().register(this);
}
@Override
public void onStop() {
super.onStop();
EventBus.getDefault().unregister(this);
}
3岗位事件:
EventBus.getDefault().post(new MessageEvent());
文章来源: Communication between Activity and Service