【android】第一行代码和Google开发文档-第十章 服务 Service(附源码)

Service 服务

线程Thread和服务Service

Server
首先抛出一个问题,服务和线程之间的异同?
在官方文档的解析如下:

A service is simply a component that can run in the background, even when the user is not interacting with your application, so you should create a service only if that is what you need.

If you must perform work outside of your main thread, but only while the user is interacting with your application, you should instead create a new thread in the context of another application component. For example, if you want to play some music, but only while your activity is running, you might create a thread in onCreate(), start running it in onStart(), and stop it in onStop(). Also consider using thread pools and executors from the java.util.concurrent package or Kotlin coroutines instead of the traditional Thread class. See the Threading on Android document for more information about moving execution to background threads.

Remember that if you do use a service, it still runs in your application’s main thread by default, so you should still create a new thread within the service if it performs intensive or blocking operations.

简单的说:

  • 服务是不需要跟用户进行交互的。
  • 线程在用户需要短暂进行交互的情况下进行使用,官方推荐使用新的线程方式例如concurrent和kotlin的方法构建。
  • 服务是默认基于主线程的,可以考虑创建一个线程维系高密度和容易进行操作阻碍的服务。

Manifest中记得申明Service

<manifest ... >
  ...
  <application ... >
      <service android:name=".ExampleService" />
      ...
  </application>
</manifest>
  • 设置属性,该服务仅本app可用!(一般情况下的一些服务基本上都是不对外共享的)

You can ensure that your service is available to only your app by including the android:exported attribute and setting it to false.

  • 确保安全性,使用服务启动的时候应该explicit明确性强的方式启动,不需要过滤器filter进行筛选。

To ensure that your app is secure, always use an explicit intent when starting a Service and don’t declare intent filters for your services.

创建一个服务

创建一个class必须继承Service才能实现服务的功能,
在这里主要是以下的几个方法:
onStartCommandonBind(这个主要是根activity这些component进行交互的方法)
示例的代码如下:


package com.chris.servicepractice;

import android.app.Activity;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.util.Log;
import android.widget.Toast;

public class MyService extends Service {
    private static final String TAG = "MyService";
    private MyBinder myBinder = new MyBinder();
    public MyService() {
    }
    //这个是必须实现的
    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
//        throw new UnsupportedOperationException("Not yet implemented");
        return myBinder;
    }
    //服务初次构建,只会启动一起,即构建服务的时候
    @Override
    public void onCreate() {
        Log.d(TAG, "onCreate");
        super.onCreate();

    }
    //正式启动服务,每一次启动都会调用
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.d(TAG, "onStartCommand");
        Toast.makeText(this, "startCommand", Toast.LENGTH_SHORT).show();
        return super.onStartCommand(intent, flags, startId);
    }
    //服务消亡
    @Override
    public void onDestroy() {
        Log.d(TAG, "onDestroy");
        Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show();
        super.onDestroy();
    }
    //和Activity进行交互的一个Binder,在这里可以自己编写相关的操作
    public class  MyBinder extends Binder{
        void startDownload(){
            Log.d(TAG, "startDownload");

        }
    }

}

在Aactivity调用;

 //启动服务
                Intent startServiceIntent = new Intent(this,MyService.class);
                startService(startServiceIntent);

If the service doesn’t also provide binding, the intent that is delivered with startService() is the only mode of communication between the application component and the service.

官方文档原话大意:如果没有实现onBind那么就这有这个on StartCommand是Activity唯一和Service交互的渠道

  • 此外,启动服务的多个请求会导致对服务的onStartCommand()的多个相应调用。但是,停止服务只需要一个停止服务的请求(使用stopSelf()或stopService())。

关闭服务

关闭的方法主要是自己关闭和component关闭;

  • stopSelf(StartId)这里的startId是正式调用中的参数,为了避免终其他正在调用该服务时被误停止,所以用一个id进行管理维系;
  • stopService 活动Activity等组件进行关闭。

在进行高效的资源管理下,最好记得服务在不用的时候进行stop,避免浪费!

切记切记:服务是默认在主线程进行的,大消耗的情况下最好再开一个线程,要不容易出现ANR无响应的情况

The Service class is the base class for all services. When you extend this class, it’s important to create a new thread in which the service can complete all of its work; the service uses your application’s main thread by default, which can slow the performance of any activity that your application is running.

组件捆绑和解绑服务

bind和unbind和前面开启关闭服务是大不相同的。

  • bindService绑定服务
    api源码如下:
public boolean bindService(Intent service, ServiceConnection conn, int flags) {
        throw new RuntimeException("Stub!");
    }
  1. 构建一个已实现Ibinder的对象。也可直接基础Binder
  2. 绑定
  3. 调用该对象才可进行交互,注意⚠️ 直接绑定是不会触发到onStartCommand
  • unbindServic解绑服务
    api源码

    public void unbindService(ServiceConnection conn) {
        throw new RuntimeException("Stub!");
    }

解绑捆绑都绕不开的

ServiceConnection和服务进行连接的对象

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package android.content;

import android.os.IBinder;

public interface ServiceConnection {
    void onServiceConnected(ComponentName var1, IBinder var2);

    void onServiceDisconnected(ComponentName var1);

    default void onBindingDied(ComponentName name) {
        throw new RuntimeException("Stub!");
    }

    default void onNullBinding(ComponentName name) {
        throw new RuntimeException("Stub!");
    }
}

Notification

官方文档推荐

