0

我正在开发一个 Android 应用程序,它在运行时动态生成 UI 中的布局小部件(这是因为小部件的数量和类型未定义)

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) {...}
      }
  }

它适用于除 DatePicker 之外的所有小部件,实际上这行代码......

final DatePicker datePicker = new DatePicker(this);

抛出此异常:

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)
4

2 回答 2

0

我认为问题在于,这DatePicker不是一个小部件,而是一堆。根据文档,它们总是在对话框中使用,例如DatePickerDialog.

所以我建议你动态创建一个按钮并添加一个点击回调来打开一个DatePickerDialog.

于 2013-06-27T10:52:36.723 回答
-1

我解决了这个问题;我将 DatePicker 的初始化移动到 runOnUiThread 方法,如下所示:

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

我已经知道不建议从后台线程操作 UI,但是当我成功地从后台线程初始化其他类型的小部件时,我认为这样做很好。

于 2013-07-01T14:27:48.340 回答