Android Gradle Plugins系列-01-自定义Gradle插件入门指南

2023-05-16

前言

本文内容已经有很多大佬写过了,不过这里为了知识体系的完整,就再写一遍,并加入Maven Publish插件的使用,不感兴趣跳过就好。官方文档:Developing Custom Gradle Plugins在这。

插件的开发语言

官方说了,不管你用啥语言,只要最终能编译成JVM 字节码就行。不过一般使用Java,Kotlin,Groovy的居多,而静态语言类型的Java和Kotlin相对于Groovy性能更好。

插件打包的三种方式

Build Script

直接build script中编写插件的源代码。这样做的好处是插件会自动编译并包含在build script的classpath中,不用我们执行任何操作。但是,插件在build script之外是不可见的,所以不能在定义它的build script之外复用这个插件。

buildSrc project

将插件的源代码放在 rootProjectDir/buildSrc/src/main/java 目录(或 rootProjectDir/buildSrc/src/main/groovy 或 rootProjectDir/buildSrc/src/main/kotlin,具体取决于使用哪种语言)。 Gradle 负责编译和测试插件,并使插件在build script的classpath上可用。该插件对项目里的所有build script都是可见的。 但是对其它项目就不可见了,因此其它项目不能复用该插件。

有关 buildSrc 项目的更多详细信息,请阅读组织 Gradle 项目。

Standardalone project

为插件创建一个单独的项目(或单独的Module),最终编译并发布一个 JAR。通常来说,这个 JAR 可能包含一些插件,或者将几个相关的任务类捆绑到一个库中,或者两者的某种组合。

一般我们开发自定义插件,都是选择Standardalone project的方式居多,编译打包成JAR后,发布到Maven仓库(本地,远程,私有或公有都可以),以便提供给其它项目使用,这样的好处是方便复用,项目编译速度也会快一些。

编写一个简单的插件

创建 Gradle 插件,需要编写一个实现 Plugin 接口的类。 当插件应用于项目时,Gradle会自动创建插件类的实例并调用该实例的 Plugin.apply() 方法。 项目对象作为参数传递,插件可以使用它来配置项目。

在Build Script编写插件

下面的示例包含一个问候插件(GreetingPlugin类),它向项目添加了一个 hello 任务,用于输出一句问候的话。在CustomGradlePlugin Module的build.gradle脚本(groovy语言)中添加以下代码:


plugins {
    id 'maven-publish'
    id 'java-library'
    id 'kotlin'
}

//---------------------------------自定义插件----------------------------------
//添加一个名为GreetingPlugin的插件
class GreetingPlugin implements Plugin<Project> {
    void apply(Project project) {
        project.task('hello') {
            doLast {
                println 'Hello from the GreetingPlugin'
            }
        }
    }
}

// Apply the plugin
apply plugin: GreetingPlugin
//---------------------------------自定义插件----------------------------------


dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation "com.android.tools.build:gradle:3.5.0"
    implementation gradleApi()
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.5.30"
    implementation group: 'org.ow2.asm', name: 'asm', version: '7.2'
    implementation group: 'org.ow2.asm', name: 'asm-commons', version: '7.2'
}

publishing {
    publications {
        maven(MavenPublication) {
            groupId = 'com.nxg.plugin'
            artifactId = 'custom-plugin'
            version = '1.0.0'
            from components.java
        }
    }

    repositories {
        maven {
            // change to point to your repo, e.g. http://my.org/repo
            url = layout.buildDirectory.dir('repo')
        }
    }
}

java {
    sourceCompatibility = JavaVersion.VERSION_1_8
    targetCompatibility = JavaVersion.VERSION_1_8
}  

点击Sync Projects With Gradle File,就会生成一个名为hello的task,可以在右上角的Gradle页面查看。

通过Gradle Task 执行插件

双击或右键执行,即可在控制台看到对应的打印。

至此,一个简单的插件就完成了。

通过命令行执行插件

你可能想使用命令行执行插件,在Terminal中执行:sh gradlew -q hello./gradlew -q hello

Android Gradle plugin requires Java 11 to run. You are currently using Java 1.8.

你可能会遇到报错如下:


nxg:/home/work/AndroidStudioProjects/AndroidDevelopmentPractices/AndroidGradlePluginsSample$ sh gradlew -q hello

FAILURE: Build failed with an exception.

