Android在framework层添加自定义服务的流程

news2025/2/24 4:13:29

环境说明

  • ubuntu16.04
  • android4.1
  • java version “1.6.0_45”
  • GNU Make 3.81
  • gcc version 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.12)

可能有人会问,现在都2024了怎么还在用android4版本,早都过时了。确实,现在最新的都是Android13、Android14了,不过我这里主要是用于demo的演示学习使用,只要整个的流程掌握了,哪个版本的流程都是大同小异;再一个就拿Android13来说,源码100G多非常庞大,代码clone、源码编译都是很慢的,而Android4.1源码才4G多,编译运行就快多了,省时省力。

编写AIDL文件

如果不了解aidl,建议先看看:android AIDL使用demo
仿照系统中现有服务的编写方式,新增服务需要编写aidl接口(也就是提供什么服务),在frameworks/base/core/java/android/helloservice/新建aidl文件,
在这里插入图片描述
ICallBack.aidl内容如下

package android.helloservice;
interface ICallBack {
    void onReceive(String serverMsg);
}

IHelloService.aidl内容如下

package android.helloservice;
import android.helloservice.ICallBack;
interface IHelloService {
     String getHello(String send);
     void registerCallback(ICallBack callback);
     void unRegisterCallback(ICallBack callback);
}

修改frameworks/base/Android.mk,在LOCAL_SRC_FILES变量中加入新增的aidl文件

## READ ME: ########################################################
##
## When updating this list of aidl files, consider if that aidl is
## part of the SDK API.  If it is, also add it to the list below that
## is preprocessed and distributed with the SDK.  This list should
## not contain any aidl files for parcelables, but the one below should
## if you intend for 3rd parties to be able to send those objects
## across process boundaries.
##
## READ ME: ########################################################
LOCAL_SRC_FILES += \
	core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl \
	core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl \
	core/java/com/android/internal/widget/IRemoteViewsFactory.aidl \
	core/java/com/android/internal/widget/IRemoteViewsAdapterConnection.aidl \
	//省略部分
	core/java/android/helloservice/ICallBack.aidl \
	core/java/android/helloservice/IHelloService.aidl \

执行mmm frameworks/base单编,编译成功之后会在out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/android/helloservice/生成如下文件在这里插入图片描述
IHelloService.java内容(androidstudio生成,aosp生成的代码紧凑不方便阅读)

/*
 * This file is auto-generated.  DO NOT MODIFY.
 */
