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插件入门指南 的相关文章

  • 如何减少Android中CheckBox的宽度和高度

    谁能告诉我如何减少 CheckBox 的宽度和高度 以便在 Android 中显示非常小的 CheckBox 提前致谢 只需像使用普通按钮一样使用 setWidth w 和 setHeight h 函数即可
  • 如何在 Android 上为 Facebook 的应用程序制作新菜单? [复制]

    这个问题在这里已经有答案了 可能的重复 Android facebook 风格幻灯片 https stackoverflow com questions 8657894 android facebook style slide 最近 Fac
  • 进度条中形状的填充

    我正在使用 xml 文件来定义进度条 我在背景形状上定义了填充 但这个设置有时会正确显示 有时则不能 因此 如果我启动内部带有进度条的应用程序或活动 则会正确显示带有背景和 填充 进度的进度条 然后我关闭我的应用程序并再次启动它 并且 进度
  • Phonegap(3.0.0) 相机第一次尝试不成功

    出于测试目的 我复制了在音隙相机 API http docs phonegap com en 3 0 0 cordova camera camera md html Camera我发出警报onPhotoDataSuccess测试函数何时被触
  • android 弹出菜单文本颜色(AppCompat)

    我需要更改 popuo 菜单的文本颜色 但我找不到任何方法来执行此操作 我可以更改 popomenu 的背景但不能更改文本 我以这种方式编辑 style xml
  • 如何处理 Jetpack Compose 中的导航?

    在 Jetpack Compose 中 导航应该如何完成 所有 并不多 示例 包括来自 Google 的官方示例 都使用密封类并加载新屏幕以响应观察当前屏幕的变化 这确实 有点 有效 但不提供导航返回堆栈 并且手机的后退按钮完全不知道 只是
  • 华为移动服务的 Android 虚拟设备

    我想将HMS应用到我的应用程序中 然而 购买真正的华为手机并不在我的候选清单上 华为是否为此目的提供 Android 虚拟设备 如果没有 如何测试我的 HMS 实现是否真正有效 是的 华为确实提供了一个 Android 虚拟设备 名为App
  • ZipResourceFile 无法解析为类型

    我正在尝试重写我的应用程序以使用 APK 扩展文件 我一直在关注这里的文档http developer android com google play expansion files html http developer android
  • 呼叫转移

    我想将所有拨打我号码的呼叫转接至新的预定义号码 自动地 可以转接来电吗 也许至少对于 Froyo 来说是可能的 我找到了名为 Easy Call Forwarding 的应用程序 http www appstorehq com easyca
  • Android.system.ErrnoException:isConnected失败:ECONNREFUSED(连接被拒绝)

    我使用Java连接MySQL和Json将数据发送到android 当我通过URL地址将数据从Java发送到json时 http 192 168 1 221 9999 rentalcar service category getAllManu
  • Android接收短信Intent:获取消息Id或线程Id

    我已经注册了一个广播监听器来接收android provider Telephony SMS DELIVER意向行动 我似乎能够获取这条新消息的正文和发件人电话号码 但是我无法获取此新消息的消息 ID 或线程 ID 我发现的唯一方法是搜索消
  • 在不同的活动上显示 OnItemClickListener 的结果

    我使用 OnItemClickListener 从列表视图中选择一个项目 如下所示 listView setTextFilterEnabled true final TextView disp TextView findViewById R
  • 在包“android”中找不到属性“roundIcon”的资源标识符

    我正在尝试编译我的项目 但出现一些错误 Android 清单 xml
  • 返回 RxJava 的 Completable 的方法的命名约定

    我有一个带有视图类的 Android 应用程序 Fragment Activity 观察其ViewModel The ViewModel公开方法 例如getUserName返回Observable
  • 无法在android中使用retrofit发出@Post请求

    我正在学习如何在 android 中使用改造 但是每当我尝试从互联网检索数据时 我的应用程序不会返回任何内容我的响应没有成功 我不知道如何修复当前我正在尝试发布的错误并使用此 URL 检索数据https jsonplaceholder ty
  • 如何在不打开浏览器的情况下查看 Android 应用程序中的网页?

    嘿 我正在开发一个 Android 应用程序 我想连接到该应用程序内的网络 不过 我在某种程度上尝试过 WebView 但它在我的目录中显示的文件很好 但当连接到 google com 时 它显示错误 然后我添加了这个文件
  • 在大画布上滚动

    我需要一些帮助来了解滚动绘制到 Android 画布上的项目的基础知识 假设我想创建一个时间线 其中 0 处的时间是可视化的顶部 并且随着时间的增加 时间线继续呈现在上一个点下方 如果我想在 Android 上渲染它 我知道我可以通过重写
  • 使用 OnContextItemSelected 从 ListView 项目中检索文本

    我有一个带有 经典 上下文菜单的 ListView 其中包含删除和类似选项 由于我要从 SharedPreferences 对象中删除 因此我需要检索键 即设置到 ListView 项目中的文本 我尝试过以下代码 Override publ
  • 与桌面浏览器相比,移动浏览器有多强大? [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • 只有创建视图层次结构的原始线程才能触摸其视图。在安卓上[重复]

    这个问题在这里已经有答案了 我只是一个初学者 所以请原谅我问一个可能愚蠢的问题 我不明白只有创建视图层次结构的原始线程才能触摸其视图的含义 请有人告诉我为什么会发生此错误以及如何解决此问题 ThankYou 这是我的班级 public cl

随机推荐

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

    直方图均衡化的英文名称是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