Android - 在Activity中使用Service的方法?

13

我的应用程序中有以下方法:

public void switchSpeaker(boolean speakerFlag){

        if(speakerFlag){
        audio_service.setSpeakerphoneOn(false);
        }
        else{
        audio_service.setSpeakerphoneOn(true);
        }

    }

所以我的问题是,最好和最有效的方法是什么,以便在以下Activity中使用这种方法:

final Button speaker_Button = (Button) findViewById(R.id.widget36);

            speaker_Button.setOnClickListener(new View.OnClickListener(){
                public void onClick(View v){

                    switchSpeaker(true); //method from Service

                }

            });

我是否必须编写 AIDL,还是有更简单的方法?

3个回答

71

有三种方法可以将服务与您的活动绑定。

  1. IBinder实现
  2. 使用Messanger
  3. 使用AIDL

在这些方法中,IBinder实现是最适合您的情况。

IBinder类的示例

1. Server.java 服务

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 void switchSpeaker(boolean speakerFlag){

        if(speakerFlag){
        audio_service.setSpeakerphoneOn(false);
        }
        else{
        audio_service.setSpeakerphoneOn(true);
        }

    }
}

2. Client.java 活动

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) {
            mServer.switchSpeaker(true);
        }
    });

}

@Override
protected void onStart() {
    super.onStart();
    Intent mIntent = new Intent(this, Server.class);
bindService(mIntent, mConnection, BIND_AUTO_CREATE);
};

ServiceConnection mConnection = new ServiceConnection() {

    public void onServiceDisconnected(ComponentName name) {
        Toast.makeText(Client.this, "Service is disconnected", 1000).show();
        mBounded = false;
        mServer = null;
    }

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

Messenger类的示例

1. Server.java服务

public class Server extends Service{

    Messenger messenger = new Messenger(new LocalHandler());
    Messenger clientMessenger;
    static final int SysterTime = 0;
    static final int AddHandler = 1;
    List<Handler> mHandlers;

    @Override
    public void onCreate() {
        super.onCreate();
        mHandlers = new ArrayList<Handler>();
    }

    @Override
    public IBinder onBind(Intent intent) {
        return messenger.getBinder();
    }

    public class LocalHandler extends Handler {

        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
            case SysterTime:
                SimpleDateFormat mDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                try {
                    clientMessenger.send(Message.obtain(null, SysterTime, mDateFormat.format(new Date())));
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
                break;

            case AddHandler:
                clientMessenger = new Messenger((Handler) msg.obj);
                try {
                    clientMessenger.send(Message.obtain(null, AddHandler, "Registed messanger"));
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
                break;

            default:
                break;
            }
            super.handleMessage(msg);
        }
    }
}

2. Client.java 活动

public class Client extends Activity {

    Messenger messenger;
    boolean mBounded;
    TextView text;
    Button button;
    Button register;


    @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) {

                Message message = Message.obtain(null, Server.SysterTime, null);
                try {
                    messenger.send(message);
                } catch (RemoteException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        });

        register = (Button) findViewById(R.id.register);
        register.setOnClickListener(new OnClickListener() {

            public void onClick(View v) {

                Message message = Message.obtain(null, Server.AddHandler, new ClientHandle());
                try {
                    messenger.send(message);
                } catch (RemoteException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        });

    }


    public class ClientHandle extends Handler {

        @Override
        public void handleMessage(Message msg) {

            switch (msg.what) {
            case Server.SysterTime:
                text.setText(msg.obj.toString());
                break;

            case Server.AddHandler:
                text.setText(msg.obj.toString());
                break;

            default:
                break;
            }

            super.handleMessage(msg);
        }


    }

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

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



    @Override
    protected void onStop() {
        super.onStop();
        if(mBounded) {
            unbindService(mConnection);
        }
    }



    ServiceConnection mConnection = new ServiceConnection() {

        public void onServiceDisconnected(ComponentName name) {
            mBounded = false;
            messenger = null;
        }

        public void onServiceConnected(ComponentName name, IBinder service) {
            Toast.makeText(Client.this, "Service is connected", 1000).show();
            messenger = new Messenger(service);
            mBounded = true;
        }
    };
}

AIDL的示例

1. IRemoteService.aidl

package com.example.bindservice.aidl;

interface IRemoteService {

    String getMessage(String msg);
}

2. Server.java 服务

public class Server extends Service{

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

    IRemoteService.Stub mStub = new IRemoteService.Stub() {

        public String getMessage(String msg) throws RemoteException {
            return msg;
        }
    };
}

3. Client.java 活动

public class Client extends Activity {

    Button button;
    TextView text;
    boolean mBound;
    IRemoteService mIRemoteService;
    EditText etMsg;

    @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);
        etMsg = (EditText)findViewById(R.id.etMsg);
        button.setOnClickListener(new OnClickListener() {

            public void onClick(View v) {

                if(mBound) {
                    try {
                        text.setText(mIRemoteService.getMessage(etMsg.getText().toString()));
                    } catch (RemoteException e) {
                        e.printStackTrace();
                    }                   
                }
            }
        });
    }

    @Override
    protected void onStart() {
        super.onStart();
        bindService(new Intent(Client.this, Server.class), mConnection, BIND_AUTO_CREATE);
    }

    @Override
    protected void onStop() {
        super.onStop();
        if(mBound) {
            unbindService(mConnection);
            mBound = false; 
        }
    }

    ServiceConnection mConnection = new ServiceConnection() {

        public void onServiceDisconnected(ComponentName name) {
            mIRemoteService = null;
            mBound = false;
        }

        public void onServiceConnected(ComponentName name, IBinder service) {
            mIRemoteService = IRemoteService.Stub.asInterface(service);
            mBound = true;
        }
    };
}