When a service is running, it can notify the user of events using Toast Notifications or Status Bar Notifications.

使用notfication进行交互,利于用户清晰明白服务状态!
可以参考以下的代码,避坑


   //NOTIFICATION 
       NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
        //添加上一个前台服务的通知栏
        Intent notificationIntent = new Intent(this, MainActivity.class);
        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
                notificationIntent, FLAG_UPDATE_CURRENT);
        Notification notification = null;
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
            NotificationChannel channel = new NotificationChannel("notificationID", "chris", NotificationManager.IMPORTANCE_HIGH);
            manager.createNotificationChannel(channel);
            notification = new Notification.Builder(this,"notificationID")
                    .setContentText("MyService")
                    .setContentTitle("This is Content Title")
                    .setWhen(System.currentTimeMillis())
                    .setSmallIcon(R.mipmap.ic_launcher)
                    .setContentIntent(pendingIntent)
                    .build();
        }


        startForeground(1, notification);

生命周期

多说无益,附上代码吧。

示例代码

视图xml:

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <Button
        android:id="@+id/start_service"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Start Service" />

    <Button
        android:id="@+id/stop_service"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Stop Service" />
    <Button
        android:id="@+id/bind_service"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Bind Service" />

    <Button
        android:id="@+id/unbind_service"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Unbind Service"
        />

</LinearLayout>

MainActivity

package com.chris.servicepractice;

import androidx.appcompat.app.AppCompatActivity;

import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.view.View;
import android.widget.Button;

/**
 * 在这里主要是简单地了解和使用Service这个四大组件之一
 * 基本是基于郭霖大神写的书籍以及google开发文档中关于Service的描述
 */
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    private Button startService;
    private Button stopService;
    private Button bindService;
    private Button unbindService;


    private MyService.MyBinder myBinder;
    //由于Activity要和Service进行相关的交互,这样才能通过活动得知服务的操作
    private ServiceConnection serviceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
                //服务连接上之后的操作
                myBinder = (MyService.MyBinder) iBinder;
                myBinder.startDownload();//模拟方法
        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {

        }
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        startService = findViewById(R.id.start_service);
        stopService = findViewById(R.id.stop_service);
        bindService = findViewById(R.id.bind_service);
        unbindService = findViewById(R.id.unbind_service);
        startService.setOnClickListener(this);
        stopService.setOnClickListener(this);
        bindService.setOnClickListener(this);
        unbindService.setOnClickListener(this);
    }

    @Override
    public void onClick(View view) {
        switch(view.getId()) {
            case R.id.start_service:
                //启动服务
                Intent startServiceIntent = new Intent(this,MyService.class);
                startService(startServiceIntent);
                break;
            case R.id.stop_service:
                //关闭服务
                Intent stopServiceIntent = new Intent(this,MyService.class);
                stopService(stopServiceIntent);
                break;
            case R.id.bind_service:
                Intent bindServiceIntent = new Intent(this,MyService.class);
                bindService(bindServiceIntent,serviceConnection,BIND_AUTO_CREATE);//最后一个参数具体的意义,我还不是很清楚
                break;
            case R.id.unbind_service:
                unbindService(serviceConnection);
                break;
        }
    }
}

MyService 服务类

package com.chris.servicepractice;

import static android.app.PendingIntent.FLAG_UPDATE_CURRENT;
import static java.lang.Thread.sleep;

import android.app.Activity;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.Binder;
import android.os.Build;
import android.os.IBinder;
import android.util.Log;
import android.widget.Toast;

import androidx.core.app.NotificationCompat;

public class MyService extends Service {
    private static final String TAG = "MyService";
    private MyBinder myBinder = new MyBinder();
    public MyService() {
    }
    //这个是必须实现的
    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
//        throw new UnsupportedOperationException("Not yet implemented");
        return myBinder;
    }
    //服务初次构建,只会启动一起,即构建服务的时候
    @Override
    public void onCreate() {
        super.onCreate();
        Log.d(TAG, "onCreate");
        //NOTIFICATION
       NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
        //添加上一个前台服务的通知栏
        Intent notificationIntent = new Intent(this, MainActivity.class);
        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
                notificationIntent, FLAG_UPDATE_CURRENT);
        Notification notification = null;
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
            NotificationChannel channel = new NotificationChannel("notificationID", "chris", NotificationManager.IMPORTANCE_HIGH);
            manager.createNotificationChannel(channel);
            notification = new Notification.Builder(this,"notificationID")
                    .setContentText("MyService")
                    .setContentTitle("This is Content Title")
                    .setWhen(System.currentTimeMillis())
                    .setSmallIcon(R.mipmap.ic_launcher)
                    .setContentIntent(pendingIntent)
                    .build();
        }
        startForeground(1, notification);
        Log.d(TAG, "onCreate() executed");



    }
    //正式启动服务,每一次启动都会调用
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.d(TAG, "onStartCommand");
        Toast.makeText(this, "startCommand", Toast.LENGTH_SHORT).show();
        try{
            sleep(2000);
//            stopSelf(startId);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return super.onStartCommand(intent, flags, startId);
    }



    //服务消亡
    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.d(TAG, "onDestroy");
        stopForeground(true);//删除通知!
        Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show();
    }
    //和Activity进行交互的一个Binder,在这里可以自己编写相关的操作
    public class  MyBinder extends Binder{
        void startDownload(){
            Log.d(TAG, "startDownload");

        }
    }

}

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值