如何从活动中调用服务的方法?

Posted

技术标签:

【中文标题】如何从活动中调用服务的方法?【英文标题】:How to call methods of a Service from activity? 【发布时间】:2011-06-18 05:05:51 【问题描述】:

我只是想从我的活动中调用本地服务的方法。我该怎么做?

【问题讨论】:

【参考方案1】:

这是一个可能有帮助的示例Server.java:

package com.example.bindservice.binder;

import java.text.SimpleDateFormat;
import java.util.Date;

import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;

public class Server extends Service 

    IBinder mBinder = new LocalBinder();

    @Override
    public IBinder onBind(Intent intent) 
        return mBinder;
    

    public class LocalBinder extends Binder 
        public Server getServerInstance() 
            return Server.this;
        
    

    public String getTime() 
        SimpleDateFormat mDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        return mDateFormat.format(new Date());
    

Client.java

package com.example.bindservice.binder;

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

import com.example.bindservice.binder.Server.LocalBinder;

public class Client extends Activity 

    boolean mBounded;
    Server mServer;
    TextView text;
    Button button;

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

        text = (TextView)findViewById(R.id.text);
        button = (Button) findViewById(R.id.button);
        button.setOnClickListener(new OnClickListener() 
            public void onClick(View v) 
                text.setText(mServer.getTime());
            
        );
    

    @Override
    protected void onStart() 
        super.onStart();

        Intent mIntent = new Intent(this, Server.class);
        bindService(mIntent, mConnection, BIND_AUTO_CREATE);
    ;

    ServiceConnection mConnection = new ServiceConnection() 
        @Override
        public void onServiceDisconnected(ComponentName name) 
            Toast.makeText(Client.this, "Service is disconnected", 1000).show();
            mBounded = false;
            mServer = null;
        

        @Override
        public void onServiceConnected(ComponentName name, IBinder service) 
            Toast.makeText(Client.this, "Service is connected", 1000).show();
            mBounded = true;
            LocalBinder mLocalBinder = (LocalBinder)service;
            mServer = mLocalBinder.getServerInstance();
        
    ;

    @Override
    protected void onStop() 
        super.onStop();
        if(mBounded) 
            unbindService(mConnection);
            mBounded = false;
        
    ;

【讨论】:

如果服务被强制停止,我会接到 onServiceDisconnected 的电话吗? 为什么调用一个简单的函数这么难 @Mr.Z 也许你没有将服务绑定到Android中的活动***.com/questions/1916253/… 这应该是正确的答案。谢谢。你节省了我的时间。【参考方案2】:

在“本地服务示例”下的服务文档中有此权限的示例代码:

http://developer.android.com/reference/android/app/Service.html#LocalServiceSample

同样对于那些建议使用aidl 的人——如果您的服务和客户端都是您自己的.apk 的一部分并且在同一个进程中运行(默认行为),则不需要aidl;它只是额外的复杂性,并没有给你任何东西。

【讨论】:

【参考方案3】:

如何调用普通的 Java 方法?

A obj = new A();
obj.method();

Service 是一个 Java 类。那么如何调用服务方法呢?

serviceObj.method();

现在真正的问题是如何创建服务对象?

Service serviceObj = new Service();

绝对不是。

在 Android 中,Service 是由 Android 操作系统创建、销毁和管理的系统组件。 要创建服务对象,您需要 IBinder

这是您从IBinder 获取服务对象的方法。

一旦你拥有了 serviceObject.它将像任何普通的 Java 对象一样工作。 上面图中解释的东西叫做Binding a Service

绑定使得从 Activity 观察后台服务成为可能。通过绑定,我们可以通过两种方式进行通信,即ActivityService。 Prateek Yadav 已经提供了出色的代码 sn-p。你可以使用它。

注意事项

永远不要忘记取消绑定服务,否则会导致 ResourceLeak。 您可以按任意顺序拨打startService(intent)bindService(mIntent, mConnection, BIND_AUTO_CREATE)。绑定和启动服务是两个独立的东西。

【讨论】:

【参考方案4】:

实现此目的的一种方法是使用Android's AIDL 定义一个接口,并利用Binder 子系统执行IPC。我发布的链接中有一组很棒的说明。如果您有问题,我会从那里开始,然后在这里发布。尽管是一个相当复杂的主题 (IPC) Android 和 Binder 在使它变得非常简单方面做得非常好(至少在开始时,我相信如果你愿意,你可以让它变得复杂;-))