* Where:
Build file '/home/work/AndroidStudioProjects/AndroidDevelopmentPractices/AndroidGradlePluginsSample/app/build.gradle' line: 2

* What went wrong:
An exception occurred applying plugin request [id: 'com.android.application']
> Failed to apply plugin 'com.android.internal.application'.
   > Android Gradle plugin requires Java 11 to run. You are currently using Java 1.8.
     You can try some of the following options:
       - changing the IDE settings.
       - changing the JAVA_HOME environment variable.
       - changing `org.gradle.java.home` in `gradle.properties`.

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.

* Get more help at https://help.gradle.org

BUILD FAILED in 12s
nxg:/home/work/AndroidStudioProjects/AndroidDevelopmentPractices/AndroidGradlePluginsSample$ 
  

解决办法是进入设置界面修改Gradle JDK的版本为JDK 11。

但是笔者测试发现这样还不能解决问题,需要在项目根目录的gradle.properties文件中指定JAVA_HOME的路径。


//JDK路径可以在Setting--->Build,Exceution,Deployment--->Build Tools--->Gradle JDK中获取
org.gradle.java.home=/work/android/android-studio-4.0/android-studio/jre  

在buildSrc目录编写插件

新建buildSrc目录

在项目的根目录新建一个名为buildSrc的目录,注意名称一定要对。

新建build.gradle

由于新建的buildSrc什么都没有,显然是不能正常工作,此时需要手动建一个build.gralde文件,并填入以下代码:


plugins {
    //使用maven-publish插件
    id 'maven-publish'
    //使用java库,用于开发插件
    id 'java-library'
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation gradleApi()
}

publishing {
    publications {
        maven(MavenPublication) {
            groupId = 'com.nxg.plugin'
            artifactId = 'custom-plugin'
            version = '1.0.0'
            from components.java
        }
    }

    repositories {
        maven {
            // change to point to your repo, e.g. http://my.org/repo
            url = layout.buildDirectory.dir('repo')
        }
    }
}

java {
    sourceCompatibility = JavaVersion.VERSION_1_8
    targetCompatibility = JavaVersion.VERSION_1_8
}
//指定源码/资源路径
sourceSets {
    main {
        java {
            srcDir 'src/main/java'
            //srcDir 'src/main/kotlin'
        }
        groovy {
            srcDir 'src/main/groovy'
        }
        resources {
            srcDir 'src/main/resources'
        }
    }
}  

Sync Project With Gradle Files,buildSrc目录下就会生成.gralde和build目录。

新建源码目录

根据此路径rootProjectDir/buildSrc/src/main/java 目录(或 rootProjectDir/buildSrc/src/main/groovy 或 rootProjectDir/buildSrc/src/main/kotlin,具体是哪个路径要看你用的开发语言)新建对应的目录,在对应目录中新建自己的包。

右键buildSrc目录,New--->Directory,新建目录,由于build.gradle中已经配置了sourceSets,因此这里直接就提示出来了,双击对应的路径既可完成新建。

这里为了演示,Java,Kotlin,Groovy的目录都创建了,实际插件还是用的Java。

新建插件类

在对应开发语言的目录,创建插件的包名,再新建一个GreetingPlugin类实现Plugin<Project>接口,代码如下:


package com.nxg.plugins;

import org.gradle.api.Plugin;
import org.gradle.api.Project;

public class JavaGreetingPlugin implements Plugin<Project> {
    @Override
    public void apply(Project project) {
        System.out.println("JavaGreetingPlugin(buildSrc) ---> apply");
        project.task("hello").doLast(task -> System.out.println("Hello from the com.nxg.plugins.JavaGreetingPlugin(buildSrc)"));
    }
}
  

新建properties文件

同样右键buildSrc目录,New--->Directory,新建目录resources,然后按照以下路径:


resources/META-INF/gradle-plugins/com.nxg.plugins.greeting.properties  

建立对应的目录和properties文件。

xxx.properties文件,这里的xxx对应的插件id,com.nxg.plugins.greeting.properties的id就是com.nxg.plugins.greeting,通常用包名+插件名命名,或者用其他唯一标示都是可以的。id通常是在bulid.gradle中使用plugins依赖插件时用于指定插件。


plugins {
    id 'com.android.application'
    id 'kotlin-android'
    id 'com.nxg.plugins.greeting'
}  

com.nxg.plugins.properties的内容为:


implementation-class=com.nxg.plugins.JavaGreetingPlugin  

implementation-class=xxx,xxx填写插件的包名加类名。

