6

I'm having problems trying to make this Layout totally programmatically, every time the process run end without success and the app crashes.

The Part of XML im trying to create programmatically is it :

<LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

        <ImageView
            android:id="@+id/idImagenPlay0"
            android:layout_width="62dp"
            android:layout_height="54dp"
            android:layout_marginRight="10dp"
            android:layout_marginTop="15dp"
            android:src="@drawable/ic_action_play" />
        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent">

        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:orientation="vertical">

            <TextView
                android:id="@+id/idNombre0"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginTop="10dp"
                android:text="Description"
                android:textSize="25sp"
                android:textStyle="bold" />

            <TextView
                android:id="@+id/idInfo0"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginBottom="15dp"
                android:layout_marginRight="10dp"
                android:text="Title" />

        </LinearLayout>

        <ImageView
            android:id="@+id/idImagenShare0"
            android:layout_width="54dp"
            android:layout_height="48dp"
            android:layout_alignParentRight="true"
            android:layout_marginRight="10dp"
            android:layout_marginTop="15dp"
            android:src="@drawable/ic_action_share" />
        </RelativeLayout>
    </LinearLayout>

I'm trying to recreate it with the following kotlin code:

fun createXmlElement(title:String,description:String){
    val parent = LinearLayout(this)
    parent.layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,
            LinearLayout.LayoutParams.WRAP_CONTENT)

    parent.orientation = LinearLayout.HORIZONTAL

    //children of parent linearlayout
    val iv = ImageView(this)
    val lp = LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,
            LinearLayout.LayoutParams.WRAP_CONTENT)

    lp.setMargins(0, 11, 7, 0)
    iv.setLayoutParams(lp)
    iv.setImageResource(R.drawable.ic_action_play)
    iv.getLayoutParams().height = 40;
    iv.getLayoutParams().width = 46;

    parent.addView(iv); // lo agregamos al layout

    val relativeP = RelativeLayout(this)
    relativeP.layoutParams = RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT,
            RelativeLayout.LayoutParams.MATCH_PARENT)

    val linearCH = LinearLayout(this)
    linearCH.layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,
            LinearLayout.LayoutParams.WRAP_CONTENT)
    // TextView1
    val tv1 = TextView(this)
    val lptv1 = LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,
            LinearLayout.LayoutParams.WRAP_CONTENT)

    lptv1.setMargins(0, 7, 0, 0)

    tv1.setLayoutParams(lptv1)
    tv1.setText(title) // nombre de la musica
    tv1.setTextSize(TypedValue.COMPLEX_UNIT_SP,25F)
    tv1.setTypeface(null, Typeface.BOLD);

    // TextView2
    val tv2 = TextView(this)
    val lptv2 = LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,
            LinearLayout.LayoutParams.WRAP_CONTENT)

    lptv2.setMargins(0, 11, 7, 0)

    tv2.setLayoutParams(lptv1)
    tv2.setText(description) // Descripcion de la musica
    tv2.setTextSize(TypedValue.COMPLEX_UNIT_SP, 25F)
    tv2.setTypeface(null, Typeface.BOLD);

    linearCH.addView(tv1)
    linearCH.addView(tv2)

    relativeP.addView(linearCH)

    // last ImageView
    val iv2 = ImageView(this)
    val lpiv2 = RelativeLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,
            LinearLayout.LayoutParams.WRAP_CONTENT)

    lpiv2.setMargins(0, 11, 7, 0)
    lpiv2.addRule(RelativeLayout.ALIGN_PARENT_RIGHT)
    iv2.setLayoutParams(lpiv2)
    iv2.setImageResource(R.drawable.ic_action_share)
    iv2.getLayoutParams().height = 40;
    iv2.getLayoutParams().width = 46;


    parent.addView(iv)
    parent.addView(relativeP)
    parent.addView(iv2)


}

This is the error I'm getting in logcat

04-27 10:51:01.224 6973-6973/com.klystru.app.appE/AndroidRuntime: FATAL EXCEPTION: main
Process: com.klystru.app.app, PID: 6973
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.klystru.app.app/com.klystru.app.app.MainActivity}: java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2583)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2665)
    at android.app.ActivityThread.-wrap11(ActivityThread.java)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1499)
    at android.os.Handler.dispatchMessage(Handler.java:111)
    at android.os.Looper.loop(Looper.java:207)
    at android.app.ActivityThread.main(ActivityThread.java:5765)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:789)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:679)
 Caused by: java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.
    at android.view.ViewGroup.addViewInner(ViewGroup.java:4453)
    at android.view.ViewGroup.addView(ViewGroup.java:4281)
    at android.view.ViewGroup.addView(ViewGroup.java:4222)
    at android.view.ViewGroup.addView(ViewGroup.java:4195)
    at com.klystru.app.app.MainActivity.createXmlElement(MainActivity.kt:284)
    at com.klystru.app.app.MainActivity.onCreate(MainActivity.kt:121)
    at android.app.Activity.performCreate(Activity.java:6309)
    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1113)
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2530)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2665) 
    at android.app.ActivityThread.-wrap11(ActivityThread.java) 
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1499) 
    at android.os.Handler.dispatchMessage(Handler.java:111) 
    at android.os.Looper.loop(Looper.java:207) 
    at android.app.ActivityThread.main(ActivityThread.java:5765) 
    at java.lang.reflect.Method.invoke(Native Method) 
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:789) 
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:679) 

