进度对话框未在show / dismiss之间显示JNI Native Call

时间:2012-12-28 18:44:48

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

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

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端进行描述。

I / O流共有六种Java函数,它们在整个应用程序中使用了很多次,而不仅仅是这一次调用。我考虑将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 )。微调器确实出现了,但程序在几秒钟内崩溃并重新启动。我在.sendToTarget()行中添加了mHandler.obtainMessage(),但这导致没有出现微调器,并且程序崩溃了。

编辑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传递给ProgressDialog中的OnClickListener。我不记得我可以传递给它以使它工作,我尝试了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();

2 个答案:

答案 0 :(得分:2)

鉴于您已经提到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()pd.dismiss()完成的UI更新是在UI线程上完成的。哦,你可以删除readWaves()末尾的onClick()

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

  

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

修改

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

  

我不记得我可以传递给它以使它工作,我试过   getApplicationContext(),ClassName.java和ClassName.class但没有   他们工作了。

尝试{{1}}。

答案 1 :(得分:0)

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

请看我的博客文章:

Progress Dialogue in Android