I have some code snippets below when I use android databinding framework with ViewStub.
ItemPostBinding binding=ItemPostBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false);
final Post post = mDataset.get(position);
binding.stub.getViewStub().setLayoutResource(App.getPostExtensionManager().getLayout(post.getExtension()));
I kown binding.stub will be replaced with ViewStubProxy when codes compiled. But how could I ask Android Studio to ignore the error here before compiling?
(The error is Android Studio cannot resolve getViewStub() method from class ViewStub)
UPDATE 1
I don't know if it was due to my old approach of using android data-binding framework.
classpath 'com.android.databinding:dataBinder:1.0-rc4' // project build.gradle
apply plugin: 'com.android.databinding' // module build.gradle
But with the new method mentioned in the official data-binding guide, all you need to do is adding the settings below in your module's build.gradle file.
android {
....
dataBinding {
enabled = true
}
}
And the error inspections mentioned above is gone, you can even directly use binding.stub without any problem.
binding.stub.setLayoutResource(...)
binding.stub.inflate()
...
UPDATE 2
You can use binding.stub.someViewStubMethod() directly but it will fail while compiling. You still need to use binding.stub.getViewStub().someMethod(). However, just recently the error inspections is gone somehow no matter which method you add data-binding into your project by.
You are not suppose to call getViewStub method this way. binding.stub is already the ViewStub which you put in your layout item_post. You should call binding.stub.setLayoutResource()
Android Studio can't recognize ViewStubProxy correctly. Just cast it before manipulate.
import android.databinding.ViewStubProxy;
...
ViewStubProxy viewStubProxy = (ViewStubProxy)(Object)mBinding.viewStub;
if (!viewStubProxy.isInflated()) {
viewStubProxy.getViewStub().inflate();
}
Error is gone :)
Related
On Gradle 6.1.1, how to go around adding sourceSets for android project?
The answer on other questions doesn't work anymore, getByName("name") returns error with SourceSet with name 'main' not found.
The official document said to use
sourceSets {
main {
java {
srcDir("thirdParty/src/main/java")
}
}
}
However, there are over 20 main that has to be imported and I'm not sure which one is correct.
I'm using gradle 6.5.1, however documentation suggest, that is should also work for you, try:
sourceSets {
named("main") {
java.srcDir("../buildSrc/src/main/java")
}
}
It's also works for build types (debug/release), flavours etc.
Reason for this is that groovy can somehow interpret itself and knows main etc., but on gradle kts, you have call it using named for already existing, or getByName, create etc. base on need.
Similiar situation is for implement and api in groovy you can just use implementationDebug to attach it only for debug version, but in kotlin dsl you have to call it as a string "implementationDebug", because there is no such function
----- PS -----
If named, getByName not works for you, then try to experiment with findByName and create
What I'm trying to achieve
I'm trying to generate my REST API client for Android using OpenAPI Generator from the build.gradle script. That way, I wouldn't have to run the generator command line every time the specs change. Ideally, this would be generated when I build/assemble my app, and the sources would end up in the java (generated) folder, where generated sources are then accessible from the code (this is what happens with the BuildConfig.java file for example).
What I've tried so far
Following this link from their official GitHub, here's the build.gradle file I ended up with:
apply plugin: 'com.android.application'
apply plugin: 'org.openapi.generator'
...
openApiValidate {
inputSpec = "$rootDir/app/src/main/openapi/my-api.yaml"
recommend = true
}
openApiGenerate {
generatorName = "java"
inputSpec = "$rootDir/app/src/main/openapi/my-api.yaml"
outputDir = "$buildDir/generated/openapi"
groupId = "$project.group"
id = "$project.name-openapi"
version = "$project.version"
apiPackage = "com.example.mypackage.api"
invokerPackage = "com.example.mypackage.invoker"
modelPackage = "com.example.mypackage.model"
configOptions = [
java8 : "true",
dateLibrary : "java8",
library : "retrofit2"
]
}
...
First, I've never managed to get the API generated with the build/assemble task, even when I tried adding:
compileJava.dependsOn tasks.openApiGenerate
or
assemble.dependsOn tasks.openApiGenerate
The only way I could generate the sources was by manually triggering the openApiGenerate task:
Then, when I do generate my sources this way, they end up in the build folder but aren't accessible from my code, and aren't visible in the java (generated) folder:
I then have to manually copy/paste the generated source files to my project sources in order to use the API.
Even though I'm able to work around these issues by adding manual procedures, it would be way more maintainable if the whole process was simply automatic. I was able to achieve a similar result with another tool, Protobuf. Indeed, my gradle task gets triggered every time I build the app, and the sources end up in the java (generated) folder, so I don't have to do any additional work. The task is much simpler though, so I assume the main work that I'm not able to replicate with OpenAPI Generator is handled by the Protobuf plugin itself.
You have to specify path to the generated sources as a custom source set for your Gradle module, which is app in this case, as described here – https://developer.android.com/studio/build/build-variants#configure-sourcesets. That way Gradle will treat your sources as accessible from your code.
Something like this:
android {
...
sourceSets {
main {
java.srcDirs = ['build/generated/openapi/src/main/java']
}
}
...
}
I solved the issue you described like this, I'm using gradle.kts however.
See my build.gradle.kts
plugins {
// Your other plugins
id("org.openapi.generator") version "5.3.0"
}
openApiGenerate {
generatorName.set("kotlin")
inputSpec.set("$rootDir/app/src/main/openapi/my-api.yaml")
outputDir.set("$buildDir/generated/api")
// Your other specification
}
application {
// Your other code
sourceSets {
main {
java {
// TODO: Set this path according to what was generated for you
srcDir("$buildDir/generated/api/src/main/kotlin")
}
}
}
}
tasks.compileKotlin {
dependsOn(tasks.openApiGenerate)
}
You need to build the application at least once for the IDE to detect the library (at least this is the case for me in Intellij)
Your build should automatically generate the open api classes , to refer the generated classes in your java project you should add the generated class path to your source directory like it was mentioned in the other answers
https://developer.android.com/studio/build/build-variants#configure-sourcesets
As far as the task dependency goes , in android tasks are generated after configuration thus for gradle to recognize the task , wrap it inside afterEvaluate block like
afterEvaluate {
tasks.compileDebugJavaWithJavac.dependsOn(tasks.openApiGenerate)
}
I had this issue, and this answer https://stackoverflow.com/a/55646891/14111809 led me to a more informative error:
error: incompatible types: Object cannot be converted to Annotation
#java.lang.Object()
Taking a look at the generated files that were causing this error, noticed:
import com.squareup.moshi.Json;
After including a Moshi in the app build.gradle, the build succeeded and the generated code was accessible.
implementation("com.squareup.moshi:moshi-kotlin:1.13.0")
I am trying to implement custom lint checks (using Kotlin). I have set up a module for my custom checks and added classes to test my first lew lint check, mostly following these two tutorials here and here.
So I now have a module, I have a custom IssueRegistry, I've created an issue and a Detector class for it. So far it seems complete. I've added a test to check if my lint check works and it looks alright.
I have added my module to the project by referencing it in settings.gradle like this: include ':app', ':somemodule', ':mylintmodule'
Now if I run the linter using ./gradlew lint I get a lint result file telling me this:
Lint found an issue registry (com.myproject.mylintmodule) which requires a newer API level. That means that the custom lint checks are intended for a newer lint version; please upgrade
Lint can be extended with "custom checks": additional checks implemented by developers and libraries to for example enforce specific API usages required by a library or a company coding style guideline.
The Lint APIs are not yet stable, so these checks may either cause a performance degradation, or stop working, or provide wrong results.
This warning flags custom lint checks that are found to be using obsolete APIs and will need to be updated to run in the current lint environment.
It may also flag issues found to be using a newer version of the API, meaning that you need to use a newer version of lint (or Android Studio or Gradle plugin etc) to work with these checks.
To suppress this error, use the issue id "ObsoleteLintCustomCheck" as explained in the Suppressing Warnings and Errors section.
So it tells me that I am using a newer API verion in my custom lint check, right? This is my custom IssueRegistry (minus some parts not relevant for this problem):
class MyCustomIssueRegistry : IssueRegistry() {
override val issues: List<Issue>
get() = listOf(ISSUE_NAMING_PATTERN)
override val api: Int = com.android.tools.lint.detector.api.CURRENT_API
override val minApi: Int = 1
}
From googling this problem and finding this issue I figured I have to override and set the right API version (and maybe the min API?) by overriding these properties like I did above (this version is my last attempt, directly taken from that issue).
So this property can be set to values between -1 and 5, meaning this (taken right out of the lint.detector.api class):
/** Describes the given API level */
fun describeApi(api: Int): String {
return when (api) {
5 -> "3.5+" // 3.5.0-alpha07
4 -> "3.4" // 3.4.0-alpha03
3 -> "3.3" // 3.3.0-alpha12
2 -> "3.2" // 3.2.0-alpha07
1 -> "3.1" // Initial; 3.1.0-alpha4
0 -> "3.0 and older"
-1 -> "Not specified"
else -> "Future: $api"
}
I have tried all of them, plus the one above adding a minApi override too, and I keep getting the exact same result for each of them.
Also I am unable to locate what other API version this is compared with. Is there a place where this is set for the regular linter in an Android project?
It's also unclear to me what I have to do to make sure my changes got applied - is it enough to change some code, then run lint, or do I have to compile the project first, or build & clean?
Following the tutorials, I added my custom lint check by adding this to the app's build.gradle: lintChecks project(":mylintmodule")
Is that even right? The API issue on my registry class shows up no matter if my lint check is referenced (and hopefully used) like that or not. I have also tried the other method described in the first tutorial, adding this task to the linter module build.gradle:
defaultTasks 'assemble'
task copyLintJar(type: Copy) {
description = 'Copies the lint jar file into the {user.home}/.android/lint folder.'
from('build/libs/')
into(System.getProperty("user.home") + '/.android/lint')
include("*.jar")
}
// Runs the copyLintJar task after build has completed.
build.finalizedBy(copyLintJar)
But since I can't figure out how to see if my custom checks are actually run, I don't know if that works as intended either.
So how do I get this warning resolved (since I interpret the text as "As long as the versions don't match I will not try to run your lint check"), and how can I make sure my lint check is actually run by the linter?
I'm trying to use data-binding with Android.
I can not anymore build my project. I got this error :
"Error:(13, 46) error: package ch.company.project.databinding does not
exist"
Here my gradle :
http://pastebin.com/dkXd1Mxr
and
http://pastebin.com/n9hkFWGQ
And here the gradle output :
https://pastebin.com/w93Rausg
Thanks to Yigit!
The issue was not directly link to Android Databinding.
There were a bug in the project (some variables not correctly setted)
I would recommend to use gradle with "--debug and --stacktrace" for more informations, it's helping a lot.
earlier my package name was "com.xyz.abc.Models"
changing the package name to all small letters "Models" -> "models"
solved the issue.
The bug is not the DataBinding Package, it's a syntactic or logical error. For example, you have the attribute "lastName" in your POJO, but in the layout it's android:text="#{user.lastname}".
Check your "layout" and do Rebuild Project.
I am not satisfied with accepted answer, that tell you to stack trace without hints.
Here are some possible causes that lead to this problem. Check if you are not doing any of the following.
Basically Android DataBinding is not that mature still. It will fail without appropriate errors many times.
So if you have an issue like package ch.company.project.databinding does not exist".
Possible causes of fail:
First of all check your recently edited layouts xml one by one for errors (for wrong imports & variables). I don't get proper error in this case usually.
Check your data binding syntax in binding block ({...}) in layout element for errors. Always Rebuild (not Build) project after working in one layout.
Check your #BindingAdapter method having correct parameters. For example imageUrl binding adapter would accept ImageView or View as first parameter.
You should always Rebuild project after doing work in one layout.
If you are not able to find errors by above steps, then try --debug and --stacktrace in compile option of
File> Settings> Build, Execution, Deployment> Compiler> Command-line Options
Make sure your package name start with lowercase letter.
in my case issue solved after two hours of struggle
Package name should start with small letter.
for example Activities is wrong it'll give an error instead refactor->rename to activities
I got the error:
Error:(9, 46) error: package com.company.www.bar.databinding does not
exist.
i just remove "=" sign . it worked for me
From this :
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="#={()->activity.onButtonClick()}"/>
to :
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="#{()->activity.onButtonClick()}"/>
I had similar problems with my project
You could try:
check xml files for errors that cause a build failure
clean project
File -- invalidate caches / restart
On my particular case, I was using Dagger 2. This package error appears in a lot of classes without any relation with the original error: a dependency injection error.
Happy reminder: Scroll more on your stacktrace to know what is the real problem.
I was stuck with same error for hours. After trying several solution from stackoverflow, I updated my project with stable gradle dependencies.
Still it was not solved, however with the same gradle dependency DataBinding was working fine in another project of mine.
So, I went project folder using explorer and Deleted 2 things.
build folder
all files from .idea/libraries
After that i synced the project and it continued to work just fine.
Package names have to START with Small Letters. Otherwise, Binding library cannot understand that is it class or package. Moreover, you do NOT need to do all of it with small letters.
Example, wrong usage:
package com.thecompany.activity.ContactInfo; //Problem is ContactInfo, 'C'.
Example, TRUE usage:
package com.thecompany.activity.contactInfo; //Solution is contactInfo, 'c'.
Make sure your model's fields you reference in layout have public access modifiers
Change
{ databinding = true}
to
buildFeatures{
dataBinding = true
}
If you're coming to this question because you switched to JDK11 in Android Studio Artic Fox and your view binding broke in the UI but not during execution then be aware that this is a known issue and should be resolved in Bumble Bee:
https://issuetracker.google.com/issues/180946610
The current fix is to switch back to JDK8 (or install the Bumble Bee canary release).
To get rid of this error just enclose your complete layout design inside a plain layout tag in the activity_main.xml file.
After wasting many hours in finding solution this worked for me. Give it a try.
if you tried this steps
invalidate/restart`
keeping this properties in gradel.properties
android.databinding.enableV2=false
android.enableExperimentalFeatureDatabinding=true
and checking all xml files looks good.
then you should go with this solution, add below code in project level build.gradle
allprojects {
gradle.projectsEvaluated {
tasks.withType(JavaCompile) {
options.compilerArgs << "-Xmaxerrs" << "1000"
}
}
}
this will give you exact error where you have actual error
explanation: above code will increase the size of the compile error
in my case, i follow the android documentation :
buildFeatures {
viewBinding true
}
use "=" instead of space
buildFeatures {
viewBinding = true
}
Try following Refactor -> migrate to androidx
and in the build.grade(:app)
implementation 'androidx.appcompat:appcompat:1.0.0'
or use new version is released
implementation 'androidx.databinding:databinding-runtime:4.1.0'
Make sure that if your layout filename is named in the following format: <name>_activity.xml that your binding class name complies the following format as well: <name>ActivityBinding
For me, changing my layout filename from activity_login.xml to login_activity.xml resolved this issue because my binding class name was LoginActivityBinding.
Here's an except from the Android Layouts and binding expressions page mentioning this:
A binding class is generated for each layout file. By default, the name of the class is based on the name of the layout file, converting it to Pascal case and adding the Binding suffix to it. The above layout filename is activity_main.xml so the corresponding generated class is ActivityMainBinding
if you use a model in your layout, make sure you dont have the model and the package named same and also the paackage name should start with small letter.
i changed mine from Model>Model.class to modelPac>Model.class
In my case the problem appeared when I was creating productFlavors and set sourceSets.
Changing
sourceSets {
develop {
res.srcDirs = ['myApp/src/develop/res']
}
to
sourceSets {
develop {
res.srcDirs = ['src/develop/res']
}
}
solved my issue.
I'm trying to use Android annotations framework because it seems quite powerful. I'm quite stuck to configuring my first project based on it.
I followed every step of the wiki but it doesn't generate any file after a build.
So when I ask for a generated class from the manifest:
<activity android:name=".MyActivity_"
android:label="#string/app_name">
I get an exception:
java.lang.ClassNotFoundException
My activity is exactly the same one as in the wiki:
#EActivity(R.layout.main)
public class MyActivity extends Activity {
#ViewById
EditText myInput;
#ViewById(R.id.myTextView)
TextView textView;
#Click
void myButton() {
String name = myInput.getText().toString();
textView.setText("Hello "+name);
}
}
Any ideas?
EDIT: Just found out a directory ".apt_generated" is made but it's empty after the build.
This seems to be an AndroidAnnotations bug, and should be reported on the dedicated bug tracker, here : http://code.google.com/p/androidannotations/issues/entry . You could also use the AndroidAnnotations mailing list, http://groups.google.com/group/androidannotations
First, I have a few questions :
Which IDE do you use : Eclipse, Netbeans, IntelliJ ? Which version ?
Do you use Maven, Ant, or only your IDE to build the project ?
Your problem may be due to a few things : annotation processing not triggered, a bug in AA, or the files generated in a folder not part of the classpath.
In Eclipse, you may get more information from the "Window > Show View > Error Log" view. If annotation processing is triggered, you should see some messages about AndroidAnnotations.
For other people who are running into this and the leading answer doesn't work, run a build and then search for the file androidannotations.log somewhere in the project. This log file is generated and may hint at what is wrong.
For me, it had a warning message that it could not locate AndroidManifest.xml. Though this seemed like just a warning, it was actually the cause of the error... Not finding my AndroidManifest.xml file resulted in it not generating some of the classes it should have.
Check if you have the xml file. If not, the solution is obvious. If you do have it, the typical reason AA cannot find the file is because it is in a non-standard location -- AA recursively checks the parent directories above where it generates files for this xml file and will fail if it's not there. In my case, my AndroidManifest.xml was located in [project root]/app/src/main which is not a direct ancestor folder so that was the problem.
You can specify where your xml file is in your project build.gradle:
android {
defaultConfig {
javaCompileOptions {
annotationProcessorOptions {
arguments = ["androidManifestFile": "specify_location_of_AndroidManifest.xml_here"]
}
}
}
}