官方原文说明如下:

Behind the scenes

So how does Gradle find the Plugin implementation? The answer is - you need to provide a properties file in the JAR’s META-INF/gradle-plugins directory that matches the id of your plugin, which is handled by Java Gradle Plugin Development Plugin.

Example: Wiring for a custom plugin

src/main/resources/META-INF/gradle-plugins/org.example.greeting.properties

implementation-class=org.example.GreetingPlugin

Notice that the properties filename matches the plugin id and is placed in the resources folder, and that the implementation-class property identifies the Plugin implementation class.

遇到的问题


Gradle sync failed: Entry META-INF/gradle-plugins/com.nxg.plugins.properties is a duplicate but no duplicate handling strategy has been set. Please refer to https://docs.gradle.org/7.0.2/dsl/org.gradle.api.tasks.Copy.html#org.gradle.api.tasks.Copy:duplicatesStrategy for details. (650 ms)  

看打印,先入为主的认为是properties文件重复导致了,找了一圈github,官方论坛,stackoverflow,尝试各种配置duplicatesStrategy,均无效。最后使用另外的项目来新建buildSrc,发现竟然成功了,对比后发现,是少了buildSrc里的build.gradle文件,再深入对比后发现是build.gradle里的maven-publish插件的问题,将插注释掉重新sync就好了(或者删除整个build.gradle也行,测试发现是可以的,不影响),buildSrc也用不到maven-publish。

使用插件

在app的build.gradle,使用以下方式依赖写好的自定义插件,其中id对应的值com.nxg.plugins.greeting,即是com.nxg.plugins.greeting.properties的文件名。


plugins {
    id 'com.android.application'
    id 'kotlin-android'
    id 'com.nxg.plugins.greeting'
}

// Apply the plugin,这两种方式都是支持的
//apply plugin: 'com.nxg.plugins.greeting'
  

插件的使用更详细的内容参考官方文档Using Gradle Plugins。

运行插件

添加好自定义插件的依赖后,点击Sync Projects With Gradle File,就会生成一个名为hello的task,可以在右上角的Gradle页面查看,同时Build控制台中也打印出apply方法的日志。

双击执行hello task,即可看到相关日志打印。

独立的自定义插件项目

Build Script和buildSrc的方式写插件虽然方便编译和调试,但却不能共享给多个项目使用。对于多项目开发的使用场景,将自定义的插件移动到一个独立的项目中,以便可以发布它并分享出去是一个更好的选择。

自定义插件项目的编译产物(Plugin Marker Artifact)通常是一个包含插件类的 JAR,而打包和发布插件的最简单且推荐的方法是使用Java Gradle Plugin Development Plugin。这个插件将自动使用Java Plugin,并且自动将gradleApi()依赖项添加到 api 配置中,且最终生成的 JAR 文件中会包含所需的插件描述符(com.nxg.plugins.greeting.properties),并配置发布时要使用的Plugin Marker Artifact。

新建Android Library Module

ModuleName和Package 根据需要修改,这里笔者选择Kotlin语言,Bytecode Level选择默认8。

删掉不必要的包和文件,最终的目录如下:

使用java-gradle-plugin插件

删除build.gradle里的内容,添加java-gradle-plugin插件,并配置插件id和实现类。


plugins {
    id 'java-gradle-plugin'
}

gradlePlugin {
    plugins {
        standaloneGradlePlugins {
            id = "greeting-standalone"
            implementationClass = 'com.nxg.plugins.GreetingStandaloneGradlePlugins'
        }
    }
}  

更多介绍,点击阅读java-gradle-plugin的使用。

新建插件类

根据以上插件配置,新建对应的插件类:


package com.nxg.plugins;

import org.gradle.api.Plugin;
import org.gradle.api.Project;

public class GreetingStandaloneGradlePlugins implements Plugin<Project> {

    private static final String TAG = "GreetingStandaloneGradlePlugins";

    @Override
    public void apply(Project project) {
        System.out.println("GreetingStandaloneGradlePlugins(standalone) ---> apply");
        project.task("helloStandalone").doLast(task -> System.out.println("Hello from the com.nxg.plugins.GreetingStandaloneGradlePlugins(standalone)"));
    }
}
  

一个简单的插件就完成了。

配置MavenPublish插件

使用maven-publish插件并配置如下:


plugins {
    id 'java-gradle-plugin'
    id 'maven-publish'
}

