0

I'm developing an Android application that generates the layout widgets in the UI dynamically at runtime (this is because the amount and the types of widgets are undefined)

public class DynamicLayout extends Activity{

private ScrollView scrollView;
private LinearLayout linearLayout;

@Override
public void onCreate(Bundle savedInstanceState) {       

        super.onCreate(savedInstanceState);

        scrollView = new ScrollView(this);
        linearLayout = new LinearLayout(this);
        linearLayout.setOrientation(LinearLayout.VERTICAL);
        scrollView.addView(linearLayout);
        setContentView(scrollView);
        new LoadWidgets().execute();
    }
 }

  class LoadWidgets extends AsyncTask<String, String, String>{
        @Override
        protected void onPreExecute() {...}

        @Override            
        protected String doInBackground(String... args) {   
        ...
        while (condition){

            String widgetType;

            /* code that that finds out what type of widget needs to be added
             * to layout and puts "EditText", "TimePicker", "DatePicker", "TextView"
             * or "ListView" in the widgetType String */

            if (widgetType.equals("EditText") )
             { 
                final EditText editText = new EditText(this);

                runOnUiThread(new Runnable() {
                    public void run() {
                        linearLayout.addView(editText);
                    }
                });
             }
        else if (widgetType.equals("TimePicker") )
             { 
                final TimePicker timePicker = new TimePicker(this);

                runOnUiThread(new Runnable() {
                    public void run() {
                        linearLayout.addView(timePicker);
                    }
                });
             }
        else if (widgetType.equals("DatePicker") )
             { 
                final DatePicker datePicker = new DatePicker(this);

                runOnUiThread(new Runnable() {
                    public void run() {
                        linearLayout.addView(datePicker);
                    }
                });

             }
        else if /* other widgets... */

        }
              @Override
              protected void onPostExecute(String s) {...}
      }
  }

it works perfectly fine for all the widgets except for DatePicker, in fact this line of code...

final DatePicker datePicker = new DatePicker(this);

throws this exception:

06-27 09:58:48.471: E/AndroidRuntime(877): Caused by: android.view.InflateException: Binary XML file line #81: Error inflating class android.widget.CalendarView
06-27 09:58:48.471: E/AndroidRuntime(877):  at android.view.LayoutInflater.createView(LayoutInflater.java:613)
06-27 09:58:48.471: E/AndroidRuntime(877):  at com.android.internal.policy.impl.PhoneLayoutInflater.onCreateView(PhoneLayoutInflater.java:56)
06-27 09:58:48.471: E/AndroidRuntime(877):  at android.view.LayoutInflater.onCreateView(LayoutInflater.java:660)
06-27 09:58:48.471: E/AndroidRuntime(877):  at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:685)
06-27 09:58:48.471: E/AndroidRuntime(877):  at android.view.LayoutInflater.rInflate(LayoutInflater.java:746)
06-27 09:58:48.471: E/AndroidRuntime(877):  at android.view.LayoutInflater.inflate(LayoutInflater.java:489)
06-27 09:58:48.471: E/AndroidRuntime(877):  at android.view.LayoutInflater.inflate(LayoutInflater.java:396)
06-27 09:58:48.471: E/AndroidRuntime(877):  at android.widget.DatePicker.<init>(DatePicker.java:171)
06-27 09:58:48.471: E/AndroidRuntime(877):  at android.widget.DatePicker.<init>(DatePicker.java:145)
06-27 09:58:48.471: E/AndroidRuntime(877):  at android.widget.DatePicker.<init>(DatePicker.java:141)
06-27 09:58:48.471: E/AndroidRuntime(877):  at com.dynamicLayoutApp.DynamicLayout.loadWidgets(DynamicLayout.java:302)
06-27 09:58:48.471: E/AndroidRuntime(877):  at com.dynamicLayoutApp.DynamicLayout.access$6(DynamicLayout.java:215)
06-27 09:58:48.471: E/AndroidRuntime(877):  at com.dynamicLayoutApp.DynamicLayout$LoadDynamicLayout.doInBackground(DynamicLayout.java:160)
06-27 09:58:48.471: E/AndroidRuntime(877):  at com.dynamicLayoutApp.DynamicLayout$LoadDynamicLayout.doInBackground(DynamicLayout.java:1)
06-27 09:58:48.471: E/AndroidRuntime(877):  at android.os.AsyncTask$2.call(AsyncTask.java:287)
06-27 09:58:48.471: E/AndroidRuntime(877):  at java.util.concurrent.FutureTask.run(FutureTask.java:234)
06-27 09:58:48.471: E/AndroidRuntime(877):  ... 4 more
06-27 09:58:48.471: E/AndroidRuntime(877): Caused by: java.lang.reflect.InvocationTargetException
06-27 09:58:48.471: E/AndroidRuntime(877):  at java.lang.reflect.Constructor.constructNative(Native Method)
06-27 09:58:48.471: E/AndroidRuntime(877):  at java.lang.reflect.Constructor.newInstance(Constructor.java:417)
06-27 09:58:48.471: E/AndroidRuntime(877):  at android.view.LayoutInflater.createView(LayoutInflater.java:587)
06-27 09:58:48.471: E/AndroidRuntime(877):  ... 19 more
06-27 09:58:48.471: E/AndroidRuntime(877): Caused by: java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
06-27 09:58:48.471: E/AndroidRuntime(877):  at android.os.Handler.<init>(Handler.java:197)
06-27 09:58:48.471: E/AndroidRuntime(877):  at android.os.Handler.<init>(Handler.java:111)
06-27 09:58:48.471: E/AndroidRuntime(877):  at android.view.GestureDetector$GestureHandler.<init>(GestureDetector.java:250)
06-27 09:58:48.471: E/AndroidRuntime(877):  at android.view.GestureDetector.<init>(GestureDetector.java:350)
06-27 09:58:48.471: E/AndroidRuntime(877):  at android.view.GestureDetector.<init>(GestureDetector.java:331)
06-27 09:58:48.471: E/AndroidRuntime(877):  at android.widget.CalendarView$WeeksAdapter.<init>(CalendarView.java:1349)
06-27 09:58:48.471: E/AndroidRuntime(877):  at android.widget.CalendarView.setUpAdapter(CalendarView.java:1007)
06-27 09:58:48.471: E/AndroidRuntime(877):  at android.widget.CalendarView.<init>(CalendarView.java:405)
06-27 09:58:48.471: E/AndroidRuntime(877):  at android.widget.CalendarView.<init>(CalendarView.java:333)
06-27 09:58:48.471: E/AndroidRuntime(877):  ... 22 more
06-27 09:58:53.471: E/WindowManager(877): Activity com.dynamicLayoutApp.DynamicLayout has leaked window com.android.internal.policy.impl.PhoneWindow$DecorView{40db1080 V.E..... R.....ID 0,0-563,96} that was originally added here
06-27 09:58:53.471: E/WindowManager(877): android.view.WindowLeaked: Activity com.dynamicLayoutApp.DynamicLayout has leaked window com.android.internal.policy.impl.PhoneWindow$DecorView{40db1080 V.E..... R.....ID 0,0-563,96} that was originally added here
06-27 09:58:53.471: E/WindowManager(877):   at android.view.ViewRootImpl.<init>(ViewRootImpl.java:354)
06-27 09:58:53.471: E/WindowManager(877):   at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:216)
06-27 09:58:53.471: E/WindowManager(877):   at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:69)
06-27 09:58:53.471: E/WindowManager(877):   at android.app.Dialog.show(Dialog.java:281)
Hamdi Baccara
  • 29
  • 1
  • 11
  • I'am generating all the layout dynamically. This code generates the initial layout: scrollView = new ScrollView(this); linearLayout = new LinearLayout(this); linearLayout.setOrientation(LinearLayout.VERTICAL); scrollView.addView(linearLayout); setContentView(scrollView); – Hamdi Baccara Jun 27 '13 at 10:40
  • `Caused by: android.view.InflateException: Binary XML file line #81: Error inflating class android.widget.CalendarView`. But the logcat says error in xml file line 81. – Raghunandan Jun 27 '13 at 10:41
  • the xml file indicated is the one generated automatically at runtime. I have no control over it. – Hamdi Baccara Jun 27 '13 at 10:43

2 Answers2

0

I think the problem is, that the DatePicker isn't a single Widget but a bunch of them. And according to the documentation they are always used within Dialogs, e.g. DatePickerDialog.

So I suggest you create a button dynamically and add an on-click callback that opens a DatePickerDialog.

Ridcully
  • 23,362
  • 7
  • 71
  • 86
  • I'am avoiding using Dialogs, I want the DatePicker to be embedded in the layout just like the TimePicker does and the fact that the TimePicker gets added to the layout without problems is weird as it's almost similar to DatePicker. – Hamdi Baccara Jun 27 '13 at 11:05
-1

I resolved the issue; I moved the initialisation of DatePicker to the runOnUiThread method like this:

...
else if (widgetType.equals("TimePicker") )
            runOnUiThread(new Runnable() {
                public void run() {
                    TimePicker timePicker = new TimePicker(DynamicLayout.this);
                    linearLayout.addView(timePicker);
                }
            });
    else if
...

I have already known that it's not recommended to manipulate the UI from a background thread but I thought it was fine to do it when I succeded to intialise the other types of widgets from a background thread.

Hamdi Baccara
  • 29
  • 1
  • 11