Android 四大组件 service

前言

在Android系统中,Service 是一个用来执行长时间运行的操作而不提供用户界面的应用组件。它可以在后台执行任务,即使用户切换到其他应用也不会被中断。

Service 在Android中主要用于在后台执行长时间运行的任务,例如播放音乐、执行文件下载、处理网络请求等。尽管Service运行在后台,但它仍然属于应用程序的一部分,因此不会影响用户对前台应用的交互。

Service的类型

在Android中,Service 可以分为三种类型:

前台Service

前台Service 是用户可见的服务,它会在系统的通知区域显示一个通知,表示正在运行的服务。这种类型的Service被视为用户当前活跃的一部分,因此系统不太可能在内存不足时终止它。前台Service 常用于音乐播放或GPS导航等需要用户明确知道并持续运行的功能。

后台Service

后台Service 在用户不可见的情况下执行操作,通常用于执行不需要与用户交互的任务。但从Android Oreo(API 级别 26)开始,后台服务的使用受到了严格限制,以减少对系统性能的影响和提升电池寿命。

绑定Service

绑定Service 是一种允许应用组件(如Activity)绑定到Service并与之交互的服务。组件可以发送请求、接收响应,甚至进行进程间通信(IPC)。绑定的Service 只在其他应用组件与其绑定时运行,不会无限期运行。

Service的实现

实现Service 主要涉及以下几个步骤:

  • 定义Service: 在Java或Kotlin文件中扩展Service基类,并重写其生命周期方法如onCreate(), onStartCommand(), onBind(), 和onDestroy()

  • 配置Manifest: 在AndroidManifest.xml中声明Service,并设置适当的权限和属性。

  • 启动和绑定Service: 通过startService(Intent)方法启动服务,或者使用bindService(Intent, ServiceConnection, int)绑定服务。前者适用于执行单一操作或执行不返回结果的操作,后者适用于与服务进行交互。

如下是一个例子:创建一个服务,允许用户在后台播放音乐,即使他们离开了应用,音乐仍然可以继续播放:

public class MusicService extends Service {
    private MediaPlayer mediaPlayer;

    @Override
    public void onCreate() {
        super.onCreate();
        // 初始化 MediaPlayer 对象
        mediaPlayer = MediaPlayer.create(this, R.raw.sample_music);
        mediaPlayer.setLooping(true); // 设置音乐循环播放
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        mediaPlayer.start(); // 开始播放音乐
        return START_STICKY; // 系统如果终止服务后,会尝试重新创建服务并调用 onStartCommand()
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        if (mediaPlayer != null) {
            mediaPlayer.stop();
            mediaPlayer.release();
        }
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null; // 不提供绑定功能
    }
}
<service android:name=".MusicService" />
public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Button startButton = findViewById(R.id.startButton);
        Button stopButton = findViewById(R.id.stopButton);

        startButton.setOnClickListener(v -> startService(new Intent(this, MusicService.class)));
        stopButton.setOnClickListener(v -> stopService(new Intent(this, MusicService.class)));
    }
}

管理Service的生命周期

主要包括:

  • onCreate(): 当服务第一次创建时调用。
  • onStartCommand(): 每次通过 startService() 方法启动服务时调用。
  • onBind(): 当其他组件想要与服务绑定时调用。
  • onUnbind(): 当所有组件都与服务解绑时调用。
  • onDestroy(): 当服务不再使用且将被销毁时调用。

与服务通信

Binder

对于在同一应用内运行的服务,可以通过定义一个 Binder 类并在服务中返回这个 Binder 的实例,从而实现与服务的通信。客户端(如 Activity)可以绑定到服务并获得这个 Binder 对象,通过这个对象调用服务中的方法。

public class LocalService extends Service {
    // Binder 类的实例,用于返回给客户端
    private final IBinder binder = new LocalBinder();

    public class LocalBinder extends Binder {
        LocalService getService() {
            // 返回当前的 LocalService 实例以供客户端调用公开的方法
            return LocalService.this;
        }
    }

    @Override
    public IBinder onBind(Intent intent) {
        return binder;
    }

    // 服务中的一个方法,客户端可以调用
    public int getRandomNumber() {
        return new Random().nextInt(100);
    }
}
public class MainActivity extends AppCompatActivity {
    private LocalService localService;
    private boolean isBound = false;

