您的位置:首页 > 其它

Service的使用

2016-05-16 22:52 369 查看
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());
}
};


则程序运行结果如下所示

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: