Android第3讲:服务

文章关于活动的创建,布局代码,控件绑定没有指出,可以先找到相关视频进行基础学习

Service 服务

有些应用很少与用户交互。他们只是在后台与用户进行交互,他们只是在后台处理一些任务,而且在运行期间用户仍能运行其他应用。Android系统通过服务和广播接收器组件实现这一需求。

1 服务的概述

为了处理这种后台进程,Android引入了服务的概念。服务在Android中是一种长生命周期的后天运作组件,他不断提供任何用户界面。最常见的例子就是媒体播放器应用,它可以在转到后台运作的时候仍然能播放歌曲。
和其他组件一样,服务也是运行在主线程中。这意味着如果服务要进行耗费CPU或阻塞操作,它应该创建新的线程,在新的线程里进行这些工作。

1.1 创建服务

创建流程和创建活动类似,流程如下:

  • 编写相应的组件类型
    要求继承android.app.Service或其中子类,并覆盖它的某些方法。服务有很多重要的子类,常用如下:

    • android.app.Service。最基本的服务类
    • android.app.IntentService。处理异步请求的服务类

    创建服务类实例代码如下 :

    public class MyService extends Service{
    	@Override
    	public IBinder onBind(Intent intent){
    		//TODO
    	}
    	@Override
    	public void onCreate(){
    		//TODO
    	}
    	@Override
    	public void onDestroy(){
    		//TODO
    	}
    	@Override
    	public int onStartCommand(Intent intent ,int flags,int starId){
    		//TODO
    	}
    	
    }
    
  • 在AndroidManifest.xml文件中注册

      <service
      	android:name=".MyService"
      	android:enabled="true"
      	android:exported="true"/>
    

    android:enabled="true"是设置服务器是否能够被系统实例化,true表示能,是默认值
    android:exported="true"是设置服务器是否能够被其他应用启动,true表示能,是默认值
    注意:为了保证应用的安全性请不要使用隐式意图启用服务,因为服务是一种可以在后台长期运行的组件,如果android:exported=“true”,又设置了隐式意图,就有可能被其他恶意程序在不知不觉中启动和运行

1.2 服务的分类

上面说了怎么创建一个服务,但是创建完了我需要去使用它,但是服务分为两种类型。启动类型服务绑定类型服务。这两者的生命周期和使用方式是不同的,下面就分别对两种类型服务的使用方式进行讲解。

2 启动类型服务

2.1 启动服务的概述

当应用组件(活动或服务)通过调用startService()启动服务时,服务即处于启动状态。一旦启动服务,启动它的组件就不能再管理和控制服务了,启动组件与服务是一种松耦合的关系。因此启动类型服务通常是执行单一操作,不会将结果返回给调用方。

2.2 启动服务生命周期

启动服务的生命周期如图所示。(注意是启动服务的生命周期,绑定服务是不一样的,不要混淆)。
在这里插入图片描述

启动服务生命周期由上图所示,可以从两个方面分析:两个嵌套循环、三个方法

两个嵌套循环

  • 整个生命周期循环
    服务的整个生命周期发生在onCreate()调用与onDestroy()调用之间。

    启动组件(活动或服务)可以通过调用startSerivce()方法并传递意图对象来启动服务,系统会根据意图查找这个服务。(这个启动的流程和我们之前说的启动活动的方式相同只是使用的方法不同)。

    然后系统会调用服务的onCreate()方法,接着再调用服务的onStratCommand()方法。

    启动组件数据可以通过onStartCommand()方法的意图参数传递给服务。(这里可以类之前的启动活动传递数据进行理解,只不过开启的服务不需要像活动那样获取Intent对象,而是通过onStartCommand中的参数直接使用)。

    服务开始运行后,直到其他组件(活动或服务)调用stopService()方法,或者当前服务自己调用stopSelf()方法,服务销毁调会用onDestory(),可以在这个方法中释放一些资源。

  • 有效生命周期循环
    服务的有效生命周期循环发生在onStartCommand()调用与onDestory()调用之间。组件多次启动会重复调用onStartCommand()

三个方法

  • onCreate:第一次创建服务的时候系统调用次方法,在调用onStarCommand()或onBind()方法之前调用(onBind方法是绑定类型服务的)。服务运行后,不再调用。

  • onStartCommand:启动组件通过调用startService()请求启动服务时,如果是第一次启动先调用onCreate()再调用此方法,不是第一次的话系统将直接调用此方法。

  • onDestroy:当服务不在使用,即将被销毁时,系统将调用该方法。服务应该实现该方法来清理所占有的资源。

2.3 实例

1.创建服务
创建一个服务类MyService,他需要继承Service父类。

public class MyService extends Service {
    private static String TAG="Myservice";
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Log.v(TAG,"调用了onCreate");
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.v(TAG,"调用了onStartCommand....statId="+startId);
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onDestroy() {
        Log.v(TAG,"调用了onDestroy");
        super.onDestroy();
    }
}

2.注册服务类
上文中提及到在AndroidManifest.xml中的注册代码。书写位置应和</activity/>是并列关系。在这里再进行一次展示。

<application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        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"
            android:enabled="true"
            android:exported="true"></service>

</application>

3.启动服务

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //绑定按钮控件
        Button btnStart=findViewById(R.id.button_start);
        Button btnStop =findViewById(R.id.button_stop);
        btnStart.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //通过Intent启动服务
                Intent intent =new Intent(MainActivity.this,MyService.class);
                startService(intent);
            }
        });
        btnStop.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //通过Intent停止服务
                Intent intent =new Intent(MainActivity.this,MyService.class);
                stopService(intent);
            }
        });
    }
}

