Android初学之Service(一)

**概述:**android中的Service是四大组件之一,它的功能十分类似于Activity,但是又有所不同。Activity主要是通过UI界面的交互作用完成任务,而Service则完全是一个隐藏于后台的功能执行者。比如后台播放音乐,后台监听地理位置的变化等等。根据Service启动方式的不同,可以将Service分为start型和bind型。


一个service实现的步骤如下:
1)定义一个MyService并且继承自Service(或者IntentService),根据需要的启动方式重写方法。
2)在AndroidManifest.xml中添加声明
3)声明一个intent对象,并调用启动方法


Start型Service
start型service是通过startService(intent)方法来启动service的,启动service的线程称为主线程,启动后会运行onStartCommand()中的方法,如果该方法中的操作十分耗时,则会堵塞主线程,影响app性能。这个时候一般是在onStartCommand()中新建一个线程去完成这个耗时操作。service运行后一般不会主动销毁,需要自己在外部stopService()或者在内部使用stopSelf()方法。若自己定义的service是继承IntentService的,则无需考虑阻塞和销毁问题。


start型实例代码:
MainActivity代码:

package com.example.administrator.startedservice;

import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    public void startClickService(View v){
        Intent intent = new Intent(this,MyService.class);
        startService(intent);
    }
}

MyService代码:

package com.example.administrator.startedservice;

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

public class MyService extends Service {

    public MyService() {
    }

    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
        throw new UnsupportedOperationException("Not yet implemented");
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
    //耗时操作
        for(int i=0;i<10;i++){
            System.out.println(startId+"---"+i);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        return START_STICKY;
    }
}

运行上面的代码会发现,点击按钮后,按钮一直处于按下去的状态,这说明onStartCommand的操作会阻塞启动该service的主线程。所以此时的最佳方法是新建一个线程运行耗时操作,此处不再列出代码。

start型Service实现步骤总结:

1、定义自己的service,继承Service,由于是start型,所以只需要重写onStartCommand方法,此方法是用户的业务操作代码。
2、根据自身需求可以选择是否重写其他方法,如onDestroy、onCreate等方法。
3、在Activity中声明Intent对象,并通过startService启动service
4、销毁service

——–IntentService——–
若继承了IntentService则,只需要在MyService中实现onHandleIntent(Intent intent)方法,将耗时的操作放在该方法这种就不会堵塞主线程。并且运行后会自动销毁service。

start后的service若不及时stop则该service会一直存在于后台运行,即使你的app已经退出了

bind型service:以上的start型service有一个很大的缺点:无法与service的调用者进行通信,即start方法没有返回一个值,他只是被动的告诉service应该做些什么,他无法得到service的返回结果,也无法访问service内部的对象。而通过bindService()方法绑定service后,会回调一个onBind()方法,而onBind()方法会返回一个IBinder对象,调用者能通过这个IBinder对象访问service内部成员或者远程操作service。bind型service将程序分为了两大部分,访问service的那一方是客户端,一般是Activity等能够bindService的组件;另一部分是service的服务端。

bind型service实现步骤(本地通信):

1、编辑一个AIDL文件,以IPerson为例,其格式如下:

// IPerson.aidl
package com.zhouyou.bindservice;
// Declare any non-default types here with import statements
interface IPerson {
    /**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
     void setName(String name);
     void setSex(String sex);
     String getPerson();
}

编辑好后,点击Make Project会在指定位置自动生成java文件。

2、 生成的java文件位于build 文件下的generated/source/aidl/debug中,该Java文件中包含两大部分:1)继承了IBinder的静态抽象类Stub 2)和IPerson.aidl相关的属性和方法函数。在上述的IPerson.java文件中,Stub中含有一个代理类Proxy实现了IPerson接口,其远程的通信都是这个代理来完成的,另外这个抽象类Stub的最重要的方法是asInterface,该方法返回了IPerson的实例。用于判断一个通信是远程还是本地,并根据不同情况返回不同的实例。由于Proxy也是实现了IPerson的,所以当要进行远程通信时,可以返回一个Proxy实例,让这个实例帮助我们去完成相关操作。

3、编辑一个PersonImpl.java用以实现业务对象的具体操作,具体代码如下:

public class PersonImpl extends IPerson.Stub {

    private String name,sex;
    @Override
    public void setName(String name) throws RemoteException {
        this.name = name;
    }

    @Override
    public void setSex(String sex) throws RemoteException {
        this.sex = sex;
    }

    @Override
    public String getPerson() throws RemoteException {

        return "name = " + name + ", sex = " + sex;
    }
}

4、开始编写自己的service,主要是重写onBind()方法。该方法会返回一个IBinder的对象,由于PersonImpl是扩展(继承)自IBinder的,所以可以返回一个PersonImpl的对象。具体代码如下:

public class MyService extends Service {

    private PersonImpl person;

    public MyService() {
    }

    @Override
    public IBinder onBind(Intent intent) {
        person = new PersonImpl();
        return person;
    }
}

5、最后,需要完成的就是Activity中的代码了,Intent 的声明和Start型完全一样,不同的是需要调用bindService(Intent intent, ServiceConnection conn,int flag)方法。其中intent包含了该组件绑定哪一个Service;conn会自动调用ServiceConnection中的相关方法,如果连接成功则是onServiceConnected(ComponentName name, IBinder service)方法。该方法中,ComponentName是绑定该服务的组件名称;service则是 MyService中onBind()方法返回的对象,而MyService作为一个服务端,将他自己的对象暴露给了客户端,这样就完成了客户端和服务端的数据通信。我们可以对这个返回的IBinder service进行操作,从而对服务端进行操作,至于如何操作,这就不需要去关心了;flag是bind的模式参数。具体代码如下:

package com.zhouyou.bindservice;

import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;

import com.zhouyou.service.MyService;

public class MainActivity extends AppCompatActivity {

    private IPerson person;



    private ServiceConnection conn = new ServiceConnection() {
        @Override
       /*
       *
       * 本函数在服务连接成功时调用
       * 其中name表示调用service的组件名称,service则表示被调用的服务中onBind(Intent)方法返回的IBinder对象
       * 本函数作用:将service端返回的IBinder对象转换成IPerson并暴露给MainActivity
       *
       * */
        public void onServiceConnected(ComponentName name, IBinder service) {
            person = IPerson.Stub.asInterface(service);
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
        }
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

    }

    /*
    *
    * 按钮的点击事件
    *
    * */
    public void bindService(View v){
        try {
            person.setName("小明");
            person.setSex("女");
            System.out.println(person.getPerson());
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }
    /**
    *
    *onResume()中绑定service,onPause中解绑
    *这样不会出现MainActivity has leaked、、、、的错误
    */
    public void onResume(){
                Intent intent = new Intent(this,MyService.class);
        bindService(intent, conn, BIND_AUTO_CREATE);
    }
    public void onPause(){
        unBindService(conn);
    }
}

其布局文件中只含一个按钮,十分简单所以在这不再赘述。


由于个人水平有限,难免有不足之处,希望大家不吝赐教。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值