android framework车载桌面CarLauncher的TaskView详细源码分析

TaskView TaskView是AOSP提供给系统开发者的一个强大工具,用于实现真正的“应用内嵌应用”。它通过系统服务在底层创建一个独立但视觉上融合的任务栈,完美地解决了跨进程窗口管理的复杂性。如果你的角色是系统应用开发者(例如在为设备制造商工作),需要实现分屏、自由窗口或复杂的应用切换界面,那么深入理解并使用TaskView将是关键。对于普通应用开发者而言,了解其存在和原理有助于理解Android系统UI的工作机制,但无法直接在自己的应用中使用它。 阅读详情
AI摘要

文章详细阐述了Android车载系统中TaskView的构建过程,包括TaskViewManager的初始化,TaskView的创建以及如何将其添加到ViewGroup中。同时,文中通过日志堆栈展示了Activity启动的步骤,特别强调了Task启动后的surface重新挂载操作以及onTaskAppeared回调。整个流程涉及到系统服务间的通信和Task状态的监听与更新机制。

1、构建相关的TaskView,装载到对应的ViewGroup

b站免费视频教程讲解:
https://www.bilibili.com/video/BV1wj411o7A9/
在这里插入图片描述

//packages/apps/Car/Launcher/src/com/android/car/carlauncher/CarLauncher.java
void onCreate() {
//ignore
 setContentView(R.layout.car_launcher);
            // We don't want to show Map card unnecessarily for the headless user 0.
            if (!UserHelperLite.isHeadlessSystemUser(getUserId())) {
                ViewGroup mapsCard = findViewById(R.id.maps_card);
                if (mapsCard != null) {
                //这里获取了mapsCard后,接下来就是构造出对应的TaskView
                    setUpTaskView(mapsCard);
                }
            }
            //ignore
            }
            //进行TaskView相关的设置
  private void setUpTaskView(ViewGroup parent) {
        //把TaskViewManager进行构造
        mTaskViewManager = new TaskViewManager(this,
                new HandlerExecutor(getMainThreadHandler()), mCarActivityManagerRef);
                //创建对应的TaskView
        mTaskViewManager.createTaskView(taskView -> {
            taskView.setListener(getMainExecutor(), mTaskViewListener);
            //把TaskView添加到了mapsCard
            parent.addView(taskView);
            mTaskView = taskView;
        });
    }
    //packages/apps/Car/Launcher/src/com/android/car/carlauncher/TaskViewManager.java
        public TaskViewManager(@UiContext Context context, HandlerExecutor handlerExecutor,
            AtomicReference<CarActivityManager> carActivityManagerRef) {
        mContext = context;
        mExecutor = handlerExecutor;
        //构造对应的ShellTaskOrganizer
        mTaskOrganizer = new ShellTaskOrganizer(mExecutor, mContext);
     
        //把TaskOrganizer进行对应的注册
        initTaskOrganizer(carActivityManagerRef, transactionPool);
    }
    //构造出TaskView
   void createTaskView(Consumer<TaskView> onCreate) {
        CarTaskView taskView = new CarTaskView(mContext, mTaskOrganizer, mSyncQueue);
        mExecutor.execute(() -> {
            onCreate.accept(taskView);
        });
    }

总结:
1、构建出对应的TaskViewManager,主要是注册和初始化TaskOrganizer
2、创建出相关的TaskView即SurfaceView,并放置到CarLauncher的ViewGroup

时序图如下:
在这里插入图片描述

2、相关Activity的启动情况

启动Activity相关堆栈

