精通安卓性能优化-第二章(三)

NDK编译脚本:Android.mk or CMakeLists.txt Android NDK以前默认使用Android.mk与Application.mk进行构建,但是在Android Studio2.2之后推荐使用CMake进行编译。Cmake是跨平台编译工具,全称为cross platform make,内建c、c++、java自动相依性分析功能,关于Cmake更多详情请参考官网:https://cmake.org/documentation/。下面我们对比下Android.mk与CmakeLists.txt的语法。 一、Android.mk语法 以动态库编译hell 阅读详情

编译Native库

既然已经完成C代码的实现,我们可以最终通过在应用的jni路径下调用ndk-build命令编译这个shared library。

TIP:修改环境变量,使它包含NDK目录,可以很方便的调用ndk-build或者其他脚本而不用指定命令的全路径。

结果是在lib/armeabi目录下生成名为libfibonacci.so的shared library。可能需要在Eclipse中刷新工程去显示新创建的库。如果你编译和运行这个应用程序,并且调用Fibonacci.recursiveNative,它会再次因为UnsatisfiedLinkError异常crash。这是一个典型的错误,因为许多开发者忘掉在Java代码中显式的加载shared library:VM不是千里眼,需要被告知哪些库需要加载。这可以通过调用System.loadLibrary()来实现,如2-11所示。

Listing 2-11 在静态初始化块加载库

public class Fibonacci {
    static {
        System.loadLibrary("fibonacci");    // to load libfibonacci.so
    }

    public static native long recursiveNative(int n);
}

加载Native库

在静态初始化语句块里面调用System.loadLibrary()是加载库的最简单方式。这个语句块中的代码在虚拟机加载类的时候执行,在任何方法被调用之前。(需要确认一下和构造函数的调用顺序,特别是书写的顺序在构造函数之后的情况)。一个潜在的性能问题,尽管不怎么普遍,如果你的类中有几个方法,不是所有都要求一切初始化(比如,shared libraries加载)。换句话说,静态初始化块会添加显著的开销,你将会希望去避免某些函数,如Listing 2-12所示。

Listing 2-12 在静态初始化块中加载库

public class Fibonacci {
    static {
        System.loadLibrary("fibonacci");   // 加载libfibonacci.so
        
        // 在这里做其他的耗时事情,将延后superFast的执行
    }

    public static native long recursiveNative (int n);

    public long superFast (int n) {
        return 42;
    }
}

NOTE:加载库需要的时间同样依赖于库本身(比如它的大小和方法数量)。

现在,我们看到了混合Java和C/C++的基本。本地代码是否可以提升性能,部分取决于C/C++代码是如何被编译的。事实上,存在许多的编译选项,使用不同的选项结果会变化非常大。

接下来的两部分告诉你在Application.mk和Android.mk中更多的选项,现在为止还是非常基本的。

Application.mk

Listing 2-4中的Application.mk在是最简单的之一。这个文件可以指定更多的东西,可能你需要在应用中定义许多选项。Table 2-3显示了你可以在Application.mk中定义的不同的变量。

Table 2-3 Application.mk中的变量


当微调应用的性能,你需要聚焦于这些变量:
(1) APP_OPTIM
(2) APP_CFLAGS
(3) APP_CPPFLAGS
(4) APP_STI
(5) APP_ABI

APP_OPTIM是可选的,可以被设置为release或者debug。如果没有被定义它,将会自动设置,依赖于你的应用是否debugable(android:debugable在manifest中被设置为true);如果应用debugable为true,APP_OPTIM将会设置为debug,否则,将被设置为release。在debug模式下,当你调试应用程序的时候它是有意义的,默认的行为被视为大多数情况可接受的,因此,大多数时间你不需要或者显式的去在Application.mk中定义APP_OPTIM。

