Window从Dialog中泄露

时间:2012-03-04 02:13:31

标签: android memory-leaks progressdialog toast

我有一个典型的WindowLeaked异常

  

03-03 21:03:26.441:ERROR / WindowManager(631):活动   com.myapp.Player泄漏了窗口   com.android.internal.policy.impl.PhoneWindow$DecorView@45136c38那个   最初被添加到这里03-03 21:03:26.441:   ERROR / WindowManager(631):android.view.WindowLeaked:Activity   com.myapp.Player泄漏了窗口   com.android.internal.policy.impl.PhoneWindow$DecorView@45136c38那个   最初被添加到这里03-03 21:03:26.441:   错误/ WindowManager(631):at   android.view.ViewRoot。(ViewRoot.java:247)03-03 21:03:26.441:   错误/ WindowManager(631):at   android.view.WindowManagerImpl.addView(WindowManagerImpl.java:148)   03-03 21:03:26.441:ERROR / WindowManager(631):at   android.view.WindowManagerImpl.addView(WindowManagerImpl.java:91)   03-03 21:03:26.441:ERROR / WindowManager(631):at   android.view.Window $ LocalWindowManager.addView(Window.java:424)03-03   21:03:26.441:ERROR / WindowManager(631):at   android.app.Dialog.show(Dialog.java:241)03-03 21:03:26.441:   错误/ WindowManager(631):at   android.app.AlertDialog $ Builder.show(AlertDialog.java:802)03-03   21:03:26.441:ERROR / WindowManager(631):at   android.widget.VideoView $ 4.onError(VideoView.java:387)03-03   21:03:26.441:ERROR / WindowManager(631):at   android.media.MediaPlayer $ EventHandler.handleMessage(MediaPlayer.java:1264)   03-03 21:03:26.441:ERROR / WindowManager(631):at   android.os.Handler.dispatchMessage(Handler.java:99)03-03   21:03:26.441:ERROR / WindowManager(631):at   android.os.Looper.loop(Looper.java:123)03-03 21:03:26.441:   错误/ WindowManager(631):at   android.app.ActivityThread.main(ActivityThread.java:4627)03-03   21:03:26.441:ERROR / WindowManager(631):at   java.lang.reflect.Method.invokeNative(Native Method)03-03   21:03:26.441:ERROR / WindowManager(631):at   java.lang.reflect.Method.invoke(Method.java:521)03-03 21:03:26.441:   错误/ WindowManager(631):at   com.android.internal.os.ZygoteInit $ MethodAndArgsCaller.run(ZygoteInit.java:868)   03-03 21:03:26.441:ERROR / WindowManager(631):at   com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)03-03   21:03:26.441:ERROR / WindowManager(631):at   dalvik.system.NativeStart.main(原生方法)

到目前为止,我所阅读的答案似乎都无法解决。这是代码:

mVideoView.setOnErrorListener(new OnErrorListener() {
    @Override
    public boolean onError(MediaPlayer arg0, int arg1, int arg2) {
        Toast.makeText(Player.this, "Sorry, unable to play this video", Toast.LENGTH_LONG).show();
        progressDialog.dismiss();
        if (mToken != null) {
            MusicUtils.unbindFromService(mToken);
        }
        finish();
        return false;
    }
});

我留下的唯一猜测是吐司坚持活动,但我正在阅读的所有东西似乎都说吐司并不重要。我甚至尝试使用getBaseContext(),然后尝试在finish()之后放置toast以查看它是否可行。我完全没有想法,所以任何帮助都会很棒。

更新:以下是更多代码

@Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        extras = getIntent().getExtras();
        media_url = extras.getString("media_url");
        setContentView(R.layout.video_player);
        //Start progress dialog so user knows something is going on
        progressDialog = ProgressDialog.show(this, "", "Loading...", true);
        mVideoView = (VideoView) findViewById(R.id.surface_view);

        runOnUiThread(new Runnable(){
            public void run() {
                playVideo();
            }
        });
    }

    private void playVideo() {
        try {
            if (media_url == null || media_url.length() == 0) {
                progressDialog.dismiss();
                Toast.makeText(VideoPlayer.this, "File URL/media_url is empty",
                        Toast.LENGTH_LONG).show();

            } else {
                // If the path has not changed, just start the media player
                if (media_url.equals(current) && mVideoView != null) {
                    mVideoView.start();
                    mVideoView.requestFocus();
                    return;
                }
                current = media_url;
                mVideoView.setVideoURI(Uri.parse(media_url));
                ctlr=new MediaController(VideoPlayer.this);
                ctlr.setMediaPlayer(mVideoView);
                mVideoView.setMediaController(ctlr);
                mVideoView.requestFocus();
                mVideoView.setOnPreparedListener(new OnPreparedListener() {

                    public void onPrepared(MediaPlayer arg0) {
                        progressDialog.dismiss();
                        mVideoView.start();
                    }
                });
                mVideoView.setOnErrorListener(new OnErrorListener() {

                    @Override
                    public boolean onError(MediaPlayer arg0, int arg1, int arg2) {
                        Toast.makeText(VideoPlayer.this, "Sorry, unable to play this video",
                                Toast.LENGTH_LONG).show();
                        progressDialog.dismiss();
                        if (mToken != null) {
                            MusicUtils.unbindFromService(mToken);
                        }
                        finish();
                        return false;
                    }
                });


            }
        } catch (Exception e) {
            Log.e(TAG, "error: " + e.getMessage(), e);
            if (mVideoView != null) {
                mVideoView.stopPlayback();
            }
            finish();
        }
    }

    private void startPlayback() {

        if(mService == null)
            return;
        Intent intent = getIntent();
        String filename = "";
        Uri uri = intent.getData();
        if (uri != null && uri.toString().length() > 0) {
            String scheme = uri.getScheme();
            if ("file".equals(scheme)) {
                filename = uri.getPath();
            } else {
                filename = uri.toString();
            }
            try {
                mService.stop();
                mService.openFileAsync(filename);
                mService.play();
                setIntent(new Intent());
            } catch (Exception ex) {
                Log.e(tag, "couldn't start playback: " + ex);
            }
        }
    }

    private ServiceConnection osc = new ServiceConnection() {
        public void onServiceConnected(ComponentName classname, IBinder obj) {
            mService = IMediaPlaybackService.Stub.asInterface(obj);
            startPlayback();
        }
        public void onServiceDisconnected(ComponentName classname) {
            mService = null;
        }
     };

当设备无法播放的视频类型时出现错误

2 个答案:

答案 0 :(得分:2)

也许你可以尝试通过runOnUiThread来展示你的祝酒词?

类似的东西:

    @Override
    public boolean onError(MediaPlayer arg0, int arg1, int arg2) {
       Player.this.runOnUiThread(new Runnable() {
           void run() {
               Toast.makeText(Player.this, "Sorry, unable to play this video", Toast.LENGTH_LONG).show();
               progressDialog.dismiss();
               if (mToken != null) {
                    MusicUtils.unbindFromService(mToken);
                }
                finish();
           }
        );
        return false;
    }

修改

以下是更多...以下是VideoView的代码(在Froyo中)。

似乎错误来自AlertDialog.Builder ......但是基于你的代码,它甚至不应该到达那里,因为当mOnErrorListener不为null时错误应该被处理得更高......

您可以检查是否正在调用您的错误处理程序吗?也许尝试不在那里调用finish()?

 private MediaPlayer.OnErrorListener mErrorListener =
        new MediaPlayer.OnErrorListener() {
        public boolean onError(MediaPlayer mp, int framework_err, int impl_err) {
            Log.d(TAG, "Error: " + framework_err + "," + impl_err);
            mCurrentState = STATE_ERROR;
            mTargetState = STATE_ERROR;
            if (mMediaController != null) {
                mMediaController.hide();
            }

            /* If an error handler has been supplied, use it and finish. */
            if (mOnErrorListener != null) {
                if (mOnErrorListener.onError(mMediaPlayer, framework_err, impl_err)) {
                    return true;
                }
            }

            /* Otherwise, pop up an error dialog so the user knows that
             * something bad has happened. Only try and pop up the dialog
             * if we're attached to a window. When we're going away and no
             * longer have a window, don't bother showing the user an error.
             */
            if (getWindowToken() != null) {
                Resources r = mContext.getResources();
                int messageId;

                if (framework_err == MediaPlayer.MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK) {
                    messageId = com.android.internal.R.string.VideoView_error_text_invalid_progressive_playback;
                } else {
                    messageId = com.android.internal.R.string.VideoView_error_text_unknown;
                }

                new AlertDialog.Builder(mContext)
                        .setTitle(com.android.internal.R.string.VideoView_error_title)
                        .setMessage(messageId)
                        .setPositiveButton(com.android.internal.R.string.VideoView_error_button,
                                new DialogInterface.OnClickListener() {
                                    public void onClick(DialogInterface dialog, int whichButton) {
                                        /* If we get here, there is no onError listener, so
                                         * at least inform them that the video is over.
                                         */
                                        if (mOnCompletionListener != null) {
                                            mOnCompletionListener.onCompletion(mMediaPlayer);
                                        }
                                    }
                                })
                        .setCancelable(false)
                        .show();
            }
            return true;
        }
    };

更多编辑:

将onError处理程序更改为return true;

然后“默认”错误处理程序将不会尝试构建此AlertDialog

答案 1 :(得分:0)

错误监听器事件可能不会在UI(looper)线程上回复给您。您需要将事件发布到处理程序(在UI线程上注册),让处理程序显示Toast并关闭进度对话框。