Siddhartha Sadhukhan Siddhartha Sadhukhan - 4 months ago 24
Android Question

Programically add button on android

I am facing a problem when I try to add a ScrollView to a LinearLayout app suddenly terminate.

public class DynamicButtonAdd extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

Button b1=new Button(getBaseContext());
b1.setText("Button 1");

Button b2=new Button(getBaseContext());
b2.setText("Button 2");

Button b3=new Button(getBaseContext());
b3.setText("Button 3");

Button b4=new Button(getBaseContext());
b4.setText("Button 4");

Button b5=new Button(getBaseContext());
b5.setText("Button 5");

Button b6=new Button(getBaseContext());
b6.setText("Button 6");

Button b7=new Button(getBaseContext());
b7.setText("Button 7");

Button b8=new Button(getBaseContext());
b8.setText("Button 8");

Button b9=new Button(getBaseContext());
b9.setText("Button 9");

Button b10=new Button(getBaseContext());
b10.setText("Button 10");

Button b11=new Button(getBaseContext());
b11.setText("Button 1");

Button b12=new Button(getBaseContext());
b12.setText("Button 12");

TableLayout.LayoutParams l=new TableLayout.LayoutParams();
l.width= l.height=Toolbar.LayoutParams.WRAP_CONTENT;

b1.setLayoutParams(l);

b2.setLayoutParams(l);
b3.setLayoutParams(l);
b4.setLayoutParams(l);
b5.setLayoutParams(l);
b6.setLayoutParams(l);
b7.setLayoutParams(l);
b8.setLayoutParams(l);
b9.setLayoutParams(l);
b10.setLayoutParams(l);
b11.setLayoutParams(l);
b12.setLayoutParams(l);

ScrollView sv=new ScrollView(getBaseContext());
sv.setFillViewport(true);


LinearLayout linear=new LinearLayout(getBaseContext());

sv.addView(linear);// the error appear here if I comment this line works fine without scroll
linear.setOrientation(LinearLayout.VERTICAL);
linear.setGravity(Gravity.CENTER);

linear.addView(b1);
linear.addView(b2);
linear.addView(b3);
linear.addView(b4);
linear.addView(b5);
linear.addView(b6);
linear.addView(b7);
linear.addView(b8);
linear.addView(b9);
linear.addView(b10);
linear.addView(b11);
linear.addView(b12);


setContentView(linear);
b1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Toast.makeText(getBaseContext(),"Clicked",Toast.LENGTH_SHORT).show();
}
});

}
}


The exception which is shown :

08-08 16:42:39.140 26674-26674/com.example.sid.test D/AndroidRuntime: Shutting down VM
08-08 16:42:39.140 26674-26674/com.example.sid.test W/dalvikvm: threadid=1: thread exiting with uncaught exception (group=0xb60ab4f0)
08-08 16:42:39.144 26674-26674/com.example.sid.test E/AndroidRuntime: FATAL EXCEPTION: main
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.sid.test/com.example.sid.test.DynamicButtonAdd}: 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:1647)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1663)
at android.app.ActivityThread.access$1500(ActivityThread.java:117)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:931)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:130)
at android.app.ActivityThread.main(ActivityThread.java:3683)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:507)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
at dalvik.system.NativeStart.main(Native Method)
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:1976)
at android.view.ViewGroup.addView(ViewGroup.java:1871)
at android.view.ViewGroup.addView(ViewGroup.java:1828)
at android.view.ViewGroup.addView(ViewGroup.java:1808)
at android.support.v7.app.AppCompatDelegateImplV7.setContentView(AppCompatDelegateImplV7.java:271)
at android.support.v7.app.AppCompatActivity.setContentView(AppCompatActivity.java:145)
at com.example.sid.test.DynamicButtonAdd.onCreate(DynamicButtonAdd.java:106)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1611)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1663) 
at android.app.ActivityThread.access$1500(ActivityThread.java:117) 
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:931) 
at android.os.Handler.dispatchMessage(Handler.java:99) 
at android.os.Looper.loop(Looper.java:130) 
at android.app.ActivityThread.main(ActivityThread.java:3683) 
at java.lang.reflect.Method.invokeNative(Native Method) 
at java.lang.reflect.Method.invoke(Method.java:507) 
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839) 
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597) 
at dalvik.system.NativeStart.main(Native Method) 


I am not bother about the procedure, if any useful scheme you know please tell me. One more thing minimum api level is 8 (Android 2.2) Thank you.

Answer

There are some problems with your code. The one thats causing the crash is that you are adding your LinearLayout to your ScrollView and then calling setContentView(linear) i.e. you are adding your LinearLayout to both your activity and the ScrollView. You probably wished to set the ScrollView as you content. Hence, the simple fix is:

ScrollView sv=new ScrollView(getBaseContext());
sv.setFillViewport(true);

LinearLayout linear=new LinearLayout(getBaseContext());
sv.addView(linear);
...
setContentView(sv); // you have linear here

Secondly, the problem is:

TableLayout.LayoutParams l=new TableLayout.LayoutParams();
l.width= l.height=Toolbar.LayoutParams.WRAP_CONTENT;

You are setting this LayoutParam to your Button instances which are being added to a LinearLayout. You should set the layout params of the parent ViewGroup here:

LinearLayout.LayoutParams l=new LinearLayout.LayoutParams();
l.width = l.height = LinearLayout.LayoutParams.WRAP_CONTENT;

Thirdly, I have a slight feeling (and I might be wrong since I don't know the true use case), you can move at least some of this layout description to and xml file