//定义Maven仓库信息
def MAVEN_GROUP_ID = "com.nxg.plugins"
def MAVEN_ARTIFACT_ID = "greeting-standalone"
def MAVEN_VERSION = "1.0.0"
def MAVEN_NAME = "repo"
def MAVEN_RELEASE_URL = "mavenLocal"
def MAVEN_USERNAME = ""
def MAVEN_PASSWORD = ""


gradlePlugin {
    plugins {
        standaloneGradlePlugins {
            id = MAVEN_ARTIFACT_ID
            implementationClass = 'com.nxg.plugins.GreetingStandaloneGradlePlugins'
        }
    }
}

publishing {
    publications {
        maven(MavenPublication) {
            groupId = MAVEN_GROUP_ID
            artifactId = MAVEN_ARTIFACT_ID
            version = MAVEN_VERSION
            from components.java
        }
    }

    repositories {
        maven {
            // change to point to your repo, e.g. http://my.org/repo
            url = layout.buildDirectory.dir(MAVEN_NAME)
        }
    }
}  

maven-publish插件入门和踩坑记录见:

Android Gradle Plugins系列-02-Maven Publish 插件入门指南

发布插件到maveLocal

配置好后,点击Sync Projects With Gradle File,即可在右上角的gradl task list中看到对应module的publish tasks。

双击执行publistoMavenLocal,即可发布插件的Artifact(构建产物)到本地Maven仓库,一般是在.m2(mavenLocal)目录中。

发布插件到指定目录

我想发布到指定目录行不行?当然可以。其实上面已经配置好路径了,url可以替换为自定义路径,笔者这里配置的是build目录的repo文件夹。


publishing {

    repositories {
        maven {
            // change to point to your repo, e.g. http://my.org/repo
            url = layout.buildDirectory.dir(MAVEN_NAME)
        }
    }
}
  

双击执行publish task,执行完毕后会在url配置的路径中生成插件的构建产物。

使用插件

插件的使用大同小异,不过要注意的是,发布的到mavenLocal的插件不能通过Gradle DSL(plugins{})或者apply直接使用,原因是插件的Artifact(构建产物)不在classpath中。

通过apply的方式使用插件需要在buildscript中指定本地maven仓库路径,并指定classpath,并且buildscript代码块要在plugins代码块之前声明,具体如下:


buildscript {
    repositories {
        mavenLocal()
    }
    dependencies {
        classpath 'com.nxg.plugins:greeting-standalone:1.0.0'
    }
}

plugins {
    id 'com.android.application'
    id 'kotlin-android'
    id 'com.nxg.plugins.greeting'
    //id 'com.nxg.plugins.greeting-standalone' version '1.0.0'
}

// Apply the plugin
apply plugin: 'greeting-standalone'
  

那我想通过plugins 指定id行不行?当然那行,将插件发布到JFrog Bintray即可。

那我不想发布,就想使用mavenLocal的插件呢?理论上应该可以,但是笔者按照官方文档测试,怎样修改的不行。

具体做法是在项目根目录中的settings.gradle中添加pluginManagement如下:


dependencyResolutionManagement {
    //repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        pluginManagement {
            repositories {
                mavenLocal()
                gradlePluginPortal()
            }
        }
        google()
        mavenCentral()
        mavenLocal()
    }
}

rootProject.name = "AndroidGradlePluginsSample"
include ':app'
include ':GradlePluginInBuildScript'
include ':StandaloneGradlePluginProject'
  

并且带上版本号:


plugins {
    id 'com.android.application'
    id 'kotlin-android'
    id 'com.nxg.plugins.greeting'
    id 'com.nxg.plugins' version '1.0.0'
}  

还是报错如下:


Build file '/home/work/AndroidStudioProjects/AndroidDevelopmentPractices/AndroidGradlePluginsSample/app/build.gradle' line: 16

Plugin [id: 'com.nxg.plugins.greeting-standalone', version: '1.0.0'] was not found in any of the following sources:

* Try:
Run with --info or --debug option to get more log output. Run with --scan to get full insights.

* Exception is:
org.gradle.api.plugins.UnknownPluginException: Plugin [id: 'com.nxg.plugins.greeting-standalone', version: '1.0.0'] was not found in any of the following sources:

- Gradle Core Plugins (plugin is not in 'org.gradle' namespace)
- Plugin Repositories (could not resolve plugin artifact 'com.nxg.plugins.greeting-standalone:com.nxg.plugins.greeting-standalone.gradle.plugin:1.0.0')
  Searched in the following repositories:
    MavenLocal(file:/home/lb/.m2/repository/)  

真的难搞哦。看下面的日志,很明显压根对不上啊。


Plugin [id: 'com.nxg.plugins.greeting-standalone', version: '1.0.0'] was not found in any of the following sources:
跟这个
Plugin Repositories (could not resolve plugin artifact 'com.nxg.plugins.greeting-standalone:com.nxg.plugins.greeting-standalone.gradle.plugin:1.0.0')
 再看看classpath
  classpath 'com.nxg.plugins:greeting-standalone:1.0.0'  

此问题留着以后有时间再看看吧。

插件的使用更详细的内容还是建议参考官方文档Using Gradle Plugins,多看看官方文档,顺便学学英语。

2022年02月10日新增

针对使用插件id apply 发布到mavenLocal的自定义插件失败的问题。目前已经找到问题所在,还是官方文档看得不仔细啊,摘抄关键文档如下:

Note for plugins published without java-gradle-plugin

If your plugin was published without using the Java Gradle Plugin Development Plugin, the publication will be lacking Plugin Marker Artifact, which is needed for plugins DSL to locate the plugin. In this case, the recommended way to resolve the plugin in another project is to add a resolutionStrategy section to the pluginManagement {} block of the project’s settings file as shown below.

Example 7. Resolution strategy for plugins without Plugin Marker Artifact

GroovyKotlin

settings.gradle


resolutionStrategy {         
    eachPlugin {             
        if (requested.id.namespace == 'org.example') {                 
            useModule("org.example:custom-plugin:${requested.version}")             
        }         
    }     
}  

原文链接:Developing Custom Gradle Plugins

就不翻译原文了,只说解决方案。如果使用 plugins DSL来定位插件,即以下面这种形式引用插件。


plugins {
    id 'com.android.application'
    id 'kotlin-android'
    id 'com.nxg.plugins.greeting'
    //如果本地没发布过该插件,需要先注释掉这里,插件发布后再打开注释
    id 'com.nxg.plugins.greeting-standalone' version '1.0.0'
}
  

但是编译出现Plugin [id: 'xxx.xxx.xxx', version: '1.0.0'] was not found in any of the following sources:的问题:


Build file '/home/work/AndroidStudioProjects/AndroidDevelopmentPractices/AndroidGradlePluginsSample/app/build.gradle' line: 16

Plugin [id: 'com.nxg.plugins.greeting-standalone', version: '1.0.0'] was not found in any of the following sources:

* Try:
Run with --info or --debug option to get more log output. Run with --scan to get full insights.

* Exception is:
org.gradle.api.plugins.UnknownPluginException: Plugin [id: 'com.nxg.plugins.greeting-standalone', version: '1.0.0'] was not found in any of the following sources:

- Gradle Core Plugins (plugin is not in 'org.gradle' namespace)
- Plugin Repositories (could not resolve plugin artifact 'com.nxg.plugins.greeting-standalone:com.nxg.plugins.greeting-standalone.gradle.plugin:1.0.0')
  Searched in the following repositories:
    MavenLocal(file:/home/lb/.m2/repository/)  

那就需要在项目的根目录的setting.gradle(setting.gradle.kts)中根据插件的namespace指定完整的插件信息,包含id和version。

完整的setting.gradle示例代码如下:


pluginManagement {
    resolutionStrategy {
        eachPlugin {
            println("resolutionStrategy eachPlugin ${requested.id.namespace}")
            if (requested.id.namespace == 'com.nxg.plugins') {
                useModule("com.nxg.plugins:greeting-standalone:${requested.version}")
            }
        }
    }

    repositories {
        mavenLocal()
        gradlePluginPortal()
    }
}
dependencyResolutionManagement {
    //repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        google()
        mavenCentral()
        mavenLocal()
    }
}

rootProject.name = "AndroidGradlePluginsSample"
include ':app'
include ':GradlePluginInBuildScript'
include ':StandaloneGradlePluginProject'
  

以上代码已经提交到代码仓库:https://github.com/xiangang/AndroidDevelopmentPractices/tree/master/AndroidGradlePluginsSample

注意,别忘了先把插件通过maven-pulish插件的publish task 发布到mavenLocal。