package android.helloservice;
public interface IHelloService extends android.os.IInterface
{
  /** Default implementation for IHelloService. */
  public static class Default implements android.helloservice.IHelloService
  {
    @Override public java.lang.String getHello(java.lang.String send) throws android.os.RemoteException
    {
      return null;
    }
    @Override public void registerCallback(android.helloservice.ICallBack callback) throws android.os.RemoteException
    {
    }
    @Override public void unRegisterCallback(android.helloservice.ICallBack callback) throws android.os.RemoteException
    {
    }
    @Override
    public android.os.IBinder asBinder() {
      return null;
    }
  }
  /** Local-side IPC implementation stub class. */
  public static abstract class Stub extends android.os.Binder implements android.helloservice.IHelloService
  {
    /** Construct the stub at attach it to the interface. */
    public Stub()
    {
      this.attachInterface(this, DESCRIPTOR);
    }
    /**
     * Cast an IBinder object into an android.helloservice.IHelloService interface,
     * generating a proxy if needed.
     */
    public static android.helloservice.IHelloService asInterface(android.os.IBinder obj)
    {
      if ((obj==null)) {
        return null;
      }
      android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
      if (((iin!=null)&&(iin instanceof android.helloservice.IHelloService))) {
        return ((android.helloservice.IHelloService)iin);
      }
      return new android.helloservice.IHelloService.Stub.Proxy(obj);
    }
    @Override public android.os.IBinder asBinder()
    {
      return this;
    }
    @Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
    {
      java.lang.String descriptor = DESCRIPTOR;
      if (code >= android.os.IBinder.FIRST_CALL_TRANSACTION && code <= android.os.IBinder.LAST_CALL_TRANSACTION) {
        data.enforceInterface(descriptor);
      }
      switch (code)
      {
        case INTERFACE_TRANSACTION:
        {
          reply.writeString(descriptor);
          return true;
        }
      }
      switch (code)
      {
        case TRANSACTION_getHello:
        {
          java.lang.String _arg0;
          _arg0 = data.readString();
          java.lang.String _result = this.getHello(_arg0);
          reply.writeNoException();
          reply.writeString(_result);
          break;
        }
        case TRANSACTION_registerCallback:
        {
          android.helloservice.ICallBack _arg0;
          _arg0 = android.helloservice.ICallBack.Stub.asInterface(data.readStrongBinder());
          this.registerCallback(_arg0);
          reply.writeNoException();
          break;
        }
        case TRANSACTION_unRegisterCallback:
        {
          android.helloservice.ICallBack _arg0;
          _arg0 = android.helloservice.ICallBack.Stub.asInterface(data.readStrongBinder());
          this.unRegisterCallback(_arg0);
          reply.writeNoException();
          break;
        }
        default:
        {
          return super.onTransact(code, data, reply, flags);
        }
      }
      return true;
    }
    private static class Proxy implements android.helloservice.IHelloService
    {
      private android.os.IBinder mRemote;
      Proxy(android.os.IBinder remote)
      {
        mRemote = remote;
      }
      @Override public android.os.IBinder asBinder()
      {
        return mRemote;
      }
      public java.lang.String getInterfaceDescriptor()
      {
        return DESCRIPTOR;
      }
      @Override public java.lang.String getHello(java.lang.String send) throws android.os.RemoteException
      {
        android.os.Parcel _data = android.os.Parcel.obtain();
        android.os.Parcel _reply = android.os.Parcel.obtain();
        java.lang.String _result;
        try {
          _data.writeInterfaceToken(DESCRIPTOR);
          _data.writeString(send);
          boolean _status = mRemote.transact(Stub.TRANSACTION_getHello, _data, _reply, 0);
          _reply.readException();
          _result = _reply.readString();
        }
        finally {
          _reply.recycle();
          _data.recycle();
        }
        return _result;
      }
      @Override public void registerCallback(android.helloservice.ICallBack callback) throws android.os.RemoteException
      {
        android.os.Parcel _data = android.os.Parcel.obtain();
        android.os.Parcel _reply = android.os.Parcel.obtain();
        try {
          _data.writeInterfaceToken(DESCRIPTOR);
          _data.writeStrongInterface(callback);
          boolean _status = mRemote.transact(Stub.TRANSACTION_registerCallback, _data, _reply, 0);
          _reply.readException();
        }
        finally {
          _reply.recycle();
          _data.recycle();
        }
      }
      @Override public void unRegisterCallback(android.helloservice.ICallBack callback) throws android.os.RemoteException
      {
        android.os.Parcel _data = android.os.Parcel.obtain();
        android.os.Parcel _reply = android.os.Parcel.obtain();
        try {
          _data.writeInterfaceToken(DESCRIPTOR);
          _data.writeStrongInterface(callback);
          boolean _status = mRemote.transact(Stub.TRANSACTION_unRegisterCallback, _data, _reply, 0);
          _reply.readException();
        }
        finally {
          _reply.recycle();
          _data.recycle();
        }
      }
    }
    static final int TRANSACTION_getHello = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
    static final int TRANSACTION_registerCallback = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
    static final int TRANSACTION_unRegisterCallback = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2);
  }
  public static final java.lang.String DESCRIPTOR = "android.helloservice.IHelloService";
  public java.lang.String getHello(java.lang.String send) throws android.os.RemoteException;
  public void registerCallback(android.helloservice.ICallBack callback) throws android.os.RemoteException;
  public void unRegisterCallback(android.helloservice.ICallBack callback) throws android.os.RemoteException;
}

ICallBack.java内容(androidstudio生成)

/*
 * This file is auto-generated.  DO NOT MODIFY.
 */
