Unresolved reference for synthetic view when layout is in library module

蓝咒 提交于 2019-12-18 10:20:43

问题


using Kotlin 1.20.20 (not that it matters, older versions behaves the same)

When layout is in separate library module Android Studio has no problem finding and referencing the view

import kotlinx.android.synthetic.main.view_user_input.*

But when I try to compile app it fails with Unresolved reference: view_user_input on :app:compileDebugKotlin.

Everything works fine when view is referenced IN the library module.

Am I missing something here?

Adding project structure. All modules are using kotlin and kotlin-extensions.

build.gradle
app/
  build.gradle //main application
library-module-a/
  build.gradle //library application
library-module-b/
  build.gradle //library application

Here is an example app https://github.com/mjurkus/KotlinxTest

Registered issue for that in KT tracker


回答1:


One way to solve this is to create an "alias" property that can be consumed from other modules:

// SyntheticExports.kt
package com.example.synthetic.exported

import kotlinx.android.synthetic.main.layout_in_library.*

inline val Activity.exported_text_view get() = text_view

Then on the other module:

// MainActivity.kt
import com.example.synthetic.exported.exported_text_view

exported_text_view.text = "example"

That works for us. Have to create different extensions for view, fragment, etc. It's a bit tedious to have to do them manually but this is the simplest workaround we found.

Extra: This is also a decent method to export synthetic extensions as part of a public library too, not just in an internal module.




回答2:


I also got this issue and my solution is:

  • Don't use import kotlinx.android.synthetic.main....*

  • Use findViewById()

Ex: textview_id.text = "abc". I change it to findViewById(R.id.textview_id).text = "abc"




回答3:


you could try switching to 1.2.30-eap-16 and adding

androidExtensions { experimental = true }

to your build.gradle.




回答4:


As mentioned in the comment by @cesards above this is an on going issue with the Kotlin Android Extentions. And it is not solved as of today.


Good: Use Custom Views

My primary suggestion is encapsulating the view and the relevant behavior as a custom view and instead of including it via <include> tag, use it directly in your layout as <com.example.app.YourCustomView>.

This will work no matter your view class is in another module or not.


Bad and Ugly: Id Collision Workaround

However I found a hacky workaround if you only want to get one reference from the included view.

Follow these steps to use kotlin synthetic imports for the layouts included from other modules:

  1. Give an id to the view you want to get reference of in the included xml file.
  2. Give the same id to the include tag in the including xml file.
  3. Now synthetic import the view (id) from the including layout (not from the included)

I'm not really sure how and why this works but it's a very fragile and dirty way of reusing layouts.

Example:

Your including layout (fragment_example.xml)

<include
    android:id="@+id/exampleView"
    layout="@layout/example_layout" />

Your included layout (example_layout.xml)

<merge xmlns:android="http://schemas.android.com/apk/res/android">

    <TextView
        android:id="@+id/exampleView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

</merge>

Your fragment class (ExampleFragment.kt)

import kotlinx.android.synthetic.main.fragment_example.exampleView

// Do not import the exampleView through example_layout.exampleView

class ExampleFragment : Fragment() {
    // Do something with imported exampleView
}



回答5:


Preconditions

Do not import the following library import kotlinx.android.synthetic.main.my_view.view.*

app/MainActivity.kt

override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val view: View = MyView(this)
        view.findViewById<TextView>(R.id.textViewPocLib).text = "I can edit the library components"
        setContentView(view)
}

my_library/MyView.kt

class MyView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) :
    LinearLayout(context, attrs, defStyleAttr) {

    init {
        LayoutInflater.from(context)
            .inflate(R.layout.my_view, this, true)
    }
}

GL

Sources:

  • Bug
  • Building Custom Component



回答6:


My scenario was : I needed base class (from lib) view references in child classes (app module) and had minimum number of view references from Library Module's base classes.

I would say, it's kind a fix and not a solution.

Solution #1 Get a view reference from Base class

//lib module snippet
import kotlinx.android.synthetic.main.view_user_input.*

class LibModuleBaseActivity : AppCompatActivity() {

   override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.view_user_input)
   }

    protected val vFirstName: TextView by lazy { tvFirstName }
    ...........
}


//app module snippet
class AppModuleActivity : LibModuleBaseActivity() {

    fun setUserDetails(name: String) {
        vFirstName.text = name
    }
}

Solution #2 Get the task done by Base Class

//lib module snippet
import kotlinx.android.synthetic.main.view_user_input.*

class LibModuleBaseActivity : AppCompatActivity() {
    protected fun setUserDetails(name: String) {
        tvFirstName.text = name
    }
    ...........
}


//app module snippet
class AppModuleActivity : LibModuleBaseActivity() {
    ............
    setUserDetails("user_name")
}

Note: This works only if you are inheriting from lib module and where your Base class is inflating views.




回答7:


I solved my issue with copy both androidExtension and buildscript from project build.gradle to module that uses the library.

buildscript {

    repositories {
        jcenter()
        google()
    }
    dependencies {
        classpath "com.android.tools.build:gradle:$gradle_version"
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
    }
}

androidExtensions {
    experimental = true
}

Note: I use the following version of kotlin and gradle:

buildscript {
    ext.kotlin_version = '1.3.0'
    ext.gradle_version = '3.0.1'


来源:https://stackoverflow.com/questions/48378696/unresolved-reference-for-synthetic-view-when-layout-is-in-library-module

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!