Подтвердить что ты не робот

Показывать ProgressDialog при загрузке макета с помощью setContentView

это мой сценарий: у меня есть экран входа в систему, который открывает другое действие. В Управлении я просто:

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_details);
}

Макет тяжелый, потому что он сделан из некоторых фрагментов и занимает около 1,5 секунд для загрузки. Теперь, как я могу отобразить ProgressDialog, а setContentView заканчивает раздувание макета? Я попытался с помощью AsyncTask, поместив setContentView в doInBackground, но, конечно, это невозможно сделать, поскольку пользовательский интерфейс может быть обновлен только из потока пользовательского интерфейса. Поэтому мне нужно вызвать setContentView в потоке пользовательского интерфейса, но где мне нужно показать/отклонить ProgressDialog?

Я ценю вашу помощь.

Fra.

EDIT: я последовал за предыдущим предложением @JohnBoker, это код, который у меня есть сейчас:

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_empty_layout);
    new ContentSetterTask().execute("");
}

private class ContentSetterTask extends AsyncTask<String, Void, Void> {

    public ProgressDialog prgDlg;

    @Override
    protected void onPreExecute() {
        android.os.Debug.waitForDebugger();
        prgDlg = ProgressDialog.show(MultiPaneActivity.this, "", "Loading...", true);

    }

@Override
protected Void doInBackground(String... args) {
    android.os.Debug.waitForDebugger();
    ViewGroup rootView = (ViewGroup)findViewById(R.id.emptyLayout);
    LayoutInflater inflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    View inflated = inflater.inflate(R.layout.activity_details, rootView);
    return null;
}

@Override
protected void onPostExecute(Void arg) {
    android.os.Debug.waitForDebugger();
    if (prgDlg.isShowing())
        prgDlg.dismiss();
    }
  }
}

Строка

View inflated = inflater.inflate(R.layout.activity_details, rootView);

дает мне ошибку:

06-27 16:47:24.010:   
ERROR/AndroidRuntime(8830): Caused by:android.view.ViewRoot$CalledFromWrongThreadException: 
Only the original thread that created a view hierarchy can touch its views.
4b9b3361

Ответ 1

Я решил дать полный ответ здесь для будущих читателей.

После нескольких часов, проведенных по этой проблеме, я понял, что проблема в том, что я пытаюсь сделать две вещи:

  • раздувание макета, которые НЕОБХОДИМО дизайн пользовательского интерфейса.
  • показывает диалог (ProgressDialog, на самом деле, но это не меняется результат), что можно сделать из только пользовательский интерфейс, поскольку службы не может отображать диалог.

Итак, поскольку оба вызова сделаны из потока пользовательского интерфейса (onCreate или AsyncTask не имеет никакого значения, он все еще является потоком пользовательского интерфейса), первый блокирует второй из показаний соответственно. Итог: эта проблема не может быть решена в Android прямо сейчас. Позвольте надеяться, что мы сможем получить несколько лучших API для взаимодействия с пользовательским интерфейсом, потому что у нас есть отстой.

Я собираюсь решить эту проблему, изменив макет и сделав его более легким (если возможно!). Спасибо всем!

Ответ 2

У меня была такая же проблема при создании тяжелого представления, то, что я сделал, было положено linearlayout только в xml файле и называлось setContentView на этом, тогда я создал реальное представление в асинтете и добавил dymanically представление в linearlayout.

Этот метод, похоже, работает, и я смог установить диалог прогресса во время процесса.

Ответ 3

Это не идеальное решение, но до сих пор самое близкое к тому, что мне было нужно: нам нужно некоторое время между установкой диалога прогресса (или просмотра сообщения или чего-то еще), видимым и вызывающим setContentView(), так что диалог/сообщение на самом деле отображается.

Для этого я запускаю Thread, выполняющий короткий sleep(), а затем вызывающий setContentView() в потоке пользовательского интерфейса.

Вот пример диалога прогресса:

private ProgressDialog  m_Hourglass = null ;
private Thread          m_LoadingThread = null ;

...

public void onCreate( Bundle savedInstanceState )
{
    super.onCreate( savedInstanceState );

    ...

    m_Hourglass = new ProgressDialog( this );
    m_Hourglass.setMessage( "Loading" );
    m_Hourglass.setIndeterminate( true );
    m_Hourglass.setCancelable( false );
}

public void SetMyView( View vvv )                   // Can be called from buttons.
{
    if( m_LoadingThread != null ) return;           // Avoid multiple press

    m_Hourglass.show();

    ////////////////////////////////////////////////////
    // Load in a thread, just to show the above message
    // before changing layout (because setContentView()
    // freezes the GUI.)
    m_LoadingThread = new Thread()
    {
            @Override
            public void run()
            {
                super.run();
                try                 {   sleep( 20 ); }
                catch (Exception e) {   System.out.println( e ); }
                finally             {   runOnUiThread( new Runnable()
                                        {
                                            public void run() 
                                            {
                                                SetMyViewThreaded();
                                            }
                                        });
                                    }
                m_LoadingThread = null ; // Now we can load again
            }
    };
    m_LoadingThread.start();
}

public void SetMyViewThreaded()
{
    setContentView( R.layout.some_gorgeous_layout );

    /////////////////////////////////////////////////////
    // Catch when to finally hide the progress dialog:
    ImageView iv            = (ImageView) findViewById( R.id.some_view_in_the_layout );
    ViewTreeObserver obs    = iv.getViewTreeObserver();      
    obs.addOnGlobalLayoutListener( new OnGlobalLayoutListener()
    {          
         @Override          
         public void onGlobalLayout()    // The view is now loaded
         {
             m_Hourglass.hide();
         }      
    });

    //////////////////////////////////////////////////////
    // Here we can work on the layout
    ...
}

Моя основная проблема в этом - сон (20), который является приблизительным и может быть недостаточным для всех машин. Это работает для меня, но если вы не видите диалог прогресса, вам, вероятно, придется увеличить продолжительность сна.