package android.helloservice;
public interface ICallBack extends android.os.IInterface
{
  /** Default implementation for ICallBack. */
  public static class Default implements android.helloservice.ICallBack
  {
    @Override public void onReceive(java.lang.String serverMsg) throws android.os.RemoteException
    {
    }
    @Override
    public android.os.IBinder asBinder() {
      return null;
    }
  }
  /** Local-side IPC implementation stub class. */
  public static abstract class Stub extends android.os.Binder implements android.helloservice.ICallBack
  {
    /** Construct the stub at attach it to the interface. */
    public Stub()
    {
      this.attachInterface(this, DESCRIPTOR);
    }
    /**
     * Cast an IBinder object into an android.helloservice.ICallBack interface,
     * generating a proxy if needed.
     */
    public static android.helloservice.ICallBack asInterface(android.os.IBinder obj)
    {
      if ((obj==null)) {
        return null;
      }
      android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
      if (((iin!=null)&&(iin instanceof android.helloservice.ICallBack))) {
        return ((android.helloservice.ICallBack)iin);
      }
      return new android.helloservice.ICallBack.Stub.Proxy(obj);
    }
    @Override public android.os.IBinder asBinder()
    {
      return this;
    }
    @Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
    {
      java.lang.String descriptor = DESCRIPTOR;
      if (code >= android.os.IBinder.FIRST_CALL_TRANSACTION && code <= android.os.IBinder.LAST_CALL_TRANSACTION) {
        data.enforceInterface(descriptor);
      }
      switch (code)
      {
        case INTERFACE_TRANSACTION:
        {
          reply.writeString(descriptor);
          return true;
        }
      }
      switch (code)
      {
        case TRANSACTION_onReceive:
        {
          java.lang.String _arg0;
          _arg0 = data.readString();
          this.onReceive(_arg0);
          reply.writeNoException();
          break;
        }
        default:
        {
          return super.onTransact(code, data, reply, flags);
        }
      }
      return true;
    }
    private static class Proxy implements android.helloservice.ICallBack
    {
      private android.os.IBinder mRemote;
      Proxy(android.os.IBinder remote)
      {
        mRemote = remote;
      }
      @Override public android.os.IBinder asBinder()
      {
        return mRemote;
      }
      public java.lang.String getInterfaceDescriptor()
      {
        return DESCRIPTOR;
      }
      @Override public void onReceive(java.lang.String serverMsg) throws android.os.RemoteException
      {
        android.os.Parcel _data = android.os.Parcel.obtain();
        android.os.Parcel _reply = android.os.Parcel.obtain();
        try {
          _data.writeInterfaceToken(DESCRIPTOR);
          _data.writeString(serverMsg);
          boolean _status = mRemote.transact(Stub.TRANSACTION_onReceive, _data, _reply, 0);
          _reply.readException();
        }
        finally {
          _reply.recycle();
          _data.recycle();
        }
      }
    }
    static final int TRANSACTION_onReceive = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
  }
  public static final java.lang.String DESCRIPTOR = "android.helloservice.ICallBack";
  public void onReceive(java.lang.String serverMsg) throws android.os.RemoteException;
}

编写系统服务

上面aidl是定义服务接口,下面开始编写一个系统服务来实现接口。参考系统服务MountService.java的路径编写frameworks/base/services/java/com/android/server/HelloService.java

package com.android.server;

import android.content.Context;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.util.Log;
import android.helloservice.ICallBack;
import android.helloservice.IHelloService;
public class HelloService extends IHelloService.Stub {
    private static final String TAG = "HelloService";
    private RemoteCallbackList<ICallBack> callbackList = new RemoteCallbackList();
    private Context context;

    public HelloService(Context context) {
        this.context = context;
        Log.d(TAG, "HelloService() init");
    }

    @Override
    public String getHello(String send) throws RemoteException {
        Log.d(TAG, "getHello() called with: send = [" + send + "]");
        int num = callbackList.beginBroadcast();
        for (int i = 0; i < num; i++) {
            ICallBack callback = callbackList.getBroadcastItem(i);
            if (callback != null) {
                callback.onReceive("callback from HelloService with:" + send);
            }
        }
        callbackList.finishBroadcast();
        return send + ",server receive ok";
    }

