首页 > 其他分享 >Android Service

Android Service

时间:2024-09-17 15:12:48浏览次数:7  
标签:Service void private Override new Android public

Android Service

参考:https://blog.csdn.net/javazejian/article/details/52709857

1、Service简单概述

Service(服务)是一个一种可以在后台执行长时间运行操作而没有用户界面的应用组件。服务可由其他应用组件启动(如Activity),服务一旦被启动将在后台一直运行,即使启动服务的组件(Activity)已销毁也不受影响。 此外,组件可以绑定到服务,以与之进行交互,甚至是执行进程间通信 (IPC)。 例如,服务可以处理网络事务、播放音乐,执行文件 I/O 或与内容提供程序交互,而所有这一切均可在后台进行,Service基本上分为两种形式:

  • 启动状态

当应用组件(如 Activity)通过调用 startService() 启动服务时,服务即处于“启动”状态。一旦启动,服务即可在后台无限期运行,即使启动服务的组件已被销毁也不受影响,除非手动调用才能停止服务, 已启动的服务通常是执行单一操作,而且不会将结果返回给调用方。

  • 绑定状态

当应用组件通过调用 bindService() 绑定到服务时,服务即处于“绑定”状态。绑定服务提供了一个客户端-服务器接口,允许组件与服务进行交互、发送请求、获取结果,甚至是利用进程间通信 (IPC) 跨进程执行这些操作。 仅当与另一个应用组件绑定时,绑定服务才会运行。 多个组件可以同时绑定到该服务,但全部取消绑定后,该服务即会被销毁。

Service在清单文件中的声明

前面说过Service分为启动状态和绑定状态两种,但无论哪种具体的Service启动类型,都是通过继承Service基类自定义而来,也都需要在AndroidManifest.xml中声明,那么在分析这两种状态之前,我们先来了解一下Service在AndroidManifest.xml中的声明语法,其格式如下:

<service android:enabled=["true" | "false"]
    android:exported=["true" | "false"]
    android:icon="drawable resource"
    android:isolatedProcess=["true" | "false"]
    android:label="string resource"
    android:name="string"
    android:permission="string"
    android:process="string" >
    . . .
</service>12345678910
  • android:exported:代表是否能被其他应用隐式调用,其默认值是由service中有无intent-filter决定的,如果有intent-filter,默认值为true,否则为false。为false的情况下,即使有intent-filter匹配,也无法打开,即无法被其他应用隐式调用。
  • android:name:对应Service类名
  • android:permission:是权限声明
  • android:process:是否需要在单独的进程中运行,当设置为android:process=”:remote”时,代表Service在单独的进程中运行。注意“:”很重要,它的意思是指要在当前进程名称前面附加上当前的包名,所以“remote”和”:remote”不是同一个意思,前者的进程名称为:remote,而后者的进程名称为:App-packageName:remote。
  • android:isolatedProcess :设置 true 意味着,服务会在一个特殊的进程下运行,这个进程与系统其他进程分开且没有自己的权限。与其通信的唯一途径是通过服务的API(bind and start)。
  • android:enabled:是否可以被系统实例化,默认为 true因为父标签 也有 enable 属性,所以必须两个都为默认值 true 的情况下服务才会被激活,否则不会激活。

2、示例

1. 最简单的Service

让我们从最基本的Service开始:

1.1 MyService.java

public class MyService extends Service {
    private static final String TAG = "MyService";
    private Handler handler;
    private Runnable runnable;
    private int count = 0;

    @Override
    public void onCreate() {
        super.onCreate();
        // 初始化Handler和Runnable,用于每秒递增count并打印日志
        handler = new Handler(Looper.getMainLooper());
        runnable = new Runnable() {
            @Override
            public void run() {
                count++;
                Log.d(TAG, "Count: " + count);
                handler.postDelayed(this, 1000);
            }
        };
        handler.post(runnable); // 启动任务
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        return START_STICKY; // 服务在被系统杀掉后会重启
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        handler.removeCallbacks(runnable); // 停止任务
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null; // 这个简单的服务不使用绑定
    }
}

1.2 注册服务

<service android:name=".service.MyService"/>

1.3 activity

public class MainActivity extends AppCompatActivity {

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

        Intent intent = new Intent(this, MyService.class);
        startService(intent);
    }
}

