Android Service的使用

来源:互联网 发布:ipad mini4 air2 知乎 编辑:程序博客网 时间:2024/05/06 16:55

Service是安卓开发的四大组件之一,没有用户界面,一直运行于后台。Service可用于在执行一些耗时或者不需要界面的后台操作,比如播放音乐。
这里我来记录一下Service的使用方法,包括Service的启动、绑定、通信等操作。
首先新建一个MyService继承Service,重写父类的各回调方法。为了方便观察各方法的执行顺序,为各个方法加上日记输出语句。

public class MyService extends Service {    public MyService() {    }    @Override    public void onCreate() {        super.onCreate();        Log.e("TAG", "onCreate方法被调用");    }    @Override    public int onStartCommand(Intent intent, int flags, int startId) {        Log.e("TAG", "onStartCommand方法被调用");        return super.onStartCommand(intent, flags, startId);    }    @Override    public void onDestroy() {        super.onDestroy();        Log.e("TAG", "onDestroy方法被调用");    }    @Override    public IBinder onBind(Intent intent) {        Log.e("TAG", "onBind方法被调用");        throw new UnsupportedOperationException("Not yet implemented");    }}

修改默认布局,为之添加两个按钮,分别用于启动和停止服务。

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:paddingBottom="@dimen/activity_vertical_margin"    android:paddingLeft="@dimen/activity_horizontal_margin"    android:paddingRight="@dimen/activity_horizontal_margin"    android:paddingTop="@dimen/activity_vertical_margin"    android:orientation="vertical"    tools:context="com.example.zy.myservice.MainActivity">    <Button        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:id="@+id/btnStartService"        android:text="启动服务"/>    <Button        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:id="@+id/btnStopService"        android:text="停止服务"/></LinearLayout>

修改MainActivity类,监听两个按钮的点击动作,通过Intent来启动或停止服务。

public class MainActivity extends AppCompatActivity implements View.OnClickListener {    private Button btnStartService;    private Button btnStopService;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        init();    }    public void init() {        btnStartService = (Button) findViewById(R.id.btnStartService);        btnStopService = (Button) findViewById(R.id.btnStopService);        btnStartService.setOnClickListener(this);        btnStopService.setOnClickListener(this);    }    @Override    public void onClick(View v) {        switch (v.getId()) {            case R.id.btnStartService:                startService(new Intent(this, MyService.class));                break;            case R.id.btnStopService:                stopService(new Intent(this, MyService.class));                break;        }    }}

程序运行界面如下:

这里写图片描述

点击启动服务按钮,日志输出如下:

这里写图片描述

点击停止服务按钮,日志输出如下:

这里写图片描述

可以看到,启动服务并没有执行到onBind方法。而且,当多次点击启动服务按钮时,onCreate方法只会被执行一次,而onStartCommand方法会被调用多次。
为了模拟后台操作,修改onCreate方法,让它新建一个线程,用于不断输出语句。
首先声明三个属性

    private String data="默认信息";    private int index;    private boolean flag;

