Android - 在主布局完成显示后立即运行与 UI 相关的代码

Posted

技术标签:

【中文标题】Android - 在主布局完成显示后立即运行与 UI 相关的代码【英文标题】:Android - Run UI-dependant code right after main layout has finished displaying 【发布时间】:2016-01-24 11:24:38 【问题描述】:

我正在编写我的第一个 android 应用程序。我的主布局上有一个ExpandableListView,需要一些时间来加载(~5s)。我需要在理论上显示 UI 之前或之后调用静态方法,但该方法绝对需要能够显示AlertDialog。根据我的测试,需要在显示任何 AlertDialog 之前显示 UI,这是有道理的。

据我了解,当onResume() 返回时,应用程序会显示 UI。但是,似乎没有任何简单的方法可以在onResume() 返回之后立即在 UI 线程上执行代码,以便我可以显示AlertDialog,而不是使用来自AsyncTaskonPostExecute(),它需要在之前返回它会显示我的测试中没有的任何图形对话框/Toast。

我花了很多时间尝试OnGlobalLayoutListenerRunnableAsyncTask 之类的东西,但现在我意识到由于各种原因这些都不起作用,我没有想法。

编辑:代码

@Override
protected void onResume()

    super.onResume();
    MessageQueue.IdleHandler h = new MessageQueue.IdleHandler()
    
        @Override
        public boolean queueIdle()
        
            AlertDialog.Builder dlgAlert  = new AlertDialog.Builder(getBaseContext());
            dlgAlert.setMessage("This is an alert with no consequence");
            dlgAlert.setTitle("App Title");
            dlgAlert.setPositiveButton("OK", null);
            dlgAlert.setCancelable(true);
            dlgAlert.create().show();
            return true;
        
    ;
    this.getMainLooper().myQueue().addIdleHandler(h);

【问题讨论】:

5s 加载视图...我希望你没有在 UI 线程上这样做。您可以尝试在 onResume 返回之前调用 runOnUIThread 方法。 试图在onResume 中使用Handler @KamenStoykov 感谢您的回复;我在onResume() 返回之前尝试了runOnUIThread,但是在我的方法触发时UI 仍然没有显示。以后有机会我会试试Handler 所以使用MessageQueue#addIdleHandler并在IdleHandler中显示您的对话框 @pskink 我有我的IdleHandler,但是我应该如何实例化或者我应该从哪里获取当前活动的 MessageQueue? 【参考方案1】:

我找到了解决方案;它有效,但我相信它可以做得更好/更优雅。重申目标:我需要在显示主活动的主布局之后立即运行显示对话框的代码

这段代码的作用: 如果用户在主布局显示后立即按下AlertDialog 的肯定按钮并显示ProgressDialog 直到任务完成。

在您的工作线程中,您还可以使用static HashMap<Dialog, Boolean> 或类似的东西来轻松跟踪所有嵌入式对话框的状态(如果您有很多),但您的所有对话框都必须是static 才能工作。

在您的主 Activity 类中:

private static boolean staticInitializerFired = false;
private static MyType staticArg = myVal;

@Override
protected void onResume()

    super.onResume();
    if(!staticInitializerFired)
    
        staticInitializerFired = true;
        final Context ctx = this;
        Thread t = new Thread()
        
            @Override
            public void run()
            
                MyClass.staticMethod(ctx, staticArg);
            
        ;
        t.start();
    

在我的班级中:

private static boolean dlg0Showing = true; //preset initial state so worker thread is notified correctly before the dialog is actually built and shown in the UI thread
private static boolean dlg1Showing = false;
private static ProgressDialog progressDialog;
private static void showDialogAndDoTask(final Context context)

    ((Activity)context).runOnUiThread(new Runnable()
    
        @Override
        public void run()
        
            AlertDialog dlg = new AlertDialog.Builder(context).create();
            dlg.setMessage("My message... Yes/No ?");
            dlg.setCancelable(false);
            dlg.setButton(AlertDialog.BUTTON_POSITIVE, "Yes",
                    new DialogInterface.OnClickListener()
                    
                        @Override
                        public void onClick(DialogInterface dialog, int id)
                        
                                                    dlg1Showing = true;
                    dlg0Showing = false;

                    progressDialog = ProgressDialog.show(context, "Info", "Doing task...", true);
                        
                    );
            dlg.setButton(AlertDialog.BUTTON_NEGATIVE, "Continue regardless",
                    new DialogInterface.OnClickListener()
                    
                        @Override
                        public void onClick(DialogInterface dialog, int id)
                        
                            dlg0Showing = false;
                            dialog.dismiss();
                        
                    );
            dlg.show();
            return;
        
    );
    //wait for dialogs to have completed
    while(dlg0Showing)
    
        tryThread.sleep(500);
        catch(Exception ex) 
    
    if(dlg1Showing)
    
        doTask(args);
        progressDialog.dismiss();
    
    //GC cleanup
    progressDialog = null;

【讨论】:

以上是关于Android - 在主布局完成显示后立即运行与 UI 相关的代码的主要内容,如果未能解决你的问题,请参考以下文章

Android Place Picker 在启动后立即关闭

Swift/iOS 子视图在主线程上未立即显示

使用 Laravel 在主布局中输出为空白

为啥我的 AsyncTask 在主线程上运行?

在主窗体关闭并且不等待线程完成后让线程运行

android布局不显示