【问题标题】:Progress Dialog not showing up with JNI Native Call in between show/dismiss在显示/关闭之间未显示 JNI 本机调用的进度对话框
【发布时间】:2012-12-28 18:44:48
【问题描述】:

我正在尝试使用旋转的 ProgressDialog 来告诉用户程序何时运行。我已经让ProgressDialog 正确显示和关闭,但是只有在调用之间有简单的代码时。我目前正在我的onCreate 方法中初始化ProgressDialog,然后在按下按钮时,将显示对话框,然后遍历大量代码,然后是关闭调用。代码全部正常执行,但对话框从未显示。

public class Waves extends Activity {
    private ProgressDialog pd;
    public void onCreate( Bundle savedInstanceState ) {
        super.onCreate( savedInstanceState );
        pd = new ProgressDialog( this );  
        pd.setProgressStyle(ProgressDialog.STYLE_SPINNER);
        pd.setMessage("Reading...");
        pd.setCancelable(false);
        setContentView( R.layout.waves );

        readButton = (Button) findViewById( R.id.readButton );
        readButton.setOnClickListener( new OnClickListener() {

        public void onClick(View arg0) {
            pd.show( );
            if( myService.getState() != 3 ) {
                myService.setHandler( mHandler );
                myService.connect( MainMenu.previousDevice, true );
            } else {
                readWaves();
            }
        }
    });

}

readWaves 如下所示。在 readWaves 的末尾是调用 pd.dismiss() 的地方。在 readWaves 中有很多函数调用,我将尝试展示它们,但不会太冗长。

private void readWaves() {
    if( spinnerChoice == 0 ) {
        Log.i( "IN IF", "IN IF" );
        // Diff Voltage
        waveResults = RelayAPIModel.NativeCalls.GetWavesJava( RelayAPIModel.WAVES_V );
    } else {
        // Current 
        waveResults = RelayAPIModel.NativeCalls.GetWavesJava( RelayAPIModel.WAVES_I );
    }

    updateGraph();
    netV1Check.setChecked( true );
    netV2Check.setChecked( true );
    netV3Check.setChecked( true );
    vdi1Check.setChecked( true );
    vdi2Check.setChecked( true );
    vdi3Check.setChecked( true );
    hasRead = true;
    pd.dismiss();
}

updateGraph() 调用对图表做了简单的修饰,所以我认为问题不存在。 RelayAPIModel.NativeCalls.GetWavesJava() 电话是我认为问题出现的地方。

GetWavesJava() 是一个用 C 语言编写的函数,位于我的本地库中。在 GetWavesJava() 中,有大量对其他本机 C 函数的函数调用,以及对我的应用程序 Java 端的大量函数调用。

这听起来很愚蠢,但原因是 C 中的本机库是需要使用的现有库。但是,它不支持Android的蓝牙功能,所以所有通过蓝牙发送/接收数据的方法都需要在Java端进行描述。

总共有六个 Java 函数用于 I/O 流,它们在整个应用程序中被多次使用,而不仅仅是这一次调用。我考虑将pd.dismiss() 放在其中一个函数中,但仅在调用这些函数的 1% 时才需要它。

有谁知道确保我的对话框在本机函数调用之前显示并在之后停止的解决方案?

This is a similar SO question but not exactly the same

编辑:

使用下面的答案,这是我的代码:

readButton = (Button) findViewById( R.id.readButton );
readButton.setOnClickListener( new OnClickListener() {

        public void onClick(View arg0) {

            pd.show( );
            Thread export = new Thread() {  
                 public void run() {
                        if( myService.getState() != 3 ) {
                            Log.i( "myService", "12222" );
                            myService.setHandler( mHandler );
                            myService.connect( MainMenu.previousDevice, true );
                        } else {
                            Log.i("myService",  "32222" );
                            readWaves();
                            Log.i( "myService", "42222" );
                        }

                 mHandler.obtainMessage(MainMenu.READ_FINISHED );
                 }
            };
            export.start();
                        }
    });

永远无法到达Log( 42222 )。微调器确实出现了,但程序会在几秒钟内崩溃并重新启动。我在mHandler.obtainMessage() 行中添加了.sendToTarget(),但这会导致没有微调器出现,并且程序崩溃。

编辑 2:

我还要补充一点,readWaves 函数使用现有的正在运行的线程来执行。我不确定这是否有什么不同

编辑 3:

这里我更新了最初提交的第二个代码块。使用此代码,进度对话框永远不会显示自己。代码执行时,涉及ProgressDialog 的所有代码根本不存在。

private void readWaves() {
    if( spinnerChoice == 0 ) {
        Log.i( "IN IF", "IN IF" );
        // Diff Voltage
        waveResults = RelayAPIModel.NativeCalls.GetWavesJava( RelayAPIModel.WAVES_V );
    } else {
        // Current 
        waveResults = RelayAPIModel.NativeCalls.GetWavesJava( RelayAPIModel.WAVES_I );
    }

    pd.dismiss();
    updateGraph();
    netV1Check.setChecked( true );
    netV2Check.setChecked( true );
    netV3Check.setChecked( true );
    vdi1Check.setChecked( true );
    vdi2Check.setChecked( true );
    vdi3Check.setChecked( true );
    hasRead = true;

}

编辑 4: 这是我最近的代码。 ProgressDialog 显示在我想要的位置,但微调器不旋转。我尝试将pd.dismiss() 替换为pd.hide() 并将pd.dismiss() 稍后放入代码中,但这会导致对话框始终停留在屏幕上。而且由于使用了.setCancelable(false),我永远无法退出它。我还在 onClickListener 之外声明了pd,因为我无法将参数this 传递给OnClickListener 内的ProgressDialog。我不记得我可以传递给它什么让它工作,我尝试了getApplicationContext()ClassName.javaClassName.class,但它们都没有工作。