每当执行到onCreate方法时,就会新建一个子线程用于输出data,而且每输出一句就休眠一秒。

 public void onCreate() {        super.onCreate();        Log.e("TAG", "onCreate方法被调用");        flag=false;        new Thread(){            @Override            public void run() {                super.run();                while(flag){                    index++;                    System.out.println(index+" : "+data);                    try {                        sleep(1000);                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                }            }        }.start();    }

又因为开启了子线程,如果不主动停止的话,就算执行了onDestroy方法,子线程也会继续在后台执行,所以修改onDestroy

 @Override    public void onDestroy() {        super.onDestroy();        flag = false;        Log.e("TAG", "onDestroy方法被调用");    }

这样,当执行onDestroy方法时,子线程也就不会继续输出了。

这里写图片描述

服务除了启动外,也有用于绑定的形式,为默认布局添加两个按钮,分别用于绑定服务以及取消绑定服务。
修改MainActivity的onClick方法

 @Override    public void onClick(View v) {        switch (v.getId()) {            case R.id.btnStartService:                startService(new Intent(this, MyService.class));                break;            case R.id.btnStopService:                stopService(new Intent(this, MyService.class));                break;            case R.id.btnBindService:                bindService(new Intent(this,MyService.class),this, Context.BIND_AUTO_CREATE);                break;            case R.id.btnUnbindService:                unbindService(this);        }    }

bindService方法用于绑定服务,参数二需要传入一个ServiceConnection接口的实现类,让MainActivity类实现之,所以传入this

ServiceConnection接口需要实现的方法如下所示

 @Override    public void onServiceConnected(ComponentName name, IBinder service) {    }    @Override    public void onServiceDisconnected(ComponentName name) {    }

此外,绑定服务需要重写onBind(Intent intent)方法,返回一个IBinder类型的对象,这里可以自己声明一个实现了Binder接口的MyBind内部类。

    public class MyBinder extends Binder {    }    @Override    public IBinder onBind(Intent intent) {        Log.e("TAG", "onBind方法被调用");        return new MyBinder();    }

启动程序,点击绑定服务按钮,可以看到日志输出如下所示,绑定服务后并没有执行onStartCommand方法,而是执行了onBind方法。

这里写图片描述

此外,我们该如何与服务进行通信呢,比如说修改Service的输出语句。
其实,onServiceConnected(ComponentName name, IBinder service)方法会在服务绑定成功的时候执行,当中的IBinder 参数即为MyService中onBind方法返回的对象,通过它,我们就可以与服务进行通信了。
为默认布局增添一个EditText,用于输入想要日志输出的语句,此外还要一个Button,用于同步数据。
修改MyBinder类,为之增添一个方法,用于修改输出信息。

    public class MyBinder extends Binder {        public void setData(String data) {            MyService.this.data = data;        }    }

在MainActivity中声明一个MyBinder对象,通过onServiceConnected方法就可以获得onBind返回的对象的引用了。

    private MyService.MyBinder myBinder; @Override    public void onServiceConnected(ComponentName name, IBinder service) {        this.myBinder= (MyService.MyBinder) service;    }

修改MainActivity的onClick方法,添加一个判断语句,用于修改输出语句

case R.id.btnSyncData:                if (myBinder != null) {               myBinder.setData(editText.getText().toString());                }

程序运行界面如下:

这里写图片描述

点击绑定服务,因为编辑框中已经有默认文本,所以直接点击同步数据,日志输出如下:

这里写图片描述

可以看到输出语句成功修改了。

既然可以在Activity中向Service传递数据,那Service又该如何向Activity返回数据呢?
用以上的方法似乎不行,不过可以通过回调方法来实现。
在默认布局中增添一个TextView,用于显示当前的输出语句。

为MyBinder方法增添一个返回服务对象引用的方法

public class MyBinder extends Binder {        public void setData(String data) {            MyService.this.data = data;        }        public MyService getMyService() {            return MyService.this;        }    }

声明一个接口以及一个接口对象

    public interface CallBack {        public void editTextView(String data);    }    public CallBack callBack;

修改onCreate方法,当callBack不为空时,每执行一次输出语句就调用一次editTextView方法

 @Override    public void onCreate() {        super.onCreate();        Log.e("TAG", "onCreate方法被调用");        flag = true;        new Thread() {            @Override            public void run() {                super.run();                while (flag) {                    index++;                    String outPutData=index + " : " + data;                    System.out.println(outPutData);                    if(callBack!=null){                        callBack.editTextView(outPutData);                    }                    try {                        sleep(1000);                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                }            }        }.start();    }

在MainActivity中声明一个MyService.CallBack对象
修改onServiceConnected方法传递引用

@Override    public void onServiceConnected(ComponentName name, IBinder service) {        this.myBinder = (MyService.MyBinder) service;        ((MyService.MyBinder) service).getMyService().callBack = this.callBack;    }

因为子线程中不允许更新UI组件,函数应写为

private MyService.CallBack callBack = new MyService.CallBack() {        @Override        public void editTextView(String data) {            Message msg = new Message();            msg.obj = data;            handler.sendMessage(msg);        }    };    private Handler handler = new Handler() {        @Override        public void handleMessage(Message msg) {            super.handleMessage(msg);            textView.setText(msg.obj.toString());        }    };

则程序运行结果如下所示

这里写图片描述

0 0
原创粉丝点击