07-26 17:25:48.075  1584  1584 I lsm3333 : TaskView startActivity
07-26 17:25:48.075  1584  1584 I lsm3333 : java.lang.Exception
07-26 17:25:48.075  1584  1584 I lsm3333 : 	at com.android.wm.shell.TaskView.startActivity(TaskView.java:179)
07-26 17:25:48.075  1584  1584 I lsm3333 : 	at com.android.car.carlauncher.CarLauncher.startMapsInTaskView(CarLauncher.java:373)
07-26 17:25:48.075  1584  1584 I lsm3333 : 	at com.android.car.carlauncher.CarLauncher.-$$Nest$mstartMapsInTaskView(Unknown Source:0)
07-26 17:25:48.075  1584  1584 I lsm3333 : 	at com.android.car.carlauncher.CarLauncher$1.onInitialized(CarLauncher.java:108)
07-26 17:25:48.075  1584  1584 I lsm3333 : 	at com.android.wm.shell.TaskView.lambda$surfaceCreated$11$com-android-wm-shell-TaskView(TaskView.java:416)
07-26 17:25:48.075  1584  1584 I lsm3333 : 	at com.android.wm.shell.TaskView$$ExternalSyntheticLambda11.run(Unknown Source:2)
07-26 17:25:48.075  1584  1584 I lsm3333 : 	at android.os.Handler.handleCallback(Handler.java:942)
07-26 17:25:48.075  1584  1584 I lsm3333 : 	at android.os.Handler.dispatchMessage(Handler.java:99)
07-26 17:25:48.075  1584  1584 I lsm3333 : 	at android.os.Looper.loopOnce(Looper.java:201)
07-26 17:25:48.075  1584  1584 I lsm3333 : 	at android.os.Looper.loop(Looper.java:288)
07-26 17:25:48.075  1584  1584 I lsm3333 : 	at android.app.ActivityThread.main(ActivityThread.java:7898)
07-26 17:25:48.075  1584  1584 I lsm3333 : 	at java.lang.reflect.Method.invoke(Native Method)
07-26 17:25:48.075  1584  1584 I lsm3333 : 	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
07-26 17:25:48.075  1584  1584 I lsm3333 : 	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:936)


主要代码流程步骤如下:
TaskView.onInitialized -->CarLauncher.startMapsInTaskView -->
TaskView.startActivity -->TaskView.prepareActivityOptions -->PendingIntent.send
相关时序图如下:
在这里插入图片描述

3、Task启动后,进行相关的surface重新挂载操作

Task启动完成后进行相关的onTaskAppeared回调:
相关堆栈:

07-26 17:33:03.205  2931  2931 I lsm3333 : onTaskAppeared taskInfo = TaskInfo{userId=10 taskId=1000013 displayId=0 isRunning=true baseIntent=Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.android.car.mapsplaceholder/.MapsPlaceholderActivity } baseActivity=ComponentInfo{com.android.car.mapsplaceholder/com.android.car.mapsplaceholder.MapsPlaceholderActivity} topActivity=ComponentInfo{com.android.car.mapsplaceholder/com.android.car.mapsplaceholder.MapsPlaceholderActivity} origActivity=null realActivity=ComponentInfo{com.android.car.mapsplaceholder/com.android.car.mapsplaceholder.MapsPlaceholderActivity} numActivities=1 lastActiveTime=462943 supportsSplitScreenMultiWindow=false supportsMultiWindow=true resizeMode=2 isResizeable=true minWidth=-1 minHeight=-1 defaultMinSize=220 token=WCT{android.window.IWindowContainerToken$Stub$Proxy@8b9b010} topActivityType=1 pictureInPictureParams=null shouldDockBigOverlays=false launchIntoPipHostTaskId=0 displayCutoutSafeInsets=null topActivityInfo=ActivityInfo{7150709 com.android.car.mapsplaceholder.MapsPlaceholderActivity} launchCookies=[android.os.Binder@a4aa911] positionInParent=Point(303, 57) parentTaskId=-1 isFocused=true isVisible=false isSleeping=false topActivityInSizeCompat=false topActivityEligibleForLetterboxEducation= false locusId=null displayAreaFeatureId=1 cameraCompatControlState=hidden}
07-26 17:33:03.205  2931  2931 I lsm3333 : java.lang.Exception
07-26 17:33:03.205  2931  2931 I lsm3333 : 	at com.android.wm.shell.TaskView.onTaskAppeared(TaskView.java:313)
07-26 17:33:03.205  2931  2931 I lsm3333 : 	at com.android.car.carlauncher.CarTaskView.onTaskAppeared(CarTaskView.java:46)
07-26 17:33:03.205  2931  2931 I lsm3333 : 	at com.android.wm.shell.ShellTaskOrganizer.onTaskAppeared(ShellTaskOrganizer.java:440)
07-26 17:33:03.205  2931  2931 I lsm3333 : 	at com.android.wm.shell.ShellTaskOrganizer.onTaskAppeared(ShellTaskOrganizer.java:429)
07-26 17:33:03.205  2931  2931 I lsm3333 : 	at android.window.TaskOrganizer$1.lambda$onTaskAppeared$4$android-window-TaskOrganizer$1(TaskOrganizer.java:306)
07-26 17:33:03.205  2931  2931 I lsm3333 : 	at android.window.TaskOrganizer$1$$ExternalSyntheticLambda6.run(Unknown Source:6)
07-26 17:33:03.205  2931  2931 I lsm3333 : 	at android.os.Handler.handleCallback(Handler.java:942)
07-26 17:33:03.205  2931  2931 I lsm3333 : 	at android.os.Handler.dispatchMessage(Handler.java:99)
07-26 17:33:03.205  2931  2931 I lsm3333 : 	at android.os.Looper.loopOnce(Looper.java:201)
07-26 17:33:03.205  2931  2931 I lsm3333 : 	at android.os.Looper.loop(Looper.java:288)
07-26 17:33:03.205  2931  2931 I lsm3333 : 	at android.app.ActivityThread.main(ActivityThread.java:7898)
07-26 17:33:03.205  2931  2931 I lsm3333 : 	at java.lang.reflect.Method.invoke(Native Method)
07-26 17:33:03.205  2931  2931 I lsm3333 : 	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
07-26 17:33:03.205  2931  2931 I lsm3333 : 	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:936)