I still research what it can be, I'm suspecting it may be wrong LayoutParams, but it's not really clear about how to set up correctly those resources programmatically.

Thanks in advance.

PD: If I found something I will update.

Any help will be really welcome!

UPDATE 1.0:

Ok following the logcat I have to call removeView in child's parent, but I don't know exactly where. I am looking for that.

10
  • 1
    Maybe that would be helpful to post the crash you're getting as well? Commented Apr 27, 2018 at 15:43
  • Thank you!, I forget to check the logcats!! Look like i have to call removeView() first anywhere.... Commented Apr 27, 2018 at 15:53
  • 1
    Logcat states the error lies into the function createMusicElement(), and not in the createXmlElement() that you pasted (unless they are indeed the same, just renamed when pasted here) Commented Apr 27, 2018 at 16:01
  • Yeah, they are the same, i just renamed it. Done... Commented Apr 27, 2018 at 16:07
  • 1
    No, if you need "constantly changing layout", then you need a RecyclerView. Commented Apr 28, 2018 at 10:37

2 Answers 2

5

Ok the solution is as following:

Just need to add removeAllView on all parents before adding the childs

protected fun createXmlElement(title:String,description:String){
    val parent = LinearLayout(this)
    parent.layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,
            LinearLayout.LayoutParams.WRAP_CONTENT)

    parent.orientation = LinearLayout.HORIZONTAL



    //children of parent linearlayout
    val iv = ImageView(this)
    val lp = LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,
            LinearLayout.LayoutParams.WRAP_CONTENT)

    lp.setMargins(0, 11, 7, 0)
    iv.setLayoutParams(lp)
    iv.setImageResource(R.drawable.ic_action_play)
    iv.getLayoutParams().height = 40
    iv.getLayoutParams().width = 46


    parent.addView(iv); // lo agregamos al layout

    val relativeP = RelativeLayout(this)
    relativeP.layoutParams = RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT,
            RelativeLayout.LayoutParams.MATCH_PARENT)

    val linearCH = LinearLayout(this)
    linearCH.layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,
            LinearLayout.LayoutParams.WRAP_CONTENT)
    // TextView1
    val tv1 = TextView(this)
    val lptv1 = LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,
            LinearLayout.LayoutParams.WRAP_CONTENT)

    lptv1.setMargins(0, 7, 0, 0)

    tv1.setLayoutParams(lptv1)
    tv1.setText(title) // title
    tv1.setTextSize(TypedValue.COMPLEX_UNIT_SP,25F)
    tv1.setTypeface(null, Typeface.BOLD)

    // TextView2
    val tv2 = TextView(this)
    val lptv2 = LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,
            LinearLayout.LayoutParams.WRAP_CONTENT)

    lptv2.setMargins(0, 11, 7, 0)

    tv2.setLayoutParams(lptv1)
    tv2.setText(description) // description
    tv2.setTextSize(TypedValue.COMPLEX_UNIT_SP, 25F)
    tv2.setTypeface(null, Typeface.BOLD)

    linearCH.removeAllViews()
    linearCH.addView(tv1)
    linearCH.addView(tv2)

    relativeP.removeAllViews()
    relativeP.addView(linearCH)

    // last ImageView
    val iv2 = ImageView(this)
    val lpiv2 = RelativeLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,
            LinearLayout.LayoutParams.WRAP_CONTENT)

    lpiv2.setMargins(0, 11, 7, 0)
    lpiv2.addRule(RelativeLayout.ALIGN_PARENT_RIGHT)
    iv2.setLayoutParams(lpiv2)
    iv2.setImageResource(R.drawable.ic_action_share)
    iv2.getLayoutParams().height = 40
    iv2.getLayoutParams().width = 46


    parent.removeAllViews()
    parent.addView(iv)
    parent.addView(relativeP)
    parent.addView(iv2)

    val finalParent = this.findViewById(R.id.contenedor) as ViewGroup

    finalParent.addView(parent)
}

Thanks NSion, the error on logcat point to me the right direction!

Sign up to request clarification or add additional context in comments.

Comments

0

Inspired from the answer above. This is my helper function.

In OnViewCreated

val titleCard = createNumberCard()
        val verse1Card:CardView = createVerseCard()

        detailLinearLayout.addView(titleCard, 0)
        detailLinearLayout.addView(verse1Card, 1)
private fun createVerseCard(): CardView {
        //verseCard
        val verseCard = CardView(requireActivity())
        verseCard.setId(View.generateViewId())

        val verseCardLayout = ConstraintLayout(activity)
        verseCardLayout.layoutParams = ConstraintLayout.LayoutParams(
            ConstraintLayout.LayoutParams.MATCH_PARENT,
            ConstraintLayout.LayoutParams.MATCH_PARENT
        )

        verseCard.addView(verseCardLayout)

        val set = ConstraintSet()

        val verseView = TextView(activity)
        verseView.text = "Verse 1"
        verseView.setId(View.generateViewId())

        verseCardLayout.addView(verseView, 0)

        set.clone(verseCardLayout)

        set.connect(
            verseView.getId(),
            ConstraintSet.TOP,
            verseCardLayout.getId(),
            ConstraintSet.TOP,
            0
        )

        set.applyTo(verseCardLayout)
        return verseCard
    }

Im using these in a fragment.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.