APP_CFLAGS(C/C++)和APP_CPPFLAGS(C++ only) 定义传递给编译器的标志位。指定标志去优化代码并不是必须的,因为它们可以简单的用来包含一个路径去查找头文件(比如,APP_CFLAGS += -I(LOCAL_PATH)/myincludefiles)。参考gcc文档的详细标志清单。最经典的性能相关的标志是-Ox系列,x指定了优化级别,从0到无优化的3,或者-Os。然而,在多数情况下,简单的定义APP_OPTIM为release或者根本不定义APP_OPTIM是足够的,因为它将为你选择一个优化级别,产生可接受的结果。

APP_STL用来指定应用程序使用哪个标准库。比如,NDK 6定义了4个可能的值:
(1) system
(2) stlport_static
(3) stlport_shared
(4) gnustl_static

每个库都有它的优缺点。比如:
(1) 只有gnustl_static库支持C++异常和运行时类型信息(RTTI)。STLport库在NDK r7添加了对RTTI的支持。
(2) 如果多个本地共享库使用了C++库则使用stlport_shared。(记得去用System.loadLibrary(“stlport_shared”)显式的加载这个库)。
(3) 如果在你的应用程序有只有一个shared library使用stlport_static,避免动态的加载这个库。


你可以分别通过添加-fexceptions和-frtti到APP_CPPFLAGS打开C++异常和RTTI支持。

对(几乎)所有的设备优化

如果你的应用性能很大程度上依赖于C++库的性能,用不同的库去测试并且选择最好的。选择可能不是仅仅基于性能,因为你还要考虑其他的参数,比如你的应用程序的最终大小或者你需要的C++库的功能(比如RTTI)。


我们上面编译的库(libfibonacci.so)针对armeabi ABI编译。两个问题浮出水面:
(1) 当native代码和armeabi-v7a ABI兼容的情况下,它不会对Cortex系列的处理器优化。
(2) Native代码不会和x86 ABI兼容。

Cortex系列的处理器比基于早些的ARMv5结构的处理器更加强大。一个原因是新的指令集在armv7结构中定义,对armv5编译的库将不会使用。因为编译器以armeabi ABI为目标,它保证不会使用任何armv5的处理器不理解的指令。即使你的库编译为和基于Cortex的设备兼容,将不能完全利用CPU,因此不能利用全部的潜在性能。