    private ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName className, IBinder service) {
            LocalBinder binder = (LocalBinder) service;
            localService = binder.getService();
            isBound = true;
        }

        @Override
        public void onServiceDisconnected(ComponentName arg0) {
            isBound = false;
        }
    };

    @Override
    protected void onStart() {
        super.onStart();
        bindService(new Intent(this, LocalService.class), connection, Context.BIND_AUTO_CREATE);
    }

    @Override
    protected void onStop() {
        super.onStop();
        if (isBound) {
            unbindService(connection);
            isBound = false;
        }
    }

    public void onButtonClick(View v) {
        if (isBound) {
            // 调用服务的方法
            int num = localService.getRandomNumber();
            Toast.makeText(this, "number: " + num, Toast.LENGTH_SHORT).show();
        }
    }
}
Messager

如果服务需要与多个应用组件或其他应用进行跨进程通信,可以使用 Messenger。在这种方式a中,服务使用 Handler 接收消息,并通过 Messenger 对象响应。

public class MessengerService extends Service {
    static final int MSG_SAY_HELLO = 1;

    class IncomingHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case MSG_SAY_HELLO:
                    Toast.makeText(getApplicationContext(), "Hello!", Toast.LENGTH_SHORT).show();
                    break;
                default:
                    super.handleMessage(msg);
            }
        }
    }

    final Messenger messenger = new Messenger(new IncomingHandler());

    @Override
    public IBinder onBind(Intent intent) {
        return messenger.getBinder();
    }
}
public class ActivityMessenger extends AppCompatActivity {
    Messenger messenger = null;
    boolean isBound;

    private ServiceConnection connection = new ServiceConnection() {
        public void onServiceConnected(ComponentName className, IBinder service) {
            messenger = new Messenger(service);
            isBound = true;
        }

        public void onServiceDisconnected(ComponentName className) {
            messenger = null;
            isBound = false;
        }
    };

    public void sayHello(View v) {
        if (!isBound) return;
        Message msg = Message.obtain(null, MessengerService.MSG_SAY_HELLO, 0, 0);
        try {
            messenger.send(msg);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }
}
AIDL

AIDL(Android Interface Definition Language)是一种接口定义语言,用于让客户端和服务之间能够在不同的进程中进行通信。使用 AIDL 是处理复杂数据传输或跨应用通信的标准方式。

定义一个 AIDL 文件,这个文件描述了服务将要公开的接口

interface IRandomNumberService {
    int getRandomNumber();
}

当构建项目时,Android 构建工具会根据 AIDL 文件生成一个 Java 接口。然后可以创建一个实现这个接口的服务:

IRandomNumberService.Stub 是由 AIDL 文件自动生成的,需要实现这个 Stub 类中的方

public class RandomNumberService extends Service {
    private final IRandomNumberService.Stub binder = new IRandomNumberService.Stub() {
        public int getRandomNumber() throws RemoteException {
            return new java.util.Random().nextInt(100);
        }
    };

    @Override
    public IBinder onBind(Intent intent) {
        return binder;
    }
}

现在,任何其他应用都可以绑定到这个服务并调用 getRandomNumber 方法

public class ClientActivity extends AppCompatActivity {
    private IRandomNumberService randomNumberService;
    private boolean isBound = false;

    private ServiceConnection connection = new ServiceConnection() {
        public void onServiceConnected(ComponentName className, IBinder service) {
            randomNumberService = IRandomNumberService.Stub.asInterface(service);
            isBound = true;
        }

        public void onServiceDisconnected(ComponentName className) {
            randomNumberService = null;
            isBound = false;
        }
    };

    @Override
    protected void onStart() {
        super.onStart();
        bindService(new Intent("com.example.myapp.RandomNumberService"),
                    connection, Context.BIND_AUTO_CREATE);
    }

    @Override
    protected void onStop() {
        super.onStop();
        if (isBound) {
            unbindService(connection);
            isBound = false;
        }
    }

    public void onButtonClick() {
        if (isBound) {
            try {
                int randomNumber = randomNumberService.getRandomNumber();
                // Use the random number...
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
    }
}

上一篇:Java 实现二叉搜索树 代码


下一篇:HTML-JavaWeb