    @Override
    public void registerCallback(ICallBack callback) throws RemoteException {
        callbackList.register(callback);
        Log.d(TAG, "registerCallback() called with: callback = [" + callback + "]");
    }

    @Override
    public void unRegisterCallback(ICallBack callback) throws RemoteException {
        callbackList.unregister(callback);
        Log.d(TAG, "unRegisterCallback() called with: callback = [" + callback + "]");
    }
}

注册系统服务

所有系统服务都运行在名为 system_server 的进程中,我们也要把服务加入进去。系统中已有很多服务了,我们把它加入到最后,修改frameworks/base/services/java/com/android/server/SystemServer.java

 	@Override
    public void run() {
    ...省略部分
    	try {
            Slog.i(TAG, "Entropy Mixer");
            ServiceManager.addService("entropy", new EntropyMixer());
			
			//HelloService的name必须唯一
		    Slog.i(TAG, "HelloService");
            ServiceManager.addService("HelloService", new HelloService(context));
        }
    }

执行mmm frameworks/base/services/java/编译service模块
执行make snod重新打包system.img
执行emulator重启模拟器,发现一直停留在重启界面。在这里插入图片描述
无奈,执行make -j30(本机16核32线程)重编也报错,提示如下

PRODUCT_COPY_FILES device/generic/goldfish/data/etc/apns-conf.xml:system/etc/apns-conf.xml ignored.
Checking API: checkapi-current
target Java: services (out/target/common/obj/JAVA_LIBRARIES/services_intermediates/classes)
out/target/common/obj/PACKAGING/public_api.txt:10084: error 2: Added package android.helloservice

******************************
You have tried to change the API from what has been previously approved.

To make these errors go away, you have two choices:
   1) You can add "@hide" javadoc comments to the methods, etc. listed in the
      errors above.

   2) You can update current.txt by executing the following command:
         make update-api

      To submit the revised current.txt to the main Android repository,
      you will need approval.
******************************

根据错误提示执行下面命令

make update-api
make -j30
emulator

模拟器重启成功,且看到HelloService相关日志,说明HelloService服务添加成功。

I/InputManager(  147): Starting input manager
D/PermissionCache(   35): checking android.permission.ACCESS_SURFACE_FLINGER for uid=1000 => granted (1193 us)
I/WindowManager(  147): Enabled StrictMode logging for WMThread's Looper
I/SystemServer(  147): HelloService
D/HelloService(  147): HelloService() init
I/SystemServer(  147): No Bluetooh Service (emulator)

App调用服务

framework层添加服务成功后,app如何使用服务呢?有两种方式,下面一一讲解

方式1:拿到AIDL文件直接访问

为了方便开发,用androidstudio新建一个项目名字就叫Hello。把上面的两个aidl文件复制到项目,保持aidl的包名结构,在这里插入图片描述

MainActivity内容如下,其中ServiceManager会报红不用管,因为等下我们要拷贝项目到aosp源码环境下编译,源码环境下可以正常编过。

package com.hai.hello;

import android.app.Activity;
import android.helloservice.ICallBack;
import android.helloservice.IHelloService;
import android.os.Bundle;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.Log;
import android.view.View;