编辑 正如 cmets 中所指出的,如果 Service 和客户端在同一进程中运行,则这是不必要的。除非您另外指定,否则这是默认设置。但是,无论如何它仍然有效,只是增加了一点复杂性。

【讨论】:

AIDL 仅在服务和活动位于不同应用程序中时才需要。如果您的服务和活动对您的应用程序来说是本地的(这是常见的情况),请参阅@hackbod 的回复 @odedfos 你说对了一部分。使用 AIDL 的必要性取决于调用者和被调用者是否在不同的进程中,不一定是不同的应用程序。大多数情况下,应用程序只有一个进程,因此这不是问题,但您可以指定服务在与 UI 不同的进程中运行,即使在同一个应用程序中也是如此。 本地服务定义不使用IPC,问题是关于本地服务,所以这个答案是错误的。 @Ixx 默认情况下不会,但您可以指定它们在单独的进程中运行。此外,如果您在与客户端相同的进程中运行服务,这确实工作 ergo 它并没有错,它只是更复杂并且需要更多的开销。【参考方案5】:

我不知道你的问题出在哪里,请发布一些代码。 使用 Binder,Activity 可以访问服务对象。请参阅 API 中的示例以创建活动和服务之间的连接。

在您的活动中拥有服务对象,您可以简单地调用: mService.yourMethod(); 如果您能准确描述您的问题,我们可以为您提供更好的帮助,正如我所说,发布一些 sn-ps。

【讨论】:

为什么不放一些有用资源的链接?发布一些关于如何绑定服务并随后调用其方法的骨架 sn-ps? :) @Juri ***.com/questions/1916253/… 突然链接了【参考方案6】:

Kotlin 的等效代码

MainActivity.kt

private var mBounded = false

private var foregroundService: ForegroundService? = null

 override fun onPostCreate(savedInstanceState: Bundle?) 
    super.onPostCreate(savedInstanceState)

    btn_start_service.setOnClickListener  startMyService(); 

    btn_stop_service.setOnClickListener  stopMyService(); 

    mConnection = object : ServiceConnection 
        override fun onServiceDisconnected(name: ComponentName) 
            Toast.makeText(this@MainActivity, "Service is disconnected", Toast.LENGTH_SHORT)
                .show()
            mBounded = false
            foregroundService = null
        

        override fun onServiceConnected(name: ComponentName, service: IBinder) 
            Toast.makeText(this@MainActivity, "Service is connected", Toast.LENGTH_SHORT).show()
            mBounded = true
            val mLocalBinder = service as LocalBinder
            foregroundService = mLocalBinder.getServerInstance()
        
    

    val startIntent = Intent(this, ForegroundService::class.java)
    bindService(startIntent, mConnection as ServiceConnection, Context.BIND_AUTO_CREATE);



private fun startMyService() 
    foregroundService!!.startService(this, "sdds")



  private fun stopMyService() 
    if (mBounded) 
        mConnection?.let  unbindService(it) ;
        mBounded = false;
    
    val stopIntent = Intent(this, ForegroundService::class.java)
    stopService(stopIntent)

ForegroundService.kt

class ForegroundService : Service() 

private val CHANNEL_ID = "ForegroundService Kotlin"

var mBinder: IBinder = LocalBinder()

fun startService(context: Context, message: String) 
    val startIntent = Intent(context, ForegroundService::class.java)
    startIntent.putExtra("inputExtra", message)
    ContextCompat.startForegroundService(context, startIntent)


fun stopService(context: Context) 
    val stopIntent = Intent(context, ForegroundService::class.java)
    context.stopService(stopIntent)


override fun onBind(intent: Intent?): IBinder? 
    return mBinder



class LocalBinder : Binder() 
    fun getServerInstance(): ForegroundService? 
        return ForegroundService()
    

【讨论】:

以上是关于如何从活动中调用服务的方法?的主要内容,如果未能解决你的问题,请参考以下文章

如何从主要活动中调用片段方法

如何从活动中调用片段方法?

为啥挂起的意图在从服务的通知中调用时不会启动活动

如何在活动形式非活动类中调用方法

从片段中调用父母的活动

从意图活动访问片段方法