Service使用详解

Service就是去掉界面的Activity

Service与Activity较为相似,都可代表可执行的程序,都有生命周期。区别是Service工作在后台,Activity工作在前台。其实根据功能来选择是使用Activity还是Service:需要用户交互(UI)就使用Activity,不需要用户交互,只需做一些处理工作,就用Service。

Service可以做些什么
他要做的就是Activity不需要界面的操作,比如闹钟服务,定了时间后我们不再需要界面显示但是需要计时系统运行。又比如我们短信某些APP比较人性化,发送了短信验证码后会有个自动读取短信验证码的功能,也可以用一个后台Service来监控,Service是一个后台默默无闻的工作者。
Service一种是启动状态,主要用于后台计算。另一种是绑定状态,主要用于其他组件和service的交互。
Service的这两种状态可以共存。

Service的配置

与Activity相似,创建Service需要继承Service类和实现AndroidManifest.xml文件注册。

public class MyService extends Service {
  //onBind(Intent intent)方法必须实现。
    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
        return binder;
    }
}

AndroidManifest.xml中声明此Service(Android Studio自动就添加了声明)

<service android:name=".MyService"/>
//与Activity类似也可添加Intent-filter匹配过滤规则,说明该Service可被那些Intent启动

Service运行和停止
启动Service有两种方式:

  1. 两者不访问,调用Context的startService(Intent)启动,调用stopService(Intent)来停止。
  2. 两者互通数据,则应使用bindService(Intent service,ServiceConnection coon,int flags)绑定和unbindService()解注册。

方式一,两者不访问
我们注册好的这个Service只是一个框架,还需要进一步操作,才能让他跑起来。
设计代码,让按钮点击Service 跑起来,再次点击Stop。代码如下:

在MainActivity.java中用Intent启动Service:

public class MainActivity extends AppCompatActivity {

    private Button open,close;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        open = (Button) findViewById(R.id.button);
        close = (Button) findViewById(R.id.button1);
        final Intent intent = new Intent(this,MyService.class);
        open.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //启动Service
                startService(intent);
            }
        });
        close.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //关闭Service
                stopService(intent);
            }
        });
    }
}

Myservice.java

public class MyService extends Service {

    @Override
    public IBinder onBind(Intent intent) {
        Log.v("test","onBind");
        return binder;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Log.v("test","onCreate");
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.v("test","onStartCommand");
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.v("test","onDestroy");
    }
}

点击打开Service:

04-24 12:50:37.176 3448-3448/com.alphathink.myactivity V/test: onCreate
04-24 12:50:37.177 3448-3448/com.alphathink.myactivity V/test: onStartCommand

点击关闭Service:

04-24 12:51:51.416 3448-3448/com.alphathink.myactivity V/test: onDestroy

多次点击打开Service:

04-24 12:58:14.032 10286-10286/com.alphathink.myactivity V/test: onCreate
04-24 12:58:14.033 10286-10286/com.alphathink.myactivity V/test: onStartCommand
04-24 12:58:16.794 10286-10286/com.alphathink.myactivity V/test: onStartCommand
04-24 12:58:17.480 10286-10286/com.alphathink.myactivity V/test: onStartCommand

可以发现,onCreate()方法不再执行,但会执行onStartCommand()方法。


方式二,实现本地Service绑定和通信

绑定Service:bindService(Intent service,ServiceConnection coon,int flags)
解绑Service:unbindService(ServiceConnection coon)

参数含义:

  • service:通过传入的intent携带service来指定绑定service对象
  • coon:ServiceConnection对象,监听访问者与Service连接状况,连接状态则调用其下的onServiceConnected(ComponentName name,IBinder service),异常终止连接则调用onServiceDisconnected(ComponenttName name)方法,主动解注册则不调用。
  • flags:绑定时确定是否在无Service下新建Service,0–不创建,BIND_AUTO_CREATE–自动创建。

我们实现Service的时候,必须要实现如下方法:

@Override
    public IBinder onBind(Intent intent) {
        Log.v("test","onBind");
        return binder;
    }