相关业务代码的执行:


 @Override
    public void onTaskAppeared(ActivityManager.RunningTaskInfo taskInfo,
            SurfaceControl leash) {

        if (mSurfaceCreated) {
            // Surface is ready, so just reparent the task to this surface control
            //核心的关键方法,对task的surface进行从新reparent到surfaceview的surafce下,这样实现了activity之间的内嵌
            mTransaction.reparent(mTaskLeash, getSurfaceControl())
                    .show(mTaskLeash)
                    .apply();
        } else {
         
        }
       //这里会再次进行相关的位置变化通知,该方法会触发重新对task的bounds进行更新
        onLocationChanged();
        if (taskInfo.taskDescription != null) {
            int backgroundColor = taskInfo.taskDescription.getBackgroundColor();
            mSyncQueue.runInSync((t) -> {
                setResizeBackgroundColor(t, backgroundColor);
            });
        }

        if (mListener != null) {
            final int taskId = taskInfo.taskId;
            final ComponentName baseActivity = taskInfo.baseActivity;
            mListenerExecutor.execute(() -> {
            //回调对应的CarLauncher的onTaskCreated方法
                mListener.onTaskCreated(taskId, baseActivity);
            });
        }
    }

4、Task启动过程通知流程详细分析

1、首先要监听Task相关的显示情况,必须要注册相关的监听方法
进行相关的ShellTaskOrganizer构造