1.4 解释

  • onCreate():初始化服务,启动一个每秒递增count的任务,并打印日志。
  • onStartCommand():定义服务的启动行为,这里返回START_STICKY,表示如果服务被系统杀掉,系统会尝试重新启动它。
  • onDestroy():停止任务,清理资源。
  • onBind():返回null,表示这是一个简单的、不可绑定的服务。

2. 绑定服务(Bound Service)

绑定服务允许客户端(如Activity)绑定到服务,并与之交互。绑定服务通常用于与应用组件进行长时间的交互。

2.1 MyBoundService.java

public class MyBoundService extends Service {
    private final IBinder binder = new LocalBinder();
    private int count = 0;
    private String logData = "Initial Data";

    public class LocalBinder extends Binder {
        public MyBoundService getService() {
            return MyBoundService.this;
        }
    }

    @Override
    public IBinder onBind(Intent intent) {
        return binder; // 返回IBinder实例
    }

    public String getServiceData() {
        return logData + count;
    }

    public void setServiceData(String data) {
        this.logData = data;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        // 计数任务
        new Handler(Looper.getMainLooper()).postDelayed(() -> {
            count++;
            Log.d("MyBoundService", "Count: " + count);
        }, 1000);
    }
}

2.2 注册服务

<service android:name=".service.MyBoundService" />

2.3 activity

public class MainActivity extends AppCompatActivity {

    private MyBoundService myBoundService;
    private boolean isBound = false;

    private ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName className, IBinder service) {
            MyBoundService.LocalBinder binder = (MyBoundService.LocalBinder) service;
            myBoundService = binder.getService();
            isBound = true;
            Log.d("MainActivity", "Service Connected: " + myBoundService.getServiceData());
        }

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

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

        Intent intent = new Intent(this, MyBoundService.class);
        bindService(intent, connection, Context.BIND_AUTO_CREATE);

        Handler handler = new Handler();
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                myBoundService.setServiceData("Service finish");
                Log.d("MainActivity", "Service getLogData: " + myBoundService.getServiceData());
                // 执行延时后的UI更新任务
                System.exit(0);
            }
        }, 5000); // 延时5秒


    }

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

2.4 解释

  • LocalBinder:定义一个内部类,用于客户端绑定服务时获取服务实例。
  • getServiceData():提供获取服务数据的接口。
  • setServiceData():提供设置服务数据的接口。

3.使用 Messenger 进行进程间通信(IPC)

Messenger需要结合Handler一起使用。需要一个handler,一个Messenger对象。handler最终会负责发送和接收消息。它不仅能够在后台执行任务,还能通过 Messenger 发送和接收消息,从而与客户端进行双向交互。

3.1 MyComplexService

public class MyComplexService extends Service {
    private static final String TAG = "MyComplexService";
    private final Messenger serviceMessenger = new Messenger(new IncomingHandler());
    private Messenger clientMessenger;
    private boolean isRunning = false;
    int count = 0;

    @Override
    public IBinder onBind(Intent intent) {
        return serviceMessenger.getBinder(); // 返回Messenger的Binder
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Log.d(TAG, "Service created");
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.d(TAG, "Service destroyed");
        isRunning = false; // 停止任务
    }

    private void startBackgroundTask() {
        if (isRunning) return;
        isRunning = true;

        // 后台线程开始计数任务
        new Thread(() -> {
            while (isRunning) {
                try {
                    Thread.sleep(1000);
                    count++;
                    if (clientMessenger != null) {
                        Message msg = Message.obtain(null, 0);
                        Bundle bundle = new Bundle();
                        bundle.putInt("count", count);
                        msg.setData(bundle);
                        try {
                            clientMessenger.send(msg); // 发送消息给客户端
                        } catch (RemoteException e) {
                            e.printStackTrace();
                        }
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

    // 处理客户端发送的消息
    private class IncomingHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case 1: // 客户端请求启动任务
                    startBackgroundTask();
                    break;
                case 2: // 客户端请求停止任务
                    isRunning = false;
                    stopSelf();
                    break;
                case 3: // 客户端传递自己的Messenger
                    clientMessenger = new Messenger(msg.replyTo.getBinder());
                    break;
                default:
                    super.handleMessage(msg);
            }
        }
    }
}

3.2 注册服务

<service android:name=".service.MyComplexService" />

3.3 activity

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";
    private Messenger serviceMessenger;
    private boolean isBound = false;
    private TextView textView;

    private final Messenger clientMessenger = new Messenger(new IncomingHandler());

    private final ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName className, IBinder service) {
            serviceMessenger = new Messenger(service);
            isBound = true;

            Message msg = Message.obtain(null, 3);
            msg.replyTo = clientMessenger;
            try {
                serviceMessenger.send(msg);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

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

    private class IncomingHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            int count = msg.getData().getInt("count");
            textView.setText("Count: " + count);
        }
    }

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

        Intent intent = new Intent(this, MyComplexService.class);
        bindService(intent, connection, Context.BIND_AUTO_CREATE);

        findViewById(R.id.startButton).setOnClickListener(v -> startServiceTask());
        findViewById(R.id.stopButton).setOnClickListener(v -> stopServiceTask());
    }