3 绑定类型服务

3.1 绑定服务概述

当应用组件(活动或服务)通过调用bindService()绑定到服务时,服务即处于"绑定"状态。绑定过服务提供了一个C/S(客户端/服务器)接口,通过该接口组件能够与服务进行交互、发送请求、返回数据等,甚至可以通过进程间的通信(IPC)实现跨进程操作。相对于启动类型服务,绑定类型服务是高耦合等。多个组件可以通时绑定到该服务,单全部绑定取消后,该服务会被销毁。

3.2 绑定服务生命周期

在这里插入图片描述
绑定服务的生命周期如图所示,可以从两个不同的角度进行分析。即两个嵌套循环和四个方法。

两个嵌套循环

  • 整个生命周期循环
    服务的整个生命周期都发生在onCreat()和onDestroy()调用之间,客户端通过调用bindService()方法创建服务,然后系统调用服务的onCreate()方法,再接着调用onBind()方法。所有得而绑定全部解绑后,然后系统会调用onUnbind()方法,再调用onDestroy()方法释放资源。

  • 有效生命周期循环
    服务的有效生命周期循环发生在onBind()开始到onUnbind()结束。

四个方法

  • onCreate():绑定成功成功时调用该方法,在调用onBind()之前调用该方法。服务运行后,不再调用此方法。

  • onBind():这是绑定服务至关重要的方法。绑定服务成功,系统会调用该方法,该方法必须返回IBiner接口类型对象,用于客户对象与服务器之间的通信

  • onUnbind():所有客户端通过调用unbindService()解除绑定,系统调用该方法。

  • onDestroy():所哟客户端解除帮锁定,形同调用onUnbind()方法后调用该方法。服务应该实现该方法来清理所占有的资源。

3.3 实例

1.创建服务

public class BinderService extends Service {
    private static String TAG="BinderService";
    //Binder对象
    private final IBinder mBinder =new LoaclBinder();
    public class LoaclBinder extends Binder{
        BinderService getService(){
            return  BinderService.this;
        }
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Log.v(TAG,"调用了onCreate");
    }

    @Override
    public IBinder onBind(Intent intent) {
        Log.v(TAG,"调用了onBind");
        return mBinder;
    }

    @Override
    public boolean onUnbind(Intent intent) {
        Log.v(TAG,"调用了onUnbind");
        return super.onUnbind(intent);
    }

    @Override
    public void onDestroy() {
        Log.v(TAG,"调用了onDestroy");
        super.onDestroy();
    }

    public Date getDate(){
        Date date =new Date();
        return date;
    }
}

2.注册服务
可以类比上个启动类型服务的注册代码,在这里就不在赘述了。

3.客户端代码

public class MainActivity extends AppCompatActivity {
    //绑定的服务
    BinderService mService;
    //绑定状态
    boolean mBound=false;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button btnCall=findViewById(R.id.button_call);
        btnCall.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if(mBound){
                    //调用BinderService中的方法
                    Date date= mService.getDate();
                    Toast.makeText(MainActivity.this, "Date:"+date.toString(), Toast.LENGTH_SHORT).show();
                }
            }
        });
    }

    @Override
    protected void onStart() {
        super.onStart();
        //绑定BinderService
        Intent intent =new Intent(this,BinderService.class);
        bindService(intent,mConnection, Context.BIND_AUTO_CREATE);
    }

    @Override
    protected void onStop() {
        super.onStop();
        //解除绑定BinderService
        if(mBound){
            unbindService(mConnection);
            mBound=false;
        }
    }

    private ServiceConnection mConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            //强制类型转换IBinder->BinderService
            BinderService.LoaclBinder binder =(BinderService.LoaclBinder)iBinder;
            mService=binder.getService();
            mBound=true;
        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {
            mBound=false;
        }
    };
}

4 IntentService

由于服务是在主线程进行中,所以要进行耗费CPU或者阻塞的操作,他应该产生新的线程,在新的线程里进行这些工作。开发人员可以在服务中实现多线程,但是这样会增加编程的困难,为此谷歌提供了特殊的服务类IntentService

4.1 IntentService优势

  • 创建默认的工作线程,用于在主线之后程执传递给onStartCommand()所有意图。
  • 创建工作队列,用于将意图逐一传递给onHandleIntent()方法来实现,这样就不用担心多线程问题了。
  • 处理完成所有的启动请求后自动停止服务,不需要回调stopSelf()方法。
  • 提供了onBind()的默认实现,即返回null
  • 提供了onStartCommand()的默认实现,可将意图依次发送到工作队列和onHandleIntent

4.1 IntentService实例

public class MyIntentService extends IntentService{
	private static String TAG="MyIntentService";
	public MyIntentService{
		super("MyIntentService");
	}
	@override
	protected void onHandleIntent(Intent intent){
		Log.v(TAG,"调用 onHandleIntent...");
		synchronized(this){
			try{
				wait(5*1000);
			}catch(Exception e){
			}
		}
	}
}

上述MyIntentService服务继承了IntentService只需要重写构造方法和 onHandleIntent方法。由于IntentService创建默认的工作线程,因此当前线程不是主线程,所以等待5秒不会阻塞主线程,不会出现ANR问题。另外IntentService不需要调用stopSelf()方法停止服务,处理完所有的启动请求后自动停止服务。

文章关于活动的创建,布局代码,控件绑定没有指出,可以先找到相关视频进行基础学习
文章还会持续更新。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值