学习Service第一天,后头看之前写的那些博客 架构上还是有点不是很清晰,还是要把基础的调用分开写,然后再写项目代码,这样看起来会比较清晰
好了今天就先试验一下
进入主题,Android Service的使用,作为四大控件之一,Service还是很重要的。
1、Service可以理解为后台,何为后台,就是在界面没有任何显示的情况下,偷偷摸摸的干些事情。
2、Service在默认的情况下,还是属于主线程的!!!这点一定要注意,如果直接启动Service,并且让他做一些需要长期等待的工作,呵呵,不好意思UI界面直接无响应,所以一般Service都是的逻辑操作或者等待监听都是通过起一个线程,来解决的。
3、Service一定记得要在AndroidManifest注册,四大组件都要注册!!
简单注册代码
<service android:name=".MyService">
</service>
一、使用Service必须使用一个类去继承Service
public class MyService extends Service
Service这个类,必须实现一个抽象方法
public IBinder onBind(Intent intent)
这个函数只有一个参数,我们来看一下解释
intent The Intent that was used to bind to this service人工解释:这个Intent是被用来绑定这个Service的,什么意思。之后再启动Service的时候我会解释的
然后看返回值
Return an IBinder through which clients can call on to the service人工解释(我猜了一些词,不一定完全准确,但是我知道他指的是啥,一会告诉大家):
当客户端让这个Service上线的时候,这个函数会返回一个IBinder类型的对象
这个在之后一会解释的
这样赤裸裸的一个类,就一个onBind方法,肯定是达不到我们的要求的,我们还需要重写他的一些父类方法
我这个实例,只是讲简单创建使用,所以都是伪逻辑,只是用Log打印说明方法被调用
看一下我们需要的方法
@Override
public void onCreate() {
super.onCreate();
Log.d("Service", "onCreate");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d("Service", "onStartCommand");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
Log.d("Service", "onDestroy");
}
onCreate,onStartCommand,onDestroy,这不就是一个生命周期么
我已经测试过了,所以我们一个一个来看
onCreate方法,只有在这个服务第一次创建的时候,才会调用,注意Service的唯一性
onStartCommand方法,其实原来使用的onStart方法,只不过被Google淘汰了,但其实这个方法的内部逻辑,还是调用了onStart这个方法,具体可以自己看一下源码。这个方法里,之后会存放我们的主要逻辑。或者说在这里启动一个处理逻辑的线程。
onDestroy方法与OnCreate方法是一对,有创建才有销毁。
我们把方法介绍完了,就来看一下,如果启动一个Service
二、启动Service
我在MainActivity创建了4个Button控件,两两一对,用来匹配启动Service的两种方法
<?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:id="@+id/activity_main"
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.tyran.frontservice_demo1.MainActivity">
<Button
android:id="@+id/StartService"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/start_service"
android:onClick="OnClick"/>
<Button
android:id="@+id/StopService"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/stop_service"
android:onClick="OnClick"/>
<Button
android:id="@+id/BindService"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/bind_service"
android:onClick="OnClick"/>
<Button
android:id="@+id/UnBindService"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/unbind_service"
android:onClick="OnClick"/>
</LinearLayout>
第一种方法,通过startService和stopService来控制Service
这两个方法都只有一个参数Intent,那这个Intent该如何初始化呢
VeryEasy
intent = new Intent(this, MyService.class);
intent.putExtra("Flag", "100");
MyService就是Service的子类
那之后的putExtra的作用是什么呢?
还记得之前的onBind方法么,我现在可以告诉你,这个Intent就是之后就会被传到onBind方法的Intent,所以我在这里添加了一个标记数据,之后我会在onBind里取出并打印。这里先提一下,在之后的第二种方法里我会重新解释一下。
既然Intent已经有了,那无非就是绑定控件,一个switch
case R.id.StartService:
startService(intent);
break;
case R.id.StopService:
stopService(intent);
break;
当我点击StartService这个按钮时,看一下Log输出
D/Service: onCreate
D/Service: onStartCommand
点击StopService
D/Service: onDestroy
我连续点击两下StartService
D/Service: onCreate
D/Service: onStartCommand
D/Service: onStartCommand
验证了我之前的说法,onCreate方法只会执行一次
大家注意到,Log里没有出现onBind的信息,但是我在onBind里是会打印Log的呀,并且在应用管理器中,能看到MyService这个服务的运行状态为启动。我们唯一要实现的方法居然没有调用,这肯定是不行的。那如何解决呢?
看我们的第二种方法
也是一对方法bindService和unbindService
public boolean bindService(Intent service, ServiceConnection conn, int flags)
public void unbindService(ServiceConnection conn)
绑定和解除绑定
看了方法定义我们会发现多了一个ServiceConnection,而且之前我们并没有创建或者使用过,这个类型,那我们就创建一个
private ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
binder = (MyService.MyBinder) service;
binder.BindNotification();
Log.d("Service", "onServiceConnected");
}
@Override
public void onServiceDisconnected(ComponentName name) {
Log.d("Service", "onServiceDisconnected");
}
};
创建之后,貌似就明了了,一个连接一个断开连接,并且这个IBinder貌似也似曾相识,不就是onBind的返回值么
查看一下源码,发现IBinder是一个接口,那必然需要一个实现类
在MyService里创建一个类
public class MyBinder extends Binder
{
public void BindNotification()
{
Log.d("Service", "MyBinder");
}
}
并且我把onBind的代码也贴一下
MyBinder binder = new MyBinder();
@Nullable
@Override
public IBinder onBind(Intent intent) {
Log.d("Service", "onBind");
Log.d("Service", "Intent"+intent.getStringExtra("Flag"));
return binder;
}
对比一下,onServiceConnected的方法,第二个形参,在看一下onBind的解释,会返回一个IBinder,
经过测试,原来onBind方法的返回值,就是回传到onServiceConnected方法的第二个形参。既然是传递,自然要有实体,我们构造的MyBinder类自然要在MyService里构造对象,然后MyBinder通过onBind传递给onServiceConnected,是不是突然之间思路就清晰了
MyBinder->onBind->onServiceConnected就是这样一个过程,在MyBinder里只有一个打印Log的方法,虚拟一下逻辑
好了,陌生的讲完,我们回过头看onBind的参数Intent,前面已经说过回传这个事情了,这个自然也能联想到,bindService的第一个形参,对,你猜对了,这也是一个传参,具体我就不解释啦,上面onBind的代码已经写得很清楚啦,注意第二条打印Log即可。就剩下bindService的第三个参数了,这个其实就是个标记,BIND_AUTO_CREATE代表绑定服务时如果服务未创建,自动创建,怎么创建呢,就是调用Service类的onCreate
unbindService唯一的一个参数,就是ServiceConnection这个没啥好说的。我重新理一下顺序
bindService->ServiceConnection.onServiceConnected->onCreate
我再把第一种写一下
startService->onCreate->onStartCommand
实际的应用场景,其实我也不是很明白,之后肯定会有实际应用的例子补充,以后再说啦
接下来就是完整代码
首先是AndroidManifest
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.tyran.frontservice_demo1">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name=".MyService">
</service>
</application>
</manifest>
然后是MainActivity的xml
<?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:id="@+id/activity_main"
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.tyran.frontservice_demo1.MainActivity">
<Button
android:id="@+id/StartService"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/start_service"
android:onClick="OnClick"/>
<Button
android:id="@+id/StopService"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/stop_service"
android:onClick="OnClick"/>
<Button
android:id="@+id/BindService"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/bind_service"
android:onClick="OnClick"/>
<Button
android:id="@+id/UnBindService"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/unbind_service"
android:onClick="OnClick"/>
</LinearLayout>
MainActivity
package com.tyran.frontservice_demo1;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
public class MainActivity extends AppCompatActivity {
Intent intent;
private MyService.MyBinder binder;
private ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
binder = (MyService.MyBinder) service;
binder.BindNotification();
Log.d("Service", "onServiceConnected");
}
@Override
public void onServiceDisconnected(ComponentName name) {
Log.d("Service", "onServiceDisconnected");
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
intent = new Intent(this, MyService.class);
intent.putExtra("Flag", "100");
}
public void OnClick(View v)
{
switch (v.getId())
{
case R.id.StartService:
startService(intent);
break;
case R.id.StopService:
stopService(intent);
break;
case R.id.BindService:
bindService(intent,connection,BIND_AUTO_CREATE);
break;
case R.id.UnBindService:
unbindService(connection);
break;
}
}
}
MyService
package com.tyran.frontservice_demo1;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.support.annotation.Nullable;
import android.util.Log;
/**
* Created by Tyran on 2017/2/27.
*/
public class MyService extends Service {
MyBinder binder = new MyBinder();
@Nullable
@Override
public IBinder onBind(Intent intent) {
Log.d("Service", "onBind");
Log.d("Service", "Intent"+intent.getStringExtra("Flag"));
return binder;
}
@Override
public void onCreate() {
super.onCreate();
Log.d("Service", "onCreate");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d("Service", "onStartCommand");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
Log.d("Service", "onDestroy");
}
public class MyBinder extends Binder
{
public void BindNotification()
{
Log.d("Service", "MyBinder");
}
}
}
这样完整的看一遍,应该基本的使用应该就都明白了吧。回头我也自己多看看 哈哈哈