写在最后,首先非常感谢您耐心阅读完整篇文章,坚持写原创且基于实战的文章不是件容易的事,如果本文刚好对您有点帮助,欢迎您给文章点赞评论,您的鼓励是笔者坚持不懈的动力。若文章有不对之处也欢迎指正,再次感谢。

学如逆水行舟,不进则退;心似平原走马,易放难追。

参考资料

Developing Custom Gradle Plugins

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Android Gradle Plugins系列-01-自定义Gradle插件入门指南 的相关文章

  • Sqlite 查询检查 - 小于和大于

    return mDb query DATABASE TABLE new String KEY ROWID KEY LEVEL KEY LEVEL gt 3 lt 5 null null null null 我究竟做错了什么 它返回的值全部高
  • 如何使用 (a)smack 在 Android 上保持 XMPP 连接稳定?

    我使用适用于 Android 的 asmack android 7 beem 库 我有一个后台服务正在运行 例如我的应用程序保持活动状态 但 XMPP 连接迟早会在没有任何通知的情况下消失 服务器表示客户端仍然在线 但没有发送或接收数据包
  • Android,让文本切换器成为中心?

    如何集中我的文本切换器 我尝试过设置重力 但似乎不起作用 ts setFactory new ViewFactory public View makeView TextView t new TextView this t setTypefa
  • 相当于Android中的javax.swing.Timer

    有没有类似的东西javax swing Timer在安卓上 我知道如何创建自己的线程 但是有类似摆动计时器的东西吗 您可能正在寻找课程android os CountDownTimer http developer android com
  • Android 上通过 JSCH 的基本 SSH 连接

    作为来自此的用户question https stackoverflow com questions 14323661 simple ssh connect with jsch和这个tutorial http eridem net andr
  • 不使用 CookieManager 的 Android 会话 cookie

    我的应用程序进行多次网络调用以获得身份验证 我需要将此会话存储在 cookie 中 我想使用 Cookie Manager 但经过一些研究后 我发现它仅适用于 API 9 及更高版本 并且我的应用程序需要向后兼容 我使用 HTTPURLCo
  • PhoneGap 是应用程序开发的好选择吗? [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • 将寻呼机视为列表视图行项目

    我有一个包含 20 行的列表视图 我想为列表视图中的每一行设置一个视图寻呼机 由于列表视图的行中的项目可能是一个或多个 并且我想使用视图分页器显示列表视图行项目 为此 我使用以下代码 将显示在列表视图行中的自定义布局 作为分页器项目
  • 在 Android 中关闭 Spinner 中的下拉菜单

    在 Android 中打开和关闭微调器时 我需要为箭头图标设置动画 打开微调器时我可以旋转箭头 我只是放了一个setOnTouchListener on the Spinner 当下拉菜单关闭或隐藏时 问题就来了 因为我不知道如何在该操作上
  • 使用 POST 将数据从 Android 发送到 AppEngine Datastore

    抱歉 如果这是一个简单的问题 但我只是不知道我应该做什么 而且我认为我有点超出了我的深度 我想将数据从 Android 应用程序发送到在 Google App Engine 上运行的应用程序 数据必须从那里写入数据存储区 我的数据主要采用对
  • 安卓;在 AdapterViewFlipper 上设置输入/输出动画:未知的动画师名称翻译

    我有一些非常简单的动画 可以与 ViewFlipper 完美配合 但如果我尝试在 AdapterViewFlipper 输入 输出上设置它们 我会收到运行时错误 未知的动画师名称翻译 查看每个方法的相应方法 看起来 ViewFlipper
  • 使用startActivityForResult,如何获取子活动中的requestCode?

    我有四项活动 即 A B C 和 D 我的情况是A将通过startActivityForResult启动活动B startActivityForResult new Intent this B class ONE 在另一种情况下 我将使用不
  • NoClassDefFoundError:com.google.firebase.FirebaseOptions

    我继续得到NoClassDefFoundError在我正在使用的其他测试设备 4 4 2 上 但在我的测试设备 Android 5 1 上运行良好 我尝试了用谷歌搜索的解决方案 但似乎没有任何效果 我正在使用 Firebase 实时数据库
  • UnsupportedOperationException:特权进程中不允许使用 WebView

    我在用android sharedUserId android uid system 在我的清单中获得一些不可避免的权利 从 HDMI 输入读取安卓盒子 http eweat manufacturer globalsources com s
  • 改造Android基本且简单的问题

    我的服务器返回简单的 Json 结果 如下所示 message Upload Success 我正在尝试将结果放入改造模型类中 public class MyResponse SerializedName message String me
  • Android 将菜单项在操作栏中向左对齐

    我的应用程序中有一个操作栏 它显示我定义的菜单项res menu activity main xml 我的菜单项在操作栏上向右对齐 我希望它们左对齐 我为此找到的唯一解决方案使用了自定义操作栏 如下所示 将菜单项放置在 Honeycomb
  • 使用 Tomcat 和 gradle 进行休眠

    免责声明 我是 Java 新手 我正在尝试使用 Tomcat 和 Gradle 设置 Hibernate 构建运行正确 但看起来像persistence xml文件未被读取 我的项目结构如下 build gradle src main ja
  • 如何用 XML 制作双渐变(类似 iphone)

    如何使用 XML 制作这种可绘制渐变 我可以做一个从颜色 A 到颜色 B 的简单渐变 但我不知道如何在同一个可绘制对象中组合两个渐变 我终于找到了一个带有图层列表的解决方案 这对我来说已经足够好了
  • TYPE_ACCELEROMETER 和 TYPE_LINEAR_ACCELERATION 传感器有什么区别?

    I think TYPE ACCELEROMETER显示设备加速 但是 我不明白什么时候应该使用TYPE LINEAR ACCELERATION 我需要计算移动设备的速度 哪种传感器适合此应用 另外 我读到TYPE LINEAR ACCEL
  • Android:列“_id”不存在

    我收到这个错误 IllegalArgumentException 列 id 不存在 当使用SimpleCursorAdapter从我的数据库中检索 该表确实有这个 id柱子 注意到这是一个常见问题 我尝试根据网上的一些解决方案来解决它 但它

随机推荐

  • 【数字图像处理】直方图均衡化详解及编程实现

    直方图均衡化的英文名称是Histogram Equalization 图像对比度增强的方法可以分成两类 一类是直接对比度增强方法 另一类是间接对比度增强方法 直方图拉伸和直方图均衡化是两种最常见的间接对比度增强方法 直方图拉伸是通过对比度拉
  • 【GPU编程】体绘制传输函数-分类(Volume Rendering Transfer function:Pre- VS Post-Classification)

    在科学可视化中 xff0c 我们所获得的体数据集经常是代表一些光学上的不同物理属性的单值 通常没有可行的方法可以从这样的数据中获得发射和吸收属性 因此用户必须采用某种映射方法给数据值分配光学属性值来决定数据中的不同结构的模样 这离的映射就被
  • 【OpenGL】理解GL_TRIANGLE_STRIP等绘制三角形序列的三种方式

    GL TRIANGLE STRIP绘制三角形方式很多时候令人疑惑 xff0c 在这里对其运作机理进行解释 一般情况下有三种绘制一系列三角形的方式 xff0c 分别是GL TRIANGLES GL TRIANGLE STRIP和GL TRIA
  • OpenJDK与JDK的区别分析

    OpenJDK与JDK的区别分析 一 以下是具体分析 xff1a 使用过LINUX的人都应该知道 xff0c 在大多数LINUX发行版本里 xff0c 内置或者通过软件源安装JDK的话 xff0c 都是安装的OpenJDK xff0c 那么
  • 【C++深入探索】Copy-and-swap idiom详解和实现安全自我赋值

    任何管理某资源的类比如智能指针需要遵循一个规则 xff08 The Rule of Three xff09 xff1a 如果你需要显式地声明一下三者中的一个 xff1a 析构函数 拷贝构造函数或者是拷贝赋值操作符 xff0c 那么你需要显式
  • 【Linux】Vim编辑器-批量注释与反注释

    vim编辑器 批量注释与反注释 在使用vim编写代码的时候 xff0c 经常需要用到批量注释与反注释一段代码 下面简要介绍其操作 方法一 块选择模式 插入注释 xff1a 用v进入virtual模式 用上下键选中需要注释的行数 按Contr
  • 【算法学习】图相关算法编程实现-深度优先遍历和广度优先遍历

    一 图的表示 图G 61 V E 要表示一个图 xff0c 通常有两种方法 xff1a 邻接表和邻接矩阵 两种方法都既可以表示有向图 xff0c 也可以表示无向图 邻接表表示由一个包含 V 个列表的数组组成 xff0c 其中每个列表对应V中
  • 【笔试面试题】腾讯2013实习生面试算法题及参考答案

    总结了一下自己遇到的以及同学遇到的面试算法题 xff0c 是技术二面 有几道题给出了参考答案 xff0c 还有几道没有好的思路 路过的大侠如果有好的思路请留个言交流下呗 1 八数码问题 xff1a 3 3的格子 xff0c 有1 8个数 x
  • 【Linux学习】epoll详解

    什么是 epoll epoll 是什么 xff1f 按照 man 手册的说法 xff1a 是为处理大批量句柄而作了改进的 poll 当然 xff0c 这不是 2 6 内核才有的 xff0c 它是在 2 5 44 内核中被引进的 epoll
  • 算法设计应该依赖抽象而不是业务

    很多时候 xff0c 算法的设计是归属于详细设计阶段的 一些公司甚至都没有设计而直接编码 这些往往导致很多算法的实现都混杂在业务模块中 典型的特点是 xff0c 这些算法会依赖于业务实体的某些属性的实现 举一个简单的例子 xff0c 我曾经
  • 做程序员老婆的幸福

    刚好看网上一个写程序员老公的 说说程序员老公的一些事情 请帮忙分析是不是典型程序员 xff0c 想起自己就是一个程序员 xff0c 也是一个老公 xff0c 却不以为然起来 虽然不以为然 xff0c 却并没有驳斥的任何意思 毕竟很多人都不一
  • 好习惯成就好程序员

    公司搞了一次技术峰会 xff0c 我有机会和大家聊了一下有关如何成功的问题 会上我向大家提出了我的想法 xff0c 好习惯才能成就好程序员 有很多人可能对这句话很不以为然 xff0c 我也不忙辩解 xff0c 先回答我下面的一个问题 现在我
  • 程序江湖:第三章 莫等闲白了少年头

    周五因为羽毛球比赛 xff0c 没有更新 xff0c 今天继续 读者反馈 xff1a 很多读者反馈主人公的名字比较土 呵呵这个没关系 xff0c 可以在整理的时候统一修改 另外有些人表示特别希望看到职场的故事 xff0c 这个放心 本就是这
  • 程序江湖:第二十章 讲标的前一晚上

    说明 xff1a 非常抱歉 xff0c 这周参加了太多的会议 原来写作也是需要心情的 xff0c 当没有心情的时候 xff0c 你都懒得动笔 欧阳明来到云南的最主要的目的 xff0c 是为了应对昆明客户要求的评标 就是客户邀请了几家资质还可
  • springboot项目搭建

    一 Springboot 基本概念 1 1 什么是 springboot Spring Boot是由Pivotal团队提供的全新框架 xff0c 其设计目的是用来简化新Spring应用的初始搭建以及开发过程 该框架使用了特定的方式来进行配置
  • 管理 VS. 面向对象设计

    我是在吃虾的时候 xff0c 突然想起这个关联的 管理 xff0c 往往就是给你一堆事 xff0c 然后再给你一些人 xff0c OK xff0c 你去做吧 这是你的使命 下面我们来做类比吧 首先一个问题 xff0c 你是认为人重要 xff
  • 技术管理案例:代码规范还要继续推行吗?

    这是实际工作中总结的一个典型案例 是真实的 写出来供大家参考 案例 xff1a 技术经理 Y 今年新到了一个产品部门 xff0c 发现原来产品的代码很乱 xff0c 遗留的问题很多 而现有的人员 xff0c 又大半是新招的 xff0c 很多
  • 苹果成功的根本:统筹创新

    这周的某天中午 xff0c 我们聊起了这个话题 xff0c 是关于苹果为什么成功的话题 很多人都说是因为苹果的创新能力很强 但是诺基亚也不缺乏创新啊 xff01 为什么苹果就能胜出呢 xff1f 我个人认为这有很多方面是因为乔布斯 xff0
  • 建立健康的职业发展观

    Google的Reader要下线了 xff0c 很多人都说这是因为Blog的没落 微博的兴起 xff0c 确实给了很多人表达情绪的方式 如果我能够用140个字 xff0c 清晰的表达我的观点 xff0c 并且能够让我的读者做到一点点认可 x
  • Android Gradle Plugins系列-01-自定义Gradle插件入门指南

    前言 本文内容已经有很多大佬写过了 xff0c 不过这里为了知识体系的完整 xff0c 就再写一遍 xff0c 并加入Maven Publish插件的使用 xff0c 不感兴趣跳过就好 官方文档 xff1a Developing Custo