在上边的coon连接状态下调用的onServiceConnected(ComponentName name,IBinder service)中也有个IBinder对象,没错两者关联,当我们创建Service时,onBind()方法返回的IBinder对象会在这个方法中复用。访问者就和Service建立起联系了。IBinder充当了桥接的角色。我们与Service通信就是通过IBinder对象来做信使的。实际开发也会有自定义IBinder对象来实现自己的业务逻辑。

MyService.java

public class MyService extends Service {
    private int count;
    private boolean quit;

    private MyBinder binder = new MyBinder();


    public class MyBinder extends Binder {
        public int getCount(){
            return count;
        }
    }

    @Override
    public IBinder onBind(Intent intent) {
        Log.v("test","onBind");
        return binder;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Log.v("test","onCreate");
        new Thread(){
            @Override
            public void run() {
                while(!quit){
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    count++;
                }
            }
        }.start();
    }


    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.v("test","onDestroy");
        this.quit = true;
    }

    @Override
    public boolean onUnbind(Intent intent) {
        Log.v("test","onUnbind");
        return super.onUnbind(intent);
    }
}

MainActivity.java

public class MainActivity extends AppCompatActivity {

    private Button open,close,status;
    private MyService.MyBinder binder;
    private ServiceConnection coon = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Log.v("test","service is connected");
            binder = (MyService.MyBinder) service;
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            Log.v("test","service is disconnected");
        }
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        open = (Button) findViewById(R.id.button);
        close = (Button) findViewById(R.id.button1);
        status = (Button) findViewById(R.id.button2);
        final Intent intent = new Intent(this,MyService.class);
        open.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //绑定Service
                bindService(intent,coon, Service.BIND_AUTO_CREATE);
            }
        });
        close.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //解绑Service
                unbindService(coon);
            }
        });
        status.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(MainActivity.this,"service目前count值为"+binder.getCount(),Toast.LENGTH_SHORT).show();
            }
        });
    }

}

运行后,点击打开Service:

04-27 16:53:24.241 15006-15006/com.alphathink.myactivity V/test: onCreate
04-27 16:53:24.244 15006-15006/com.alphathink.myactivity V/test: onBind
04-27 16:53:24.245 15006-15006/com.alphathink.myactivity V/test: service is connected

点击关闭Service:

04-27 16:53:55.268 15006-15006/com.alphathink.myactivity V/test: onUnbind
04-27 16:53:55.269 15006-15006/com.alphathink.myactivity V/test: onDestroy

点击获取状态:
这里写图片描述

这样就完成了绑定service的使用,与方法一不同的是重复按打开service但是onBind()只会执行一次。


Service的生命周期:

分析了以上两种方式,当然Service的生命周期也会有两种:(分别对应方式一二)
这里写图片描述



Service中的ANR
普通Service局限性:

  • 与启动Service的应用位于同个线程中。
  • 非新线程,不能处理耗时任务。(Activity5s,Broadcast10s,Service20s(小概率)会出现ANR)

测试:在方式一中更改onStartCommand()方法为:

@Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        try {
            Thread.sleep(20000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        Log.v("test","onStartCommand");
        return super.onStartCommand(intent, flags, startId);
    }

大约20s出现ANR。所以出现了IntentService。

IntentService的使用
IntentService是Service的子类,IntentService使用队列来管理请求Intent,然后开启新线程来处理他,保证同一时刻处理一个Intent。因此他不会阻塞主线程。避免了ANR的出现。另IntentService为onBind()和onStartCommand()提供了默认实现,因此我们不必重复实现。只需要实现onHandleIntent()方法即可。

MyIntentService.java

public class MyIntentService extends IntentService {


    public MyIntentService(String name) {
        super(name);
    }


    @Override
    protected void onHandleIntent(Intent intent) {

    }
}

MainActivity.java

public class MainActivity extends AppCompatActivity {

    private Button open;

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

        open = (Button) findViewById(R.id.button);
        final Intent intent = new Intent(this, MyIntentService.class);
        open.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //绑定Service
                Log.v("test","ssssss");
                startService(intent);
            }
        });
    }

}

是不是简便清爽了很多呢。由于在新线程操作,测试20s耗时操作的时候是不会出现ANR的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值