你可以参考这份文档以深入学习相关内容。


我正在使用AIDL的示例3,在这里遇到了空指针异常:String a = mIRemoteService.getMessage("msg"); - RajaReddy PolamReddy
@RajaReddyPolamReddy 请发布您的代码并提出新问题,这样您就可以获得更多和更好的答案。 - Dharmendra
我在我的情况下完全按照您的“IBinder类示例”进行操作,但是我收到了NullPointerException。 我认为我的服务根本没有绑定。 您能否请查看我的问题: 链接 - Taha Rushain
非常好的答案,完全符合我的要求。谢谢! - Martin Pfeffer
哪一种更可靠? - Solanki Kamlesh

3

这是公开的,对吧 :)

您可以调用bindService(Intent)方法。看一下ApiDemos中的LocalServiceBinding类。

在回调方法onServiceConnected中,您可以看到:

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

        // Tell the user about this for our demo.
        Toast.makeText(LocalServiceBinding.this, R.string.local_service_connected,
                Toast.LENGTH_SHORT).show();
    }

现在,使用服务对象(mBoundService)调用该方法。
就是这样 :)

但这样它将成为一个有限制的服务,即使活动组件被销毁后我也无法使用它。还有其他方法吗? - Kaveesh Kanwal
如果您希望在活动被销毁时服务仍然在后台运行,则可以正常启动服务而无需将其绑定到您的活动。然后,要从服务中调用方法,而不是直接调用,您可以使用具有预定义操作或额外数据的 Intent 调用 startService,无论服务是否已经运行,它都会调用 onStartCommand 方法 --> 检查意图并在意图匹配时调用所需的方法。这里的关键区别在于此调用是异步的,您无法直接获取方法结果。 - Binh Tran

3
你需要为客户端暴露服务的switchSpeaker方法。定义你的.aidl文件。然后从你的活动中绑定到该服务并简单地调用switchSpeaker。请参见文档
没有其他简单的方法来调用此方法,除非它是静态的。

1
对于 .aidl,我们必须处理多线程,因此这不是实现 aidl 并使用本地服务的适当方式。相反,有两个其他选项可供我们使用,它们是使用 IBinder 和使用 Messanger。如果与活动绑定的是本地服务,则 IBinder 将是最佳选择。 - Dharmendra
1
链接损坏了 :p @ponkin - Pankaj

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接