Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android 使用setContentView加载布局时显示ProgressDialog_Android_Multithreading_Android Activity_Android Asynctask_Progressdialog - Fatal编程技术网

Android 使用setContentView加载布局时显示ProgressDialog

Android 使用setContentView加载布局时显示ProgressDialog,android,multithreading,android-activity,android-asynctask,progressdialog,Android,Multithreading,Android Activity,Android Asynctask,Progressdialog,这是我的场景:我有一个登录屏幕,可以打开另一个活动。在活动中,我只需要: public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_details); } 布局有点重,因为它是由一些碎片组成的,加载大约需要1.5秒。 现在,当setContentView完成对布局的充气时,如何显示ProgressDi

这是我的场景:我有一个登录屏幕,可以打开另一个活动。在活动中,我只需要:

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_details);
}
布局有点重,因为它是由一些碎片组成的,加载大约需要1.5秒。 现在,当
setContentView
完成对布局的充气时,如何显示
ProgressDialog
?我尝试了
AsyncTask
,将
setContentView
放在
doInBackground
中,但这当然不能做到,因为只能从UI线程更新UI。 因此,我需要在UI线程中调用
setContentView
,但是我必须在哪里显示/取消
ProgressDialog

我感谢你的帮助

弗拉

编辑:我遵循@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();
    }
  }
}
给我一个错误:

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.

我在创建重视图时也遇到了同样的问题,我所做的是仅在xml文件中放置一个linearlayout,并在该文件上调用setContentView,然后我在asynctask中创建了真实视图,并动态地将视图添加到linearlayout中


这个方法似乎很有效,在这个过程中我可以打开一个进度对话框。

我决定在这里为未来的读者提供一个完整的答案

在这个问题上花了几个小时后,我意识到问题在于我正在尝试做两件事:

  • 膨胀布局,这是一个 需要在上进行的操作 UI线程由设计完成
  • 显示对话框(ProgressDialog, 事实上,但这并没有改变 结果),这可以从 仅UI线程,因为服务 无法显示任何对话框
  • 因此,由于两个调用都是从UI线程进行的(onCreate或AsyncTask没有区别,它仍然是UI线程),因此第一个调用会阻止第二个调用正确显示。 底线是:这个问题现在无法在Android中解决。希望我们能得到一些更好的API来与UI交互,因为我们得到的API有点差劲

    我将通过改变布局并使其更轻(如果可能的话!)来解决这个问题。
    谢谢大家

    这不是一个完美的解决方案,但到目前为止,这是最接近我需要的解决方案:在设置可见的进度对话框(或消息视图或其他)和调用setContentView()之间需要一段时间,以便实际显示对话框/消息

    为了实现这一点,我启动了一个执行短sleep()的线程,然后在UI线程中调用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),这是一个近似值,在所有机器上可能都不够。这对我来说是可行的,但是如果你没有看到进度对话框,你可能必须增加睡眠时间。

    那么在doInBackground方法中手动增加睡眠时间怎么样?如果你想查看布局文件,那就最好尝试并优化它。这是模拟器上的1.5秒还是手机/平板电脑上的1.5秒?嗨,在eeePad Transformer上实际上大约是1.5秒。如何手动充气?在这里发布的布局相当长,但是它有大约10-12个线性布局和一个真实片段(目前)。在活动\u空\u布局上有一个布局(相对、线性等),对吗?如何膨胀活动\ u详细信息并将null传递给root用户,这样,之后,您就可以从父布局中使用addView.trusted with:View inflated=inflater.inflate(R.layout.activity\ u details,null);rootView.addView(充气);我仍然会犯同样的错误。是的,这似乎是一个完美的选择!您可以查看线程部分的AsyncTask,将显示在onPreExecute中的进度对话框放入onPostExecute中。有一个例子是,在《我已经有了展示》和《我已经有了发布前和发布后》中的驳回。现在我在doInBackground中添加了膨胀,这就是我得到的(明显的)错误:06-27 16:12:35.630:error/AndroidRuntime(8077):由以下原因引起:android.view.ViewRoot$calledFromErrorThreadException:只有创建视图层次结构的原始线程才能接触其视图。我在第一篇文章中添加了一些细节,完整的代码和上面的错误。看来我做了一些与你建议的不同的事情(如果使用HandlerThread,可以在单独的线程上手动膨胀视图。基本上,膨胀视图的线程需要一个活套。
    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
        ...
    }