NOTE:arm v7比arm v5更加强大有许多理由,指令集是一个理由。参考ARM网址(http://www.arm.com)不同体系的更多信息。

第二个问题更加严重,因为一个针对ARM ABI编译的库将不能用在一个基于x86结构的设备上。如果本地代码对你的应用程序是必须的话,将不能在任何基于Intel的Android设备上运行。在我们的示例中,System.loadLibray(“Fibonacci”)将会以一个UnsatisfiedLinkError的异常失败,意味着库不可以被加载。


这两个问题可以简单的修复,因为APP_ABI可以为native代码指定一系列的ABI,如Listing 2-12所示。通过指定多个ABI,你可以保证本地代码不止可以支持所有的结构,而且针对每一个都做优化。

Listing 2-12 Application.mk指定三个ABI

APP_ABI := armeabi armeabi-v7a x86

使用这个新的Application.mk重新编译你的应用程序之后,libs目录下将包含3个子目录。除了armeabi,还有两个新的目录armeabi-v7a和x86。你可以轻松的猜测出,两个新的目录涉及到应用现在支持的两个新的ABI。每个目录包含一个libfibonacci.so。

TIP:在编辑Application.mk或者Android.mk后使用ndk-build –B V=1去强制库重新编译,并且显示编译命令。这种方式可以验证你的改变在编译的过程中是否起到了期望的效果。

应用文件变得更大,因为现在它包含了同一个库的3个实例,每一个针对一个不同的ABI。Android的package manager将在安装应用的时候决定哪个库会被安装。Android系统定义了一个首选的ABI和一个可选的辅助的ABI。Package manager将会首先安装针对ABI的首选库,如果辅选库已经定义了,并且找不到首选的库的话,将会选择安装辅选库。比如,一个基于Cortex的安卓设备定义首选ABI为armeabi-v7a,辅选ABI为armeabi。表2-4给出了所有设备的首选和备选ABI。

Table 2-4 首选和辅选ABI


辅选的ABI提供了一个新的Android设备兼容老的Android应用的机制,因为ARMv7ABI向后兼容ARMv5。

NOTE:安卓系统将来可能定义比首选和备选ABI更多的选择,比如ARM设计一个新的ARMv8架构向后兼容ARMv7和ARMv5。

支持所有的设备

一个问题仍然存在。尽管现在应用支持所有的NDK支持的ABI,Android可以(而且很可能)将被移植到新的架构上。比如,我们之前提到的MIPS手机。Java的承诺是“写一次,在任何地方运行”(字节码是平台无关的,不需要去为了新的平台重新编译代码),本地代码是针对特定平台的,我们产生的3个库没有一个和基于MIPS的安卓系统兼容。有两种方式去解决这个问题:
(1) 当NDK支持一种新的ABI的时候为你的应用编译新的库
(2) 当package manager安装本地代码失败的情况下,你可以提供一个默认的Java实现

第一种方案是相当琐细的,因为它仅仅涉及到安装新的NDK,修改应用的Application.mk,重新编译应用,发布更新(比如,在安卓市场上)。然而,官方的Android NDK不会总是支持所有的安卓已经移植的ABI或者将被移植的。作为结果,建议你也实现第二个方案;换句话说,Java实现同样需要提供。

NOTE:MIPS技术提供了一个单独的NDK,允许你为MIPS ABI单独编译库。参考:http://develper.mips.com/android。

Listing 2-13给出了当加载本地库失败的情况下如何提供一个默认的Java实现。

Listing 2-13 提供一个默认的Java实现

public class Fibonacci {
    private static final boolean useNative;
    
    static {
        boolean success;
        
        try {
            System.loadLibrary("fibonacci");  // 加载libfibonacci.so
            success = true;
        } catch (Throwable e) {
            success = false;
        }
        
        useNative = success;
    }
    
    public static long recursive (int n) {
        if (useNative) return recursiveNative(n);
        return recursiveJava(n);
    }
    
    private static long recursiveJava (int n) {
        if (n>1) return recursiveJava(n-2) + recursiveJava(n-1);
        return n;
    }
    
    private static native long recursiveNative (int n);
}

一个替代的设计是使用策略模式:
(1) 设计一个策略接口
(2) 定义两个类去实现这个接口(一个使用本地代码,一个只使用Java)
(3) 基于System.loadLibrary()的结果实例化正确的类

Listing 2-14给出了替代设计的实现。


Listing 2-14 使用策略模式提供一个默认的Java实现

// FibonacciInterface.java

public interface FibonacciInterface {
    public long recursive (int n);
}

// Fibonacci.java

public final class FibonacciJava implements FibonacciInterface {
    public long recursive(int n) {
        if (n > 1) return recursive(n-2)+recursive(n-1);
        return n;
    }
}

// FibonacciNative.java

public final class FibonacciNative implements FibonacciInterface {
    static {
        System.loadLibrary("fibonacci");
    }
    
    public native long recursive (int n);
}

// Fibonacci.java

public class Fibonacci {
    private static final FibonacciInterface fibStrategy;
    
    static {
        FibonacciInterface fib;
        try {
            fib = new FibonacciNative();
        } catch (Throwable e) {
            fib = new FibonacciJava();
        }
        
        fibStrategy = fib;
    }
    
    public static long recursive (int n) {
        return fibStrategy.recursive(n);
    }
}

NOTE:因为本地函数现在在FibonacciNative.java中声明而不是Fibonacci.java,你需要去重新创建native库,这次使用com_apress_proandroid_FibonacciNative.c和com_apress_proandroid_FibonacciNative.h。(Java_com_apress_proandroid_FibonacciNative_recursiveNative将是从Java调用的函数名字)。如果使用之前的库将会有UnsatisfiedLinkError异常。

就性能表现而言,两个实现之间的细微差别足够安全的被忽略:
(1) 第一个实现每次recursive()被调用的时候需要一个判断
(2) 第二个实现在recursive()被调用的时候需要在静态初始化块有一个对象分配和virtual函数的调用。


从设计角度看,推荐你使用策略模式:
(1) 你仅需要选择一次合适的策略,不会有忘记if(useNative)测试的风险
(2) 可以简单的通过修改两行代码去改变策略
(3) 在不同的文件维护策略,使得维护更容易
(4) 添加一个方法到策略接口强制你在所有的实现类中实现该方法


就像你可以看到的,配置Application.mk并不是一个必须的任务。然而,你将很快认识到大多数时间所有的应用程序使用同样的参数,简单的复制已有的Application.mk到新的应用通常可以的。

Android.mk

Application.mk允许你指定整个应用的通用变量,Android.mk用来指定你要编译什么模块和怎么去编译他们,所有的这一切都是难以忍受的细节。Table 2-5列出了在NDK 6可用的变量。

Table 2-5 在Android.mk可以定义的变量



我们再次聚焦于影响性能的几个变量:
(1) LOCAL_CFLAGS
(2) LOCAL_CPPFLAGS
(3) LOCAL_ARM_MODE
(4) LOCAL_ARM_NEON
(5) LOCAL_DISABLE_NO_EXECUTE

LOCAL_CFLAGS和LOCAL_CPPFLAGS相似于APP_CFLAGS和APP_CPPFLAGS,但是仅仅会影响当前的模块,而在Application.mk中定义的标志影响所有的模块。推荐不要在Android.mk中设置优化级别而是依赖于Application.mk中的APP_OPTIM。

LOCAL_ARM_MODE可以用来强制生成ARM模式的二进制码,即使用32位的指令。而代码密度可能会是Thumb模式(16位指令),设置为ARM代码模式会比Thumb模式性能更好。比如,Android本身的Skia库显式的被编译为ARM模式。显然,这仅仅应用到ARM ABI,即armeabi和armeabi-v7a。如果你只希望特定的文件使用ARM模式,你可以在LOCAL_SRC_FILES列出他们,带有.arm扩展名,比如,file.c.arm而不是file.c。

LOCAL_ARM_NEON指出了是否可以在代码中使用Advanced SIMD指令或者内部函数,编译器是否可以在native code中生成NEON指令。尽管性能可以通过NEON指令显著的提升,NEON仅在ARMv7架构引入并且是可选项。NEON不是在所有设备上可用。比如,三星的Galaxy Tab 10.1不支持NEON,但是Nexus S支持。LOCAL_ARM_MODE单独的文件支持NEON,使用.neon扩展名。第三章覆盖到了NEON扩展并提供了实例代码。

TIP:可以在LOCAL_SRC_FILES联合.arm和.neon扩展名,比如,file.c.arm.neon。如果所有的扩展名都使用到了,保证.arm是第一个,否则,它将不会被编译。

LOCAL_DISABLE_NO_EXECUTE本身不会对性能有影响。然而,熟练地开发者喜欢动态生成代码的时候关闭NX bit(很可能达到更好的性能)。这不是一个普遍的事情,你很可能从来没有在Android.mk中指定这个标志位,NX bit默认是打开的。关闭NX bit同样需要考虑安全风险。

Android.mk可以指定多个模块,每个模块可以使用不同的标志和源文件。Listing 2-15给出了一个Android.mk文件,编译两个不同的模块使用了不同的标志。

Listing 2-15 Android.mk中的两个模块定义

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)
LOCAL_MODULE := fibonacci
LOCAL_ARM_MODE := thumb
LOCAL_SRC_FILES := com_apress_proandroid_Fibonacci.c fibonacci.c
include $(BUILD_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := fibonarmcci
LOCAL_ARM_MODE := arm
LOCAL_SRC_FILES := com_apress_proandroid_Fibonacci.c fibonacci.c
include $(BUILD_SHARED_LIBRARY)

Application.mk、Android.mk可以用很多方式配置。在这两个文件里选择正确的变量值是达到好的性能的关键,而不用求助于更加增强的和复杂的优化。NDK经常升级,你需要参考最新的在线文档,因为新版本会增加最新的变量,有些可能被淘汰。当新的NDK发布,推荐你重新编译应用并发布更新,特别是新版本带有新的编译器的情况下。

NOTE:在使用不同的tool chain(新的SDK或者NDK)重新编译后再次测试你的应用。


Android开发初期之后怎么提升?怎么才能叫精通?方向在哪? 1. Android开发初期之后怎么提升? 首先第一个问题:Android开发初期之后怎么提升?说到这个问题,就不得不先搞清楚 “为什么很多人会一直停留在两三年的水平上,而后一直在重复以往的经验,原地踏步?” 我认为最主要的一个原因就是这部分开发者缺乏主观能动性,或者说缺乏能支撑你坚持学习的兴趣。如果你对Android开发没有太大的兴趣,那么还是尽早换方向吧。有了兴趣,然后就是要有一个比较正确的钻研路线,不要这也搞那也抓,最后什么都知道点,但也就只是知道点儿。 一个很好的例子就是我们平时在开发过程中都会用 阅读详情

相关推荐

安卓ROM开发入门到精通

包含内容: 第一期主要为ROM开发,ROM定制技术资料,提供一些工具为主 ,让你学会简单做包,和基本的ROM DIY技巧,偶尔附加一些必要的教程。第二期针对ROM技术教程,细分知识点,重点剖析、解释,形成一系列的知识文档供查阅,目前大纲已列出,可以教你从零开始做包。 1.第一期---技术资料(维护更新): 更新日志: 1.书籍-Android系统级深入开发——移植与调试 2.开发工具-And...

艾威氪的博客 1万+

Android性能优化之APK瘦身最全总结

热文导读 | 点击标题阅读Android架构进阶学习路线图吊炸天!74款APP完整源码!欢迎加入Java和Android架构知识星球作者:我是吸血鬼链接:https://...

Java和Android架构 7252

Android/JAVA性能优化:从入门到精通(万字讲解!!!)

在当今快速发展的移动应用市场中,用户体验是决定应用成功与否的关键因素之一。无论是在Android还是其他平台上,应用的性能表现直接影响用户的满意度和应用的市场竞争力。作为开发者,掌握Java性能优化的技巧不仅能够提升应用的流畅度,还能延长应用的生命周期,从而在激烈的市场竞争中脱颖而出。本文将从内存管理、线程与并发、代码优化、网络优化、数据库优化等多个方面,深入探讨Java性能优化的策略和技巧,帮助开发者在实际开发中提升应用性能,优化用户体验。提示:以下是本篇文章正文内容,下面案例可供参考。

学无止境 1222

ARM64汇编01 - 环境搭建

这是非常有必要的,因为所有的编译文件都在同一个GUN MKAE执行环境中,所有的变量都是全局变量,不清除容易引起解析错误。LOCAL_ARM_MODE:默认情况下,构建系统会以 thumb 模式生成 ARM 目标二进制文件,其中每条指令都是 16 位宽,并与。现在的应用在googleplay与国内商店的推动下,都已采用了 arm64-v8a,所以我们可以不用太关心 thumb 指令了。前面我们说了,这个选项是用来表明生成的目标文件里面,它的汇编代码是使用 arm 还是 thumb 指令。

a5right的博客 1525

从零到精通:Android开发学习路径全解析

Android开发作为移动互联网核心技术之一,其技术栈经历了从基础SDK到现代架构的演进。理解Android系统架构需要扎实的Java/Kotlin基础,掌握Activity生命周期、UI组件等核心概念。在进阶阶段,开发者需要关注性能优化、架构设计等关键技术,如内存管理、MVVM模式实现等。通过项目实践和源码阅读,开发者可以深入理解Binder机制、AMS等底层原理。本文以知名博主stormzhang的学习路径为例,系统梳理了从Java基础到Flutter跨平台的完整学习框架,为移动开发者提供了一条清晰的技

weixin_34326558的博客 268

android游戏开发从入门到精通,androidstudio插件开发

如果基础知识有太多不会的就危险了,必须好好准备,这是躲不过的。这个阶段有不会的很正常,因为对方正在确定你的水平,但态度一定要积极主动,即使之前没有研究过,也要结合一些经验说出推测的结果,切忌直接说“我不会”。我只贴上我写过内容的链接,剩下的朋友们去网上一搜,或者去买本书看下就好了,建议看 《Java 编程思想》,不仅解答了 What 还有探讨 Why。我这次面试算法问的比较少,只手写过插入排序,建议把冒泡、插入、归并时间复杂度和实现熟悉熟悉,最好手写下,不然现场手写的时候容易出错。

2401_84408418的博客 1419

Android 程序的动态调试

Android程序的动态调试编译生成原生程序使用ndk-build编译原生程序使用Eclipse自动编译原生程序使用IDA Pro调试Android原生程序远程运行调试Android原生可执行程序远程附加调试Android原生动态链接库总结IDA调试的流程一些问题及解决方法 编译生成原生程序 NDK简介: NDK(英语:Native Development Kit,简称NDK)是一种基于原生程...

carol980206的博客 1600

Android面试指南与参考答案——基于领星安卓开发职位要求

本文基于领星安卓开发职位要求,整理Android开发岗位常见面试问题与参考答案。核心内容包括:1.基础知识:Android四层架构、SDK组件及API使用;2.编程语言:Kotlin优势、Jetpack组件应用及MVVM/MVP架构对比;3.开发工具:性能优化方法及版本适配策略;4.实战经验:第三方SDK集成和APP发布流程。针对1-3年经验者及应届生,提供代码示例和项目实例说明,覆盖框架搭建、性能优化等关键技术点,帮助候选人系统准备面试,突出技术能力和问题解决思维。

郑伟强dev的专栏 1192

android.mk中常见local变量解析

local变量是用来向生成系统描述你的组件的。你应该在'include $(CLEAR_VARS)'和'include $(BUILD_XXXXX)'之间定义其中的一些变量。 1.LOCAL_PATH    这个变量用来设置当前文件的路径。你必须在Android.mk的开始处定义它,比如:          LOCAL_PATH := $(call my-dir)        这

scusyq的专栏 3705

deap数据集的情绪检测代码环境搭建与实现

deap数据数据集很大

f的博客 4157

【每天一个知识点】多视图子空间聚类(Multi-view Subspace Clustering)

本文深入解析了多视图子空间聚类技术,这是一种处理多源异构数据的先进方法。它通过融合多个数据视图(如文本、图像、网络结构)的共识与互补信息,学习统一的潜在子空间表示,从而获得比单一视图更鲁棒、准确的聚类结果。文章详细阐述了其核心思想、主流技术流派(如图融合、共同潜在子空间、张量及深度学习方法),并提供了Python实战代码与调优经验,适用于跨模态检索、生物信息学等多领域复杂数据分析。

weixin_29065015的博客 459

Android从入门到精通

全书共分15章,内容包括Android快速入门、Android模拟器与常用命令、用户界面设计、高级用户界面设计、基本程序单元Activity、Android应用核心Intent、Android事件处理、资源访问、图形图像处理技术、多媒体应用开发、Content Provider实现数据共享线程与消息处理、Service应用、网络编程及Internet应用和基于Android的家庭理财通。[Android.游戏开发入门](美)Mario.Zechner.插图版.pdf。

github_38514857的博客 878

从零开始:手把手教你设计DP接口电路(含原理图实战)

本文是一份详尽的DisplayPort接口电路设计实战指南。文章从DP接口的核心架构与HDMI的差异讲起,手把手解析了高速差分对、AUX辅助通道、热插拔检测等关键模块的原理图设计要点,并提供了一个完整的DP Source端原理图实例,最后总结了PCB布局与信号完整性的核心考量,旨在帮助硬件工程师高效、稳定地完成DP接口电路设计。

transformer2023的博客 732

想学Android开发,是否必须精通Java?

想学Android开发,必然需要先精通Java,其次c++,再后面是kotlin,基本代码上系统源码framework层面都是java和c++,基本上找不到任何kotlin,源码中只有几个简单app使用是kotlin。在这里,我为大家整理了一些列Android学习资料,有需要的朋友可以扫描下方二维码,获取更多相关资料。

Eqiqi的博客 1988

Ubuntu 20.04 环境下Autoware.universe 与 Carla 0.9.13 联合仿真

安装内容: ROS Galactic Autoware.universe based on ROS Galactic Carla 0.9.13 UnrealEngine 4.26 Openplanner (additional files: op-bridge/op-agent/scenariorunner/map data)

mhl1107的博客 1798

openEuler在虚拟机的网络配置

ethernet0.virtualDev 可以配置成其他类型的虚拟网络适配器。常见的选项包括:vlance - 用于模拟 AMD PCnet32 LANCE 网络适配器,支持10Mbps。e1000 - 用于模拟 Intel E1000 千兆网络适配器,支持1Gbps。e1000e - 用于模拟更现代的 Intel E1000e 千兆网络适配器。vmxnet - 用于 VMware 的自定义网络适配器,性能更好但需要安装 VMware Tools。

FHY1221的博客 2931

android性能优化从入门到精通

什么是性能优化 一款app除了要有强大的功能和交互外,在性能上也应该追求更高的要求,这样才能更好的提高用户体验 优化目的 性能指标 优化的方向 更快 流畅性 启动速度页面响应速度响应速度 更稳定 稳定性 避免出现应用崩溃(crash)避免出现应用无响应(ANR) 更省 资源节省性 内存大小安装包大小耗电量网络流量 优化详解 速度优化 内存优化 数据结构优化:数据结...

qq_23081779的博客 1765

38、四旋翼无人机的机械建模、控制与仿真及小型无人机高度的最优鲁棒无模型控制

本文探讨了四旋翼无人机的机械建模、控制与仿真方法,采用基于PID控制器的分层控制策略实现稳定飞行与路径跟踪,并开发了结合CAD模型与MATLAB环境的飞行模拟器。同时,针对小型无人机高度控制问题,提出了一种基于粒子群优化(PSO)的最优鲁棒无模型控制(PSO-MFC)方法,有效解决了参数整定难题,实现了零稳态误差跟踪和强抗干扰能力。两种方法在仿真中均表现出良好性能,为无人机控制系统的设计与优化提供了理论与实践基础。

l6m7n8的博客 99

Android性能优化:从入门到精通

本文从基础知识、优化方法和实战案例分析三个方面,详细介绍了Android性能优化的方法和技巧。性能优化是Android开发中不可或缺的一部分,对提升用户体验具有重要意义。开发者应掌握性能优化的基础知识,合理运用优化方法,以实现应用的高性能表现。未来,随着移动设备的性能不断提升,性能优化将更加重要。开发者需要关注新的优化技术和工具,不断更新优化策略,以满足用户对高性能应用的需求。同时,性能优化也需要与用户需求相结合,避免过度优化,确保应用的平衡发展。持续关注新技术。

2501_92486623的博客 357

PyTorch深度学习实战(1)——神经网络与模型训练过程详解

在本节中,我们将了解传统机器学习与人工神经网络间的差异,并了解如何在实现前向传播之前连接网络的各个层,以计算与网络当前权重对应的损失值;实现反向传播以优化权重达到最小化损失值的目标。并将实现网络的所有关键组成——前向传播、激活函数、损失函数、链式法则和梯度下降,从零开始构建并训练了一个简单的神经网络。

盼小辉丶的博客 9万+

【TC3xx芯片】TC3xx芯片看门狗复位的默认行为分析

TC3xx芯片看门狗复位的默认行为分析

qq_36056498的博客 350

QtScrcpy安卓投屏完整攻略:从入门到精通

还在为手机屏幕太小而烦恼吗?想要在大屏幕上畅玩手游却不知从何下手?QtScrcpy这款开源安卓投屏工具正是你需要的解决方案!它能将手机屏幕实时投射到电脑,支持键盘鼠标操作,让你彻底告别触摸屏的局限。 ## 🎯 为什么选择QtScrcpy? **传统投屏痛点**: - 连接复杂,步骤繁琐 - 延迟高,画面卡顿 - 不支持键鼠操作 - 无法多设备管理 **QtScrcpy优势对比**: ✅ *

gitblog_00510的博客 3万+

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

Android面试官:你究竟有多大的勇气,在简历上写了“精通”?

自定义 View 可以让我们产生更好的效果,app UI 美观,交互界面友好,用户青睐,用户留存率高,这就是app成功的第一步了。高级UI与自定义View有着不可分割的联系。自定义View其实并不难,为什么呢?因为自定义View无非就是显示+交互:显示由 onMeasure ->onLayout->onDraw的整个流程就将显示整个流程处理完了,而交互则是touch事件的处理;另外其他的一切你比如Canvas,Animation,Paint都是围绕着draw来进行的,所以我们需要搞懂其中的根本原理。

the shy 127

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

零基础玩转Windows Subsystem for Android:从安装到精通的实用指南

Windows Subsystem for Android(简称WSA)是微软推出的革命性功能,它就像在Windows 11系统中搭建了一座通往Android世界的桥梁????,让你的电脑无需复杂配置就能直接运行手机应用。想象一下,你可以在电脑上刷短视频、使用生产力APP,甚至畅玩安卓游戏,所有操作都在熟悉的Windows环境中完成。对于开发者而言,这更是测试安卓应用的利器;对于普通用户,它则打破了设...

gitblog_01031的博客 1645

3分钟精通安卓虚拟相机:从零配置到多场景实战

想要在安卓设备上实现摄像头内容的灵活替换吗?VCAM虚拟相机为您提供了完美的解决方案。这款基于Xposed框架的安卓虚拟相机支持安卓5.0及以上系统,能够为直播、视频会议、隐私保护等场景创建虚拟摄像头接口,让您的手机摄像体验更加丰富多彩! ## 🎯 基础入门:环境准备与快速启动 ### 必备条件清单 在开始使用VCAM虚拟相机前,请确保您的设备满足以下基本要求: - ✅ 已安装Xposed

gitblog_00738的博客 666

Windows 11安卓子系统终极安装指南:从零到精通完整教程

想要在Windows 11上完美运行Android应用吗?WSA-Script项目为你提供了终极解决方案!这个开源项目能够将Magisk root权限和Google Play服务集成到Windows Subsystem for Android™中,让你在PC上获得完整的Android体验。🚀 ## 🔧 准备工作:系统要求检查 在开始安装Windows安卓子系统之前,请确保你的系统满足以下要

gitblog_00491的博客 1005
上一篇: 精通安卓性能优化-第二章(二)
下一篇: 精通安卓性能优化-第二章(四)
北冥_有鱼
博客等级 码龄19年 14粉丝 0原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值