    readButton = (Button) findViewById( R.id.readButton );
    final ProgressDialog pd = new ProgressDialog( this );  
    readButton.setOnClickListener( new OnClickListener() {
        public void onClick(View arg0) {
            pd.setProgressStyle(ProgressDialog.STYLE_SPINNER);
            pd.setMessage("Reading...");
            pd.setCancelable(false);            
            pd.show( );

            Thread export = new Thread() {  
                 public void run() {
                        if( myService.getState() != 3 ) {
                            Log.i( "myService", "12222" ); 
                            myService.setHandler( mHandler );
                            myService.connect( MainMenu.previousDevice, true );
                        } else {
                            runOnUiThread(new Runnable() {
                                public void run() {
                                    readWaves();
                                }
                            });
                        }
                 mHandler.obtainMessage(MainMenu.READ_FINISHED ).sendToTarget();
                 pd.dismiss();
                 }
            };
            export.start(); 

编辑 5: 试图让微调器出现在 if 语句中:

    readButton = (Button) findViewById( R.id.readButton );
    readButton.setOnClickListener( new OnClickListener() {
        public void onClick(View arg0) {
            final ProgressDialog pd = new ProgressDialog( Waves.this );  
            pd.setProgressStyle(ProgressDialog.STYLE_SPINNER);
            pd.setMessage("Reading...");
            pd.setCancelable(false);            
            pd.show( );

            Thread export = new Thread() {  
                 public void run() {
                        if( myService.getState() != 3 ) {
                            Log.i( "myService", "12222" ); 
                            myService.setHandler( mHandler );
                            runOnUiThread( new Runnable() {
                                public void run() {
                                    myService.connect( MainMenu.previousDevice, true );
                                }
                            });
                        } else {
                            runOnUiThread(new Runnable() {
                                public void run() {
                                    readWaves();
                                }
                            });
                        }
                 mHandler.obtainMessage(MainMenu.READ_FINISHED ).sendToTarget();
                 pd.dismiss();
                 }
            };
            export.start();

【问题讨论】:

  • 使用您的第二个版本,我有几个问题: 1. readWaves() 是否以任何方式更新 UI,或触摸任何 UI 树对象? 2.您是否将您的progressDialog 声明为final? 3. 为什么 pd.dismiss() 在 readWaves() 和末尾,而不是在你的 Thread 的 run() 的 AFTER readWaves() 行中?
  • 其实这一切都归结为 updateGraph();做。它有什么作用?
  • @varevarao 看看我的第三次编辑。所有 UI 都在 updateGraph() 内更新,而不是在 readWaves() 内更新。
  • 宾果游戏,等一下。我可能已经解决了你的问题。

标签: android android-ndk java-native-interface progressdialog


【解决方案1】:

鉴于您提到了All UI is updated within updateGraph(),您的代码(来自第二次编辑,大部分是正确的)正在抛出CalledFromWrongThreadException。您的updateGraph() 方法是从readWaves() 方法调用的,而该方法又是从您创建的new Thread() 调用的。这意味着您正在尝试从不是这些视图的实际父级的线程更新某些视图。

试试:

final ProgressDialog pd = new ProgressDialog( this );  
pd.setProgressStyle(ProgressDialog.STYLE_SPINNER);
pd.setMessage("Reading...");
pd.setCancelable(false);            
pd.show( );
Thread export = new Thread() {  
    public void run() {
        if( myService.getState() != 3 ) {
            Log.i( "myService", "12222" );
                myService.setHandler( mHandler );
                myService.connect( MainMenu.previousDevice, true );
        } else {
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    readWaves();
                }
            });
            pd.dismiss();
        }
        mHandler.obtainMessage(MainMenu.READ_FINISHED );
    }
}.start();

runOnUiThread() 调用确保由updateGraph()readWaves() 完成的 UI 更新在 UI 线程上完成。哦,你可以删除readWaves()末尾的pd.dismiss()

编辑:对于不旋转的微调器,有一个 question here。解决方案说:

如果您关闭一个对话框,则不得再次显示相同的实例。 要么创建一个新的,要么使用 hide() 而不是 dismiss()。什么时候 使用 hide() 您仍然需要在不再需要时将其关闭。

编辑

还请注意,在上面的代码中,我已将 ProgressDialog 的声明(在您的情况下是全局的)移动到 onClick() 事件处理程序的本地上下文中。这意味着为新的单击事件创建了一个新的 ProgressDialog。如果您以任何方式泄露了这种模式,请告诉我。

我不记得我可以传递给它什么让它工作,我试过了 getApplicationContext()、ClassName.java 和 ClassName.class 但没有 其中有工作。

试试ClassName.this

【讨论】:

  • 谢谢,这就是我想要的 95%。完成阅读后,进度对话框会显示并消失。但是,对话框中的微调器不旋转。它处于初始状态。有什么想法吗?
  • 啊,实际上这并不完全有效。我第一次尝试它时,微调器出现了它应该有的整个时期。但现在,每次我希望它出现时,它只会在最后在屏幕上闪烁。
  • 好的,等一下,让我在这里胡闹一下抱歉。
  • @JuiCe,尝试将 pd.dismiss() 放入 runOnUiThread() 方法中,在 readWaves() 之后,让我知道这是否有效。
  • 我不知道发生了什么。我正在尝试使用hide()dismiss() 或同时使用这两种不同的变体,但我得到的最好的结果是显示的对话框没有旋转。我需要继续搞砸以缩小我的问题所在。我稍后会回复你。不过感谢您的帮助。
【解决方案2】:

这可能是异步问题,尝试显示对话然后使用异步处理程序来触发长任务(您的本机调用)。我也必须处理这个问题,因为有时像“解雇”/“显示”这样的事情会发布到消息队列中,然后你用长任务阻止它。尽量使用线程处理长任务,不要阻塞 UI

在这里查看我的博文:

Progress Dialogue in Android

【讨论】:

  • 我试了一下,但效果不太顺利。如果您想看一下,我编辑了我的代码。还是谢谢
  • 如果未显示 4222,那么您的代码的 native/C 内容中肯定存在错误(在 readWaves() 中)。我对您的建议是使用以下内容检测您的所有本机 C 代码:#include ......in code: __android_log_print(ANDROID_LOG_DEBUG, DEBUG_TAG, "NDK:MyApp: [%s] ", 我的整数);
  • 我不认为这是我的 C 代码中的错误。没有ProgressDialog,代码可以 100% 正常工作。
  • 您通过以下方式关闭对话:handler.sendEmptyMessage(0);然后像这样处理: public void handleMessage(Message msg) { dialog.dismiss(); } };
  • 如果您的代码看到 3222 而不是 4222,那么 readWaves() 应该受到责备吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-06-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多