    private void startServiceTask() {
        if (isBound) {
            Message msg = Message.obtain(null, 1);
            try {
                serviceMessenger.send(msg);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
    }

    private void stopServiceTask() {
        if (isBound) {
            Message msg = Message.obtain(null, 2);
            try {
                serviceMessenger.send(msg);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
    }

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

3.4 解释

  • Messenger:用于在进程间传递消息。
  • IncomingHandler:处理来自服务的消息。

4. 使用AIDL进行跨进程通信(复杂)

允许多个客户端通过消息通信与服务进行复杂交互。在客户端(如Activity)中,通过ServiceConnection来绑定服务,并使用AIDL接口与服务通信。

4.1 MyBinderService.java

public class MyBinderService extends Service {
    private boolean isRunning = false;
    private int count = 0;

    private final IMyAidlInterface.Stub mBinder = new IMyAidlInterface.Stub() {
        @Override
        public void startTask() throws RemoteException {
            startBackgroundTask();
        }

        @Override
        public void stopTask() throws RemoteException {
            stopBackgroundTask();
            stopSelf();
        }

        @Override
        public int getCount() throws RemoteException {
            return count;
        }
    };

    @Override
    public IBinder onBind(Intent intent) {
        return mBinder; // 返回AIDL接口的Binder实例
    }

    private void startBackgroundTask() {
        if (isRunning) return;
        isRunning = true;

        new Thread(() -> {
            while (isRunning) {
                try {
                    Thread.sleep(1000);
                    count++;
                    Log.d("MyBinderService", "Count: " + count);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

    private void stopBackgroundTask() {
        isRunning = false;
    }
}

4.2 注册服务

 <service
            android:name=".service.MyBinderService"
            android:exported="true"
            android:permission="android.permission.BIND_AUTO_CREATE" />

4.3 activity

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";
    private IMyAidlInterface mService;
    private boolean isBound = false;
    private TextView textView;

    private ServiceConnection mConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName className, IBinder service) {
            mService = IMyAidlInterface.Stub.asInterface(service);
            isBound = true;
        }

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

    private Handler handler;
    private Runnable runnable;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        textView = findViewById(R.id.textView);

        Intent intent = new Intent(this, MyBinderService.class);
        bindService(intent, mConnection, Context.BIND_AUTO_CREATE);

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

        startButton.setOnClickListener(v -> startServiceTask());
        stopButton.setOnClickListener(v -> stopServiceTask());

         handler = new Handler(Looper.getMainLooper());
         runnable = new Runnable() {
            @Override
            public void run() {
                int count = 0;
                try {
                    count = mService.getCount();
                    Log.d(TAG, "run: count-->"+count);
                } catch (Exception e) {
                   e.printStackTrace();
                }
                textView.setText("Count: " + count);
                handler.postDelayed(this, 1000);
            }
        };

    }

    private void startServiceTask() {
        if (isBound) {
            Log.d(TAG, "Start button clicked");
            try {
                mService.startTask();
                handler.removeCallbacks(runnable);
                handler.post(runnable);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
    }

    private void stopServiceTask() {
        if (isBound) {
            Log.d(TAG, "Stop button clicked");
            try {
                mService.stopTask();
                handler.removeCallbacks(runnable);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
    }


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

4.4 解释

  • AIDL接口:IMyAidlInterface.Stub是AIDL接口的具体实现。它定义了可以由客户端调用的方法,如startTask()stopTask()getCount()

  • 服务在被绑定后,客户端可以通过这个接口与服务通信,执行跨进程任务。

  • ServiceConnection:用于管理客户端与服务的连接状态。

  • startServiceTask()stopServiceTask():通过AIDL接口启动和停止服务任务。

总结

  1. 简单的服务:适用于后台执行不需要与客户端交互的任务。
  2. 绑定服务:适用于需要与客户端交互的任务,客户端可以通过绑定服务获取数据或执行操作。
  3. message:适合于需要在服务和客户端之间传递消息的场景。
  4. AIDL服务:适用于跨进程通信场景,允许客户端与服务进行复杂的数据交互和任务管理。

标签:Service,void,private,Override,new,Android,public
From: https://www.cnblogs.com/20lxj666/p/18400574

相关文章

  • 基于Android的健身计划管理系统 基于Android的健身管理平台(程序+LW+PPT+部署)
    ......
  • Android使用LiquidFun物理引擎实现果冻碰撞效果
    一、效果展示Android使用LiquidFun物理引擎实现果冻碰撞效果二、LiquidFun物理引擎简介LiquidFun是一个由Google开发并开源的2D物理模拟库,它基于Box2D物理引擎,并扩展了流体模拟的功能。流体动力学模拟:LiquidFun提供了强大的流体动力学系统,可以模拟流体的行为,包括液体......
  • Android 环形
    关于“Android环形”,这个描述可能指的是在Android应用开发中使用的环形布局或者控件,比如环形进度条、环形菜单等。这里我将给出一个简单的例子来创建一个环形进度条(CircularProgressBar)和一个环形菜单(CircularMenu)的例子。环形进度条在Android中,可以通过自定义ProgressBar来实......
  • Android HandlerThread Post后延迟7秒才执行的原因及解决方案|如何提高Android后台线程
    在Android开发中,HandlerThread是用于处理后台线程任务的常见工具。然而,有时我们会遇到这样的问题:当任务通过HandlerThread的post方法发送后,任务的执行时间会出现明显的延迟,比如7秒的延迟才执行任务。本文将深入分析这种问题的成因,探讨可能的影响因素,并提供多种优化方案,帮助开发者解......
  • AndroidStudio - - - 点击头像更换头像_菜单选择_相机拍照与相册获取
    1.逻辑代码1.1MainActivity类packagecom.example.myapplication;importandroid.Manifest;importandroid.app.Activity;importandroid.app.AlertDialog;importandroid.content.DialogInterface;importandroid.content.Intent;importandroid.content.pm.PackageM......
  • android 双重吸顶
    双重吸顶效果通常是指在一个页面中有两层头部区域,在用户滚动列表时,这两层头部会根据不同的条件分别吸顶显示。这种效果常见于具有多层级导航的应用中,比如在顶部有一个主要的导航栏,在下方有一个次要的导航栏或者标题栏。实现双重吸顶效果,可以利用Android中的CoordinatorLayout配合A......
  • Android中的单例模式
    在Android开发中,单例模式(SingletonPattern)是一种常用的设计模式,它确保一个类只有一个实例,并提供一个全局访问点来获取这个实例。单例模式在需要控制资源访问、管理共享资源或配置信息的场景下特别有用。在Android中,实现单例模式的方法有多种,但主要思想是一致的:私有化构造函数,......
  • Android SDK和NDK的区别
    AndroidSDK(SoftwareDevelopmentKit,软件开发工具包)和NDK(NativeDevelopmentKit,本地开发工具包)在Android应用开发中扮演着不同的角色,它们各自具有独特的功能和优势。一、定义与功能AndroidSDKAndroidSDK是由Google提供的一套开发工具,用于开发基于Android操作系统的应用......
  • Android中如何处理运行时权限?
    在Android中,处理运行时权限是开发过程中一个至关重要的环节,它自Android6.0(API级别23)引入,旨在提高用户隐私保护和应用的透明度。以下将详细阐述Android中处理运行时权限的方法、步骤、注意事项以及相关的最佳实践。一、运行时权限概述Android运行时权限(RuntimePermissions)允......
  • Android中的Intent的作用
    在深入探讨Android中的Intent及其作用之前,我们首先需要理解Android作为一个开源的移动操作系统,其核心设计哲学之一是鼓励组件之间的解耦与重用。这种设计使得开发者能够构建出灵活、可扩展且模块化的应用程序。而Intent,正是这一设计理念中至关重要的一环,它充当了不同组件之间通......