//省略相关方法
public TaskViewManager(@UiContext Context context, HandlerExecutor handlerExecutor,
            AtomicReference<CarActivityManager> carActivityManagerRef) {
      //构造对应的TaskOrganizer
        mTaskOrganizer = new ShellTaskOrganizer(mExecutor, mContext);
      
        initTaskOrganizer(carActivityManagerRef, transactionPool);
    }
    
       private void initTaskOrganizer(AtomicReference<CarActivityManager> carActivityManagerRef,
            TransactionPool transactionPool) {
				//这个方法关键注册到systemserver端,建立联系
        List<TaskAppearedInfo> taskAppearedInfos = mTaskOrganizer.registerOrganizer();
    }
 public List<TaskAppearedInfo> registerOrganizer() {
        try {
        //这里就是正式的跨进程,把mInterface传递给systemserver方便回调
            return mTaskOrganizerController.registerTaskOrganizer(mInterface).getList();
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

总结:上面几步最重要就是与systemserver端建立了联系,而且把相关的回调的mInterface传递到了systemserver端,这样systemserver端就可以在Task有变化情况下通过mInterface通知到客户端

2、监听后怎么准确的通知到TaskView

上面第一步已经实现了CarLauncher可以监听Task的相关行为,注意这里肯定是所有的Task行为,但是TaskView它自身只关心Map相关的Task,那么这里是怎么精准通知的呢?

这里可以通过一个堆栈看看:

07-26 17:33:03.205  2931  2931 I lsm3333 : 	at com.android.car.carlauncher.CarTaskView.onTaskAppeared(CarTaskView.java:46)
07-26 17:33:03.205  2931  2931 I lsm3333 : 	at com.android.wm.shell.ShellTaskOrganizer.onTaskAppeared(ShellTaskOrganizer.java:440)
07-26 17:33:03.205  2931  2931 I lsm3333 : 	at com.android.wm.shell.ShellTaskOrganizer.onTaskAppeared(ShellTaskOrganizer.java:429)
07-26 17:33:03.205  2931  2931 I lsm3333 : 	at android.window.TaskOrganizer$1.lambda$onTaskAppeared$4$android-window-TaskOrganizer$1(TaskOrganizer.java:306)

可以明显看出这里systemserver跨进程回调到了ShellTaskOrganizer的onTaskAppeared,在这个方法进行精准匹配到TaskView关心的Task变化,然后进行通知


    private void onTaskAppeared(TaskAppearedInfo info) {
        final int taskId = info.getTaskInfo().taskId;
        mTasks.put(taskId, info);
        //这里进行对应的TaskListener获取,这里就是TaskView的listener获取,本身TaskView是有实现 ShellTaskOrganizer.TaskListener接口的
        final TaskListener listener =
                getTaskListener(info.getTaskInfo(), true /*removeLaunchCookieIfNeeded*/);
                
     //获取了TaskView的Listener后就可以进行通知了,从而他知道TaskView的onTaskAppeared
        if (listener != null) {
            listener.onTaskAppeared(info.getTaskInfo(), info.getLeash());
        }
       
    }

接下来就是重点分析这个getTaskListener,是怎么可以准确知道当前通知的Task信息就是TaskView对应的Task信息


private TaskListener getTaskListener(RunningTaskInfo runningTaskInfo,
            boolean removeLaunchCookieIfNeeded) {
				//这里的launchCookies属于系统端回调带的
        final ArrayList<IBinder> launchCookies = runningTaskInfo.launchCookies;
       
        for (int i = launchCookies.size() - 1; i >= 0; --i) {
            final IBinder cookie = launchCookies.get(i);
            //拿系统端的回调的cookie与本地进行匹配,配上了就进行获取了相关的listener
            listener = mLaunchCookieToListener.get(cookie);

            if (removeLaunchCookieIfNeeded) {
                // Remove the cookie and add the listener.
                mLaunchCookieToListener.remove(cookie);
                mTaskListeners.put(taskId, listener);
          
            }
            return listener;
        }

        return mTaskListeners.get(taskListenerType);
    }

上面看出核心就是服务端会在TaskInfo中有对应的cookie,然后本地也有对应的cookie集合map,这样实现的准确匹配。
那么这个cookie来自哪里呢?哈哈,其实这个cookie都是来自客户端的,在启动activity时候就构造设置了

 public void startActivity(@NonNull PendingIntent pendingIntent, @Nullable Intent fillInIntent,
            @NonNull ActivityOptions options, @Nullable Rect launchBounds) {
        //在这prepareActivityOptions进行了相关参数的设置
        prepareActivityOptions(options, launchBounds);
   //省略
    }

来看看prepareActivityOptions方法:

 private void prepareActivityOptions(ActivityOptions options, Rect launchBounds) {
       //构造出了这个cookie,其实就是binder对象
        final Binder launchCookie = new Binder();
        mShellExecutor.execute(() -> {
        //这里把这个cookie进行相关的存放到map
            mTaskOrganizer.setPendingLaunchCookieListener(launchCookie, this);
        });
        options.setLaunchBounds(launchBounds);
        //把cookie设置进了option,可以传递到systemserver端
        options.setLaunchCookie(launchCookie);
        options.setLaunchWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
        options.setRemoveWithTaskOrganizer(true);
    }
   public void setPendingLaunchCookieListener(IBinder cookie, TaskListener listener) {
        synchronized (mLock) {
        //把这里的cookie放到了mLaunchCookieToListener的集合中
            mLaunchCookieToListener.put(cookie, listener);
        }
    }

通过这个cookie即可以精准的把系统回调的TaskInfo匹配到对应的TaskView

Android12 车载开发TaskView实现分屏 这里只给出TaskView的代码,相关联的源码,请看源码,如果想要使用TaskView需要自己去编译frameWork的源码,打包一个aar,或者jar出来使用,否则无法直接使用。1.如果分屏的应用如启动两个应用按照权重占比,互相不叠加在一起,点触摸击事件都可响应,例如左边启动QQ了,右边启动的是微信,二者窗口都可操作。TaskView是谷歌整合安卓多任务多窗口下交互重新重构的独立出来的module,本身继承自ServiceView,TaskView的相关概念性的东西参考。//创建的taskview。 阅读详情

相关推荐

Android 11多窗口+分屏+APP窗口嵌套TaskView实现原理一

然而随着版本的迭代升级,google对分屏的定制差异化也越来越大,Androd 11的分屏用的是split-screen-primary和split-screen-secondary的方式,在systemui中去实现的,其定制化的灵活度不是很高,很多业务都是放到sustemui或者fw去实现,但是随着版本的升高,后面出现了TaskView来替代了老版本的分屏方式,但是Task的核心原理其实和之前的方式是一样的,TaskView来实现分屏。

qq_18420641的博客 2615

TaskView简述

TaskView简单介绍

LeeZhenJee的博客 5812

告别爆显存!手把手教你为ComfyUI+华为Atlas 300I Duo配置wan2.1视频生成工作流(含CPU-VAE参数)

本文详细介绍了华为Atlas 300I Duo与ComfyUI的深度适配实战,重点优化wan2.1视频生成工作流。从硬件散热改造到软件栈配置,再到ComfyUI专项优化,提供完整的解决方案,显著提升视频生成效率与稳定性,特别适合需要高效文生视频的应用场景。

weixin_26812607的博客 461

Android Automotive OS 中 TaskView 深度解析 (转载)

Android Automotive OS 中的 TaskView 机制深入定制了 Android 的窗口管理,使得车载系统能够在一个屏幕上安全、高效地呈现多个应用界面。这一实现涉及 WindowManager、ShellTaskOrganizer、SurfaceControl 等框架组件协同工作:通过 LaunchCookie 精确匹配任务,通过 SurfaceControl 重组屏幕合成,通过 Insets 调整输入区域,以及通过权限机制保障只有系统应用才能驱动。TaskView 满足了车载场景对于。

m0_59896099的博客 2526

eNSP安装教程

eNSP安装教程一、安装eNSP1、先安装依赖组件2、安装eNSP主程序eNSP+V100R003C00SPC100+Setup ---不要安装在中文路径下3、安装完成后注册设备 一、安装eNSP 程序包位置:https://drive.weixin.qq.com/s?k=AOgAQQfOAAsw1wAKEgAAcAbgbSAKQ 1、先安装依赖组件 依赖组件: WinPcap_4_1_3 —直接下一步,但不要安装在中文路径下 Wireshark_v3.4.6 或者wireshark-win3

qimowei的博客 8668

SpringBoot+Vue前后端分离项目实战:个人博客系统

MyBlog主要是基于 SpringBoot + Vue 前后端分离开发的一款动态个人博客系统,后台和前台均通过JSON数据做交互,主要功能有文章管理、分类管理、标签管理、附件管理、评论管理、友链管理、个人资料/博客信息管理等。

Myles'Blog 1万+

Android7.0多窗口实现原理(一)

概述 在Android N(7.0)版本开始,系统支持了多窗口功能。在有了多窗口支持之后,用户可以同时打开和看到多个应用的界面。并且系统还支持在多个应用之间进行拖拽。在大屏幕设备上,这一功能非常实用。 在Android N中多窗口有三种表现形式: 分屏模式 该模式主要将屏幕一分为二,同时出现两个应用界面。     2.画中画模式 该模式主要在视频播放中使用,可以使视频播放窗口一直处于...

宇落 生命不息,奋斗不止...... 1万+

ESP32 CAM使用教程(入门级)

串口被占用,可以关闭其他使用到串口的界面;先将手机也连上wifi,然后使用手机浏览器打开这个IP地址,注意手机连接的wifi需要和开发板的wifi一致,也就是程序里自己修改的那个wifi,否则无法打开IP地址;将开发板连接到电脑,点击点击工具→端口,然后选择自己实际接的COM口,不清楚COM口的可以打开电脑设备管理器查看一下,插拔设备看看哪个COM口会刷新就是哪个COM口;安装好esp32库之后,点击工具→开发板→esp32→AI Thinker ESP32-CAM,型号要仔细找找,不要选错了;

qq_34426854的博客 2万+

Launcher对RecentView展示TaskView详细分析-android framework车载车机手机系统开发

实际上这里创建的调用栈是,但是这里明显使用的ViewPool这种方式,主要是为了减少频繁创建的,所以就干脆缓存到ViewPool中,需要用时候再拿出来。上面可以看出主要是通过RecentsView.applyLoadPlan方法,这个其实是从getTasks这个方法里面进行调用的。1、桌面调用到sysui获取Task信息,因为sysui中其实有分屏相关的TecentTask信息。这里其实会调用的sysui的getRecentTasks进行查询。那么又是哪里调用到的getTasks这个方法呢?

liaosongmao1的专栏 1119

Nordic开发者必备:SEGGER Embedded Studio免费许可证申请与配置全攻略

本文为Nordic芯片开发者提供了SEGGER Embedded Studio(SES)集成开发环境的详细配置指南。内容涵盖免费许可证的合规申请流程、项目创建、Nordic SDK集成,以及编辑器优化、构建调试配置、RTT日志输出等核心功能的高效设置,旨在帮助开发者构建深度优化的专业开发环境,显著提升嵌入式开发效率。

cheese的博客 353

用 Coze 打造纯自动化 AI 情报助手

本文将引导您逐步构建一个简易的AI情报助手,从提示词到工作流,再到卡片消息,详细讲解了如何利用Coze平台开发自动化工具。过程简单易懂,何不亲自动手一试?如果您对此类内容感兴趣,敬请关注本作者。未来,我将带来更多精彩的AI工具教程,助您迅速掌握各类AI应用。在这个AI时代,让您领先一步。t=O83A2AGI.NET AI 教程 震撼!用 Coze 打造纯自动化 AI 情报助手震撼!

xinzhaobuxuan的博客 2531

TaskView 是一个系统内部使用的视图组件

TaskView是Android系统中负责“最近任务列表”中单个任务展示与交互的内部视图组件,属于系统应用层面的实现,不对外公开。开发者在普通应用中无法直接使用,但在研究系统源码(如定制Launcher、开发系统级应用)时,可能会接触到它的实现逻辑。

ringboycn的专栏 535

SAP UI5 OData V4 操作结果访问:从 getObject 到返回值上下文与 $$inheritExpandSelect

SAP UI5 OData V4 操作结果获取指南 摘要:在 SAP UI5 OData V4 模型中,操作结果需通过绑定上下文获取而非直接从 invoke() 返回。本文详解核心要点: 数据获取路径 使用 invoke() 发起请求后,通过 getBoundContext().getObject() 获取结果 特定场景下 invoke() 可能返回返回值上下文(如草稿切换) 关键实践技巧 使用 $$inheritExpandSelect 继承字段选择,避免二次读取 对象页应用中,通过替换绑定上下文实现无缝

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 314

深入分析TaskView源码之触摸相关

明显发现触摸派发window层级方面还是以桌面为顶部window,地图为底下window,这样其实也可以理解,我们上面的说的情况一样,其实整个画面都是CarLauncher的,地图Activity也只是CarLauncher的一个View而已。这里就说明了CarLauncher虽然在顶部,但是他的touchRegion根本没有包含地图Activity的区域,所以派发事件时候根本不会抢地图Activity的,即地图区域的事件不会派发到桌面。2、TaskView的Activity是怎么可以接收事件的呢?

learnframework的博客 1484

YOLOv8【第二章:卷积创新篇·第23节】一文搞懂,Transformer与卷积混合架构!

🏆 本文收录于 《YOLOv8实战:从入门到深度优化》,该专栏持续复现网络上各种热门内容(全网YOLO改进最全最新的专栏,质量分97分+,全网顶流),改进内容支持(分类、检测、分割、追踪、关键点、OBB检测)。且专栏会随订阅人数上升而涨价(毕竟不断更新),当前性价比极高,有一定的参考&学习价值,部分内容会基于现有的国内外顶尖人工智能AIGC等AI大模型技术总结改进而来,嘎嘎硬核。    ✨ 特惠福利:目前活动一折秒杀价!一次订阅,永久免费,所有后续更新内容均免费阅读!

**My Coding Family** 1388

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

Android 车载应用开发与分析 - CarLauncher

虽然Launcher也是一个APP,但是它涉及到的技术点却比一般的APP要多。CarLauncher作为IVI系统的桌面,需要显示系统中所有用户可用app的入口,显示最近用户使用的APP,同时还需要支持在桌面上动态显示如地图、音乐在内各个APP内部的信息,在桌面显示地图并与之进行简单的交互。Launcher是安卓系统中的主要程序组件之一,安卓系统中如果没有Launcher就无法启动安卓桌面,Launcher出错的时候,安卓系统会出现“进程 com.android.launcher 意外停止”的提示窗口。

工宗浩生财指南针 4477

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

Android车载AOSP Android 12 CarLauncher的替换

替换车载CarLauncher

weixin_43742853的博客 1944

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

Android Task的随笔

近期任务 Task

weixin_44987266的博客 864

基础总结篇之二:Activity的四种launchMode

合抱之木,生於毫末;九層之台,起於累土;千里之行,始於足下。《老子》 今天在社区看到有朋友问“如何在半年内成为顶级架构师”,有网友道“关灯睡觉,不用半年的...”,的确,做梦还来的快一些。作为一个程序员,树立远大的目标是值得欣赏的,但不能只去空想,要一步一步地实践才行。成大事者,须从小事做起;万事起于忽微,量变引起质变。 我们今天要讲的是Activity的四种launchMode。 laun...

t225com 1263

Android多窗口事件

Android多窗口类型现在主要有三种:分屏模式,自由模式(弹窗模式),画中画模式。 多窗口模式的实现依赖于FrameWork层的代码,app层面开启多窗口只需要在AndroidManifest.xml中声明属性即可 android:resizeableActivity="true" 声明该属性后,该应用在支持多窗口的机型上即可在多窗口模式下打开。 如果需要禁用多窗口,只需要在属性里声明 android:resizeableActivity="false" 即可,该属性只有在sdk24及以上才能

weixin_43473965的博客 3620

【Android】性能优化

1,布局优化 (1)减少布局层级 (2)减少同布局层级中控件数量 (3)尽量使用ConstraintLayout布局,这是一种优化的RelativeLayout (4)使用merge标签减少布局层数 (5)warp_content会增加布局measure计算时间 (6)减少onDraw在同一区域过度绘制 <merge>标签 如果通过setContentView设置布局,那么布局会加载到DecorView中去,作为content,而DecorView布局的根布局是FrameLayo

qq_40900926的博客 469

recentUI截屏、taskview大小调整

时间:2021/01/20之前公司不允许csdn,笔记写在其它地方。最近整理过来。

纵容的博客 872

Android Recentsview多任务界面,taskview黑屏原因

recentsview下出现taskview黑屏问题

raolulu的博客 893
上一篇: pip触摸部分源码分析-pip窗口的移动,删除窗口/车载车机手机系统开发
下一篇: android 10车载CarLauncher的ActivityView源码方案分析
千里马学框架
博客等级 码龄6年 1万+粉丝 650原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

千里马学框架

帮助你了,就请我喝杯咖啡

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值