public class MainActivity extends Activity {
    private static final String TAG = "MainActivity";
    IHelloService mService;
    ICallBack.Stub callback = new ICallBack.Stub() {
        @Override
        public void onReceive(String serverMsg) throws RemoteException {
            Log.d(TAG, "onReceive() called with: serverMsg = [" + serverMsg + "]");
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mService = IHelloService.Stub.asInterface(ServiceManager.getService("HelloService"));
        Log.d(TAG, "onCreate: " + mService);
        try {
            mService.registerCallback(callback);
        } catch (RemoteException e) {
            throw new RuntimeException(e);
        }
        try {
            mService.getHello("client say hello");
        } catch (RemoteException e) {
            throw new RuntimeException(e);
        }

        try {
            mService.unRegisterCallback(callback);
        } catch (RemoteException e) {
            throw new RuntimeException(e);
        }
    }
}

把项目拷贝到packages/experimental/目录下。参考此目录下的其他app的项目结构,移除不要的文件,最终Hello的目录结构如图在这里插入图片描述
Android.mk内容如下

LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
#LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_SRC_FILES += aidl/android/helloservice/IHelloService.aidl
LOCAL_SRC_FILES += aidl/android/helloservice/ICallBack.aidl
LOCAL_PACKAGE_NAME := Hello
LOCAL_CERTIFICATE := platform
include $(BUILD_PACKAGE)

执行以下命令单编Hello项目,重启模拟器,

mmm packages/experimental/Hello
make snod
emulator

在这里插入图片描述
点击启动app,从日志可以看到Hello app启动成功并和HelloService正确交互了。

方式2:通过getSystemService访问

为了方便开发者使用,我们也提供通用接口context.getSystemService()方式获取服务。仿照AccountManager我们也写一个类就叫HelloManager吧,
frameworks/base/core/java/android/helloservice/HelloManager.java内容如下

package android.helloservice;
import android.content.Context;
import android.helloservice.ICallBack;
import android.helloservice.IHelloService;
import android.os.RemoteException;
import android.util.Log;

public class HelloManager {
    private static final String TAG = "HelloManager";
    private Context context;
    private IHelloService service;

    public HelloManager(Context context, IHelloService service) {
        this.context = context;
        this.service = service;
        Log.d(TAG, "HelloManager()");
    }

    public String getHello(String send) {
        try {
            return service.getHello(send);
        } catch (RemoteException ex) {
            throw new RuntimeException(ex);
        }
    }

    public void registerCallback(ICallBack callback) {
        try {
            service.registerCallback(callback);
        } catch (RemoteException ex) {
            throw new RuntimeException(ex);
        }
    }

    public void unRegisterCallback(ICallBack callback) {
        try {
            service.unRegisterCallback(callback);
        } catch (RemoteException ex) {
            throw new RuntimeException(ex);
        }
    }
}

HelloManager写好之后需要注册到context中,修改frameworks/base/core/java/android/app/ContextImpl.java如下:

import android.helloservice.IHelloService;
import android.helloservice.HelloManager; 
static {
		...省略部分   
        registerService(ACCESSIBILITY_SERVICE, new ServiceFetcher() {
                public Object getService(ContextImpl ctx) {
                    return AccessibilityManager.getInstance(ctx);
                }});
             
	    registerService("HelloService", new ServiceFetcher() {
                public Object createService(ContextImpl ctx) {
                    IBinder b = ServiceManager.getService("HelloService");
                    IHelloService service = IHelloService.Stub.asInterface(b);
                    return new HelloManager(ctx, service);
                }});

        registerService(ACTIVITY_SERVICE, new ServiceFetcher() {
                public Object createService(ContextImpl ctx) {
                    return new ActivityManager(ctx.getOuterContext(), ctx.mMainThread.getHandler());
                }});

然后是app使用,这里还是使用Hello项目,修改MainActivity内容如下

package com.hai.hello;
import android.app.Activity;
import android.helloservice.ICallBack;
import android.helloservice.IHelloService;
import android.helloservice.HelloManager;
import android.os.Bundle;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.Log;
import android.view.View;

public class MainActivity extends Activity {
    private static final String TAG = "MainActivity";
    IHelloService mService;
    ICallBack.Stub callback = new ICallBack.Stub() {
        @Override
        public void onReceive(String serverMsg) throws RemoteException {
            Log.d(TAG, "onReceive() called with: serverMsg = [" + serverMsg + "]");
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
	    HelloManager helloManager=(HelloManager) getSystemService("HelloService");
        Log.d(TAG, "HelloManager onCreate: " + mService);
        helloManager.registerCallback(callback);
        helloManager.getHello("client say hello");
        helloManager.unRegisterCallback(callback);
    }
}

执行下面命令

mmm packages/experimental/Hello/
make update-api
make -j30
emulator

模拟器重启后看到如下日志,说明getSystemService的方式也访问成功。
在这里插入图片描述
参考:
Android 添加系统服务的完整流程SystemService
为Android系统的Application Frameworks层增加硬件访问服务
为Android硬件抽象层(HAL)模块编写JNI方法提供Java访问硬件服务接口

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1902291.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux笔记之二

Linux笔记之二 一、文件属性学习二、软链接和硬链接1.软链接2.硬链接 三、Vim编辑器四、账号管理总结 一、文件属性学习 Linux 系统是一种典型的多用户系统&#xff0c;不同的用户处于不同的地位&#xff0c;拥有不同的权限。为了保护系统的安全性&#xff0c;Linux系统对不同…

Educational Codeforces Round 167(Div.2) A~D

A.Catch the Coin&#xff08;思维&#xff09; 题意&#xff1a; Monocarp 参观了一家有街机柜的复古街机俱乐部。在那里&#xff0c;他对"抓硬币"游戏机产生了好奇。 游戏非常简单。屏幕上的坐标网格是这样的 X X X轴从左到右&#xff1b; Y Y Y轴从下往上&…

web缓存代理服务器

一、web缓存代理 web代理的工作机制 代理服务器是一个位于客户端和原始&#xff08;资源&#xff09;服务器之间的服务器&#xff0c;为了从原始服务器取得内容&#xff0c;客户端向代理服务器发送一个请求&#xff0c;并指定目标原始服务器&#xff0c;然后代理服务器向原始…

Python基础小知识问答系列-自定义反向迭代器

1. 问题&#xff1a; 现在想要一个具有反向迭代的迭代器&#xff0c;该怎样实现反向迭代的能力&#xff1f; 2. 解决方法&#xff1a; 首先&#xff0c;在自定义一个迭代器&#xff0c;在类中实现__reversed__方法&#xff1b;使用内置函数reversed实现反 向迭代。 示例&…

linux 下,Java由Java8升级到Java11,Java不更新版本号

在ES对接过程&#xff0c;springboot3进行对接&#xff0c;需要将Java升级到11版本。首先下载安装选好的11版本Java&#xff0c;在linux下解压后&#xff0c;配置/etc/profile export JAVA_HOME/root/SJL/jdk-11.0.22 然后保存&#xff0c;执行文件source /etc/profile&#…

【算法笔记自学】第 5 章 入门篇(3)——数学问题

5.1简单数学 #include <cstdio> #include <algorithm> using namespace std; bool cmp(int a,int b){return a>b; } void to_array(int n,int num[]){for(int i0;i<4;i){num[i]n%10;n /10;} } int to_number(int num[]){int sum0;for(int i0;i<4;i){sumsu…

BitWidget,自定义bit控件

由于QBitArray并不满足我做界面是的需求&#xff0c;所以参照QBitArray简单的写了个控件&#xff0c;如下所示&#xff0c;源码及实例在我上传的资源包中 实例 帮助文档如图所示&#xff08;部分&#xff09; 帮助文档&#xff08;在资源包中&#xff09; 1.html文档 2.chm文…

使用Python绘制和弦图

使用Python绘制和弦图 和弦图效果代码 和弦图 和弦图用于展示数据的多对多关系&#xff0c;适合用于社交网络、交通流量等领域的分析。 效果 代码 import pandas as pd import holoviews as hv from holoviews import opts hv.extension(bokeh)# 示例数据 data [(A, B, 2),…

Java对象通用比对工具

目录 背景 思路 实现 背景 前段时间的任务中&#xff0c;遇到了需要识别两个对象不同属性的场景&#xff0c;如果使用传统的一个个属性比对equals方法&#xff0c;会存在大量的重复工作&#xff0c;而且为对象新增了属性后&#xff0c;比对方法也需要同步修改&#xff0c;不方…

JUC(java.util.concurrent)中的常见类

文章目录 Callable接口ReentrantLockReentrantLock 和 synchronized 的区别:如何选择使用哪个锁? 信号量SemaphoreCountDownLatch多线程环境使用ArrayList多线程使用 哈希表相关面试题 JUC放了和多线程有关的组件 Callable接口 和Runnable一样是描述一个任务,但是有返回值,表…

查询某个县区数据,没有的数据用0补充。

加油&#xff0c;新时代打工人&#xff01; 思路&#xff1a; 先查出有数据的县区&#xff0c;用县区编码判断&#xff0c;不存在县区里的数据。然后&#xff0c;用union all进行两个SQL拼接起来。 SELECTt.regionCode,t.regionName,t.testNum,t.sampleNum,t.squareNum,t.crop…

springboot+vue+mybatis图书馆借阅管理系统+PPT+论文+讲解+售后

21世纪的今天&#xff0c;随着社会的不断发展与进步&#xff0c;人们对于信息科学化的认识&#xff0c;已由低层次向高层次发展&#xff0c;由原来的感性认识向理性认识提高&#xff0c;管理工作的重要性已逐渐被人们所认识&#xff0c;科学化的管理&#xff0c;使信息存储达到…

三分钟内了解卷轴模式

在数字化时代的浪潮中&#xff0c;卷轴商业模式巧妙地将积分体系、互动任务、社交裂变、虚拟经济体系以及个性化成长路径等多元要素融为一体。 积分体系&#xff1a;激发参与动力的源泉 卷轴商业模式的核心在于其精心构建的积分系统。新用户踏入平台&#xff0c;即获赠一笔启…

基于自编码器的时间序列异常检测方法(以传感器数据为例,MATLAB R2021b)

尽管近年来研究者对自编码器及其改进算法进行了深入研究&#xff0c;但现阶段仍存在以下问题亟须解决。 1) 无监督学习模式对特征提取能力的限制与有监督学习相比&#xff0c;无监督学习模式摆脱了对样本标签的依赖、避免了人工标注的困难&#xff0c;但也因此失去了样本标签的…

LLM - 循环神经网络(RNN)

1. RNN的关键点&#xff1a;即在处理序列数据时会有顺序的记忆。比如&#xff0c;RNN在处理一个字符串时&#xff0c;在对字母表顺序有记忆的前提下&#xff0c;处理这个字符串会更容易。就像人一样&#xff0c;读取下面第一个字符串会更容易&#xff0c;因为人对字母出现的顺序…

一站式解决方案:用ChatGPT和AutoGPT组建你的个人写作团队

ChatGPT 在 AI 内容创作领域带来了巨大的飞跃&#xff0c;然而它在撰写完整文章时偶尔会陷入废话和奇怪主题。作为专业作家、AI专家及OpenAI Beta测试人员&#xff0c;我一直探索AI写作。虽然ChatGPT表现出色&#xff0c;但有时难以达到创造高质量文章的标准。 最近&#xff0…

EtherCAT转Profinet网关配置说明第二讲:上位机软件配置

EtherCAT协议转Profinet协议网关模块&#xff08;XD-ECPNS20&#xff09;&#xff0c;不仅可以实现数据之间的通信&#xff0c;还可以实现不同系统之间的数据共享。EtherCAT协议转Profinet协议网关模块&#xff08;XD-ECPNS20&#xff09;具有高速传输的特点&#xff0c;因此通…

githup开了代理push不上去

你们好&#xff0c;我是金金金。 场景 git push出错 解决 cmd查看 git config --global http.proxy git config --global https.proxy 如果什么都没有&#xff0c;代表没设置全局代理&#xff0c;此时如果你开了代理&#xff0c;则执行如下&#xff0c;设置代理 git con…

Github:git提交代码到github

创建 GitHub 仓库 a. 登录到您的 GitHub 账户。 b. 点击右上角的 "" 图标&#xff0c;选择 "New repository"。 c. 填写仓库名称&#xff08;例如 "Mitemer"&#xff09;。 d. 添加项目描述&#xff08;可选&#xff09;。 e. 选择仓库为 &…

微信小程序的轻松音乐-计算机毕业设计源码48092

目 录 摘要 1 绪论 1.1研究背景与意义 1.2研究现状 1.3论文结构与章节安排 2 基于微信小程序的轻松音乐系统分析 2.1 可行性分析 2.1.1 技术可行性分析 2.1.2 经济可行性分析 2.1.3 法律可行性分析 2.2 系统功能分析 2.2.1 功能性分析 2.3 系统用例分析 2.4 系统…