我已经在StackOverflow上阅读了几十个问题,但无法获得任何可靠的解决方案。
我有一项活动,我正在从服务器显示视频。视频是HTML5,因此,我使用HTML5WebView(只是一些方法覆盖,以支持播放HTML5视频,实际上取自互联网上的图书馆)。
在使用4.4.2的Nexus5上视频正常播放,但在2.3.6和2.3.5上播放时,内存泄漏并且应用程序崩溃。我不知道如何解决这个问题,所以如果有人可以提供帮助,那就太棒了。
我还读到这可能是一个错误,在较低版本中,但如果有解决方法,请建议。
这是我的代码......
custom_screen.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<FrameLayout
android:id="@+id/fullscreen_custom_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<FrameLayout
android:id="@+id/main_content"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</FrameLayout>
</LinearLayout>
</FrameLayout>
WebViewActivity.java
public class WebViewActivity extends Activity {
HTML5WebView mWebView;
public String url = "http://m.oxblue.com";
public String fileName = "OxBlue-Photo.png";
ProgressDialog pd;
@SuppressLint("NewApi")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (Const.DEBUGGING)
Log.d(Const.DEBUG, "***** WebViewActivity - onCreate *****");
mWebView = new HTML5WebView(this);
if (savedInstanceState != null) {
mWebView.restoreState(savedInstanceState);
} else {
if (Const.DEBUGGING)
Log.d(Const.DEBUG, "GLobal URL = " + url);
mWebView.setWebViewClient(new WebViewClient() {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
if (Const.DEBUGGING)
Log.d(Const.DEBUG, "URL = " + url);
view.loadUrl(url);
return true;
}
@Override
public void onPageStarted(WebView view, String url,
Bitmap favicon) {
super.onPageStarted(view, url, favicon);
pd = new ProgressDialog(WebViewActivity.this);
pd.setMessage("Loading...");
pd.show();
}
@Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
pd.dismiss();
}
});
mWebView.setDownloadListener(new DownloadListener() {
@Override
public void onDownloadStart(String url, String userAgent,
String contentDisposition, String mimetype,
long contentLength) {
Log.d(Const.DEBUG, "Dowloading...");
Log.d(Const.DEBUG, "URL = " + url);
DownloadFile downloadFile = new DownloadFile(
WebViewActivity.this);
downloadFile.execute(url);
}
});
mWebView.loadUrl(url);
}
setContentView(mWebView.getLayout());
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mWebView.saveState(outState);
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
}
@Override
public void onStop() {
super.onStop();
if (Const.DEBUGGING)
Log.d(Const.DEBUG, "***** WebViewActivity - onStop *****");
if (mWebView != null)
mWebView.stopLoading();
this.finish();
}
@Override
protected void onDestroy() {
super.onDestroy();
if (Const.DEBUGGING)
Log.d(Const.DEBUG, "***** WebViewActivity - onDestroy *****");
}
@Override
protected void onPause() {
super.onPause();
if (Const.DEBUGGING)
Log.d(Const.DEBUG, "***** WebViewActivity - onPause *****");
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (Const.DEBUGGING)
Log.d(Const.DEBUG, "***** WebViewActivity - onKeyDown *****");
if (keyCode == KeyEvent.KEYCODE_BACK) {
this.finish();
if (mWebView.inCustomView()) {
mWebView.hideCustomView();
return true;
}
}
return super.onKeyDown(keyCode, event);
}
public class DownloadFile extends AsyncTask<String, Void, Boolean> {
//AsyncTask to download file... not related to the problem.. so removed
}
}
HTML5WebView.java
public class HTML5WebView extends WebView {
Activity a;
private MyWebChromeClient mWebChromeClient;
private View mCustomView;
private FrameLayout mCustomViewContainer;
private WebChromeClient.CustomViewCallback mCustomViewCallback;
private FrameLayout mContentView;
private FrameLayout mBrowserFrameLayout;
private FrameLayout mLayout;
static final String LOGTAG = "HTML5WebView";
@SuppressLint("SetJavaScriptEnabled")
private void init(Context context) {
Context mContext;
if (Const.DEBUGGING)
Log.d(Const.DEBUG, "***** HTML5WebView - init *****");
mContext = context;
a = (Activity) mContext;
mLayout = new FrameLayout(context);
mBrowserFrameLayout = (FrameLayout) LayoutInflater.from(a).inflate(
R.layout.custom_screen, null);
mContentView = (FrameLayout) mBrowserFrameLayout
.findViewById(R.id.main_content);
mCustomViewContainer = (FrameLayout) mBrowserFrameLayout
.findViewById(R.id.fullscreen_custom_content);
mLayout.addView(mBrowserFrameLayout, COVER_SCREEN_PARAMS);
WebSettings s = getSettings();
s.setBuiltInZoomControls(true);
s.setSupportZoom(true);
s.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.NARROW_COLUMNS);
s.setUseWideViewPort(true);
s.setLoadWithOverviewMode(true);
s.setUseWideViewPort(true);
s.setSaveFormData(true);
s.setJavaScriptEnabled(true);
mWebChromeClient = new MyWebChromeClient();
setWebChromeClient(mWebChromeClient);
setWebViewClient(new WebViewClient());
setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY);
s.setDomStorageEnabled(true);
mContentView.addView(this);
}
public HTML5WebView(Context context) {
super(context);
if (Const.DEBUGGING)
Log.d(Const.DEBUG,
"***** HTML5WebView - Single Parameter Constructor *****");
init(context);
}
public HTML5WebView(Context context, AttributeSet attrs) {
super(context, attrs);
if (Const.DEBUGGING)
Log.d(Const.DEBUG,
"***** HTML5WebView - 2 Parameter Constructor *****");
init(context);
}
public HTML5WebView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
if (Const.DEBUGGING)
Log.d(Const.DEBUG,
"***** HTML5WebView - 3 Parameter Constructor *****");
init(context);
}
private boolean is_gone = false;
@Override
protected void onFocusChanged(boolean focused, int direction,
Rect previouslyFocusedRect) {
super.onFocusChanged(focused, direction, previouslyFocusedRect);
if (Const.DEBUGGING)
Log.d(Const.DEBUG, "***** HTML5WebView - onFocusChanged *****");
if (!focused) {
try {
WebView.class.getMethod("onPause").invoke(this);
} catch (Exception e) {
}
this.pauseTimers();
this.is_gone = true;
} else {
try {
WebView.class.getMethod("onResume").invoke(this);
} catch (Exception e) {
}
this.resumeTimers();
this.is_gone = false;
}
}
public void onWindowVisibilityChanged(int visibility) {
super.onWindowVisibilityChanged(visibility);
if (Const.DEBUGGING)
Log.d(Const.DEBUG, "***** HTML5WebView - onWindowVisibility *****");
if (visibility == View.GONE) {
try {
WebView.class.getMethod("onPause").invoke(this);
} catch (Exception e) {
}
this.pauseTimers();
this.is_gone = true;
} else if (visibility == View.VISIBLE) {
try {
WebView.class.getMethod("onResume").invoke(this);
} catch (Exception e) {
}
this.resumeTimers();
this.is_gone = false;
}
}
public void onDetachedFromWindow() {
super.onDetachedFromWindow();
if (Const.DEBUGGING)
Log.d(Const.DEBUG,
"***** HTML5WebView - onDetachedFromWindow *****");
mContentView.removeAllViews();
mBrowserFrameLayout.removeAllViews();
mLayout.removeAllViews();
if (this.is_gone) {
try {
this.destroy();
} catch (Exception e) {
e.printStackTrace();
}
}
if (Const.DEBUGGING)
Log.d(Const.DEBUG,
"***** HTML5WebView - onDetachedFromWindow - Ending *****");
}
public FrameLayout getLayout() {
if (Const.DEBUGGING)
Log.d(Const.DEBUG, "***** HTML5WebView - getLayout Method *****");
return mLayout;
}
public boolean inCustomView() {
if (Const.DEBUGGING)
Log.d(Const.DEBUG, "***** HTML5WebView - inCustomView Method *****");
return (mCustomView != null);
}
public void hideCustomView() {
if (Const.DEBUGGING)
Log.d(Const.DEBUG, "***** HTML5WebView - hideCustomView *****");
mWebChromeClient.onHideCustomView();
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (Const.DEBUGGING)
Log.d(Const.DEBUG, "***** HTML5WebView - onKeyDown *****");
if (keyCode == KeyEvent.KEYCODE_BACK) {
if ((mCustomView == null) && canGoBack()) {
goBack();
return true;
}
}
return super.onKeyDown(keyCode, event);
}
private class MyWebChromeClient extends WebChromeClient {
private View mVideoProgressView;
@Override
public void onShowCustomView(View view,
WebChromeClient.CustomViewCallback callback) {
if (Const.DEBUGGING)
Log.d(Const.DEBUG,
"***** HTML5WebView - MyWebChromeClient - onShowCustomView *****");
HTML5WebView.this.setVisibility(View.GONE);
if (mCustomView != null) {
callback.onCustomViewHidden();
return;
}
mCustomViewContainer.addView(view);
mCustomView = view;
mCustomViewCallback = callback;
mCustomViewContainer.setVisibility(View.VISIBLE);
}
@Override
public void onHideCustomView() {
if (Const.DEBUGGING)
Log.d(Const.DEBUG,
"***** HTML5WebView - MyWebChromeClient - onHideCustomView *****");
if (mCustomView == null)
return;
mCustomView.setVisibility(View.GONE);
mCustomViewContainer.removeView(mCustomView);
mCustomView = null;
mCustomViewContainer.setVisibility(View.GONE);
if (mCustomViewCallback != null)
mCustomViewCallback.onCustomViewHidden();
mBrowserFrameLayout.setVisibility(View.GONE);
HTML5WebView.this.setVisibility(View.VISIBLE);
a.finish();
}
@Override
public View getVideoLoadingProgressView() {
if (Const.DEBUGGING)
Log.d(Const.DEBUG,
"***** HTML5WebView - MyWebChromeClient - getVideoLoadingProgressView *****");
if (mVideoProgressView == null) {
LayoutInflater inflater = LayoutInflater.from(a);
mVideoProgressView = inflater.inflate(
R.layout.video_loading_progress, null);
}
return mVideoProgressView;
}
@Override
public void onGeolocationPermissionsShowPrompt(String origin,
GeolocationPermissions.Callback callback) {
if (Const.DEBUGGING)
Log.d(Const.DEBUG,
"***** HTML5WebView - MyWebChromeClient - onGeolocationPermissionsShowPrompt *****");
callback.invoke(origin, true, false);
}
}
static final FrameLayout.LayoutParams COVER_SCREEN_PARAMS = new FrameLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT);
}
Logcat追踪......
03-26 13:28:14.862: D/OxBlue(16557): ***** WebViewActivity - onPause *****
03-26 13:28:15.073: D/OxBlue(16557): ***** HTML5WebView - onWindowVisibility *****
03-26 13:28:15.133: D/OxBlue(16557): ***** WebViewActivity - onStop *****
03-26 13:28:15.133: D/webkit-timers(16557): [JWebCoreJavaBridge::pause] >> do pause
03-26 13:28:15.143: D/OxBlue(16557): ***** WebViewActivity - onDestroy *****
03-26 13:28:15.163: D/OxBlue(16557): ***** HTML5WebView - onDetachedFromWindow *****
03-26 13:28:15.163: D/OxBlue(16557): ***** HTML5WebView - onFocusChanged *****
03-26 13:28:15.163: D/OxBlue(16557): ***** HTML5WebView - onDetachedFromWindow *****
03-26 13:28:15.163: D/webviewglue(16557): nativeDestroy view: 0x2f0b68
03-26 13:28:15.163: D/OxBlue(16557): ***** HTML5WebView - onDetachedFromWindow - Ending *****
03-26 13:28:15.163: D/OxBlue(16557): ***** HTML5WebView - onDetachedFromWindow - Ending *****
03-26 13:28:15.183: E/WindowManager(16557): Activity com.xx.xxx.webview.WebViewActivity has leaked window com.android.internal.policy.impl.PhoneWindow$DecorView@405da260 that was originally added here
03-26 13:28:15.183: E/WindowManager(16557): android.view.WindowLeaked: Activity com.xx.xxx.webview.WebViewActivity has leaked window com.android.internal.policy.impl.PhoneWindow$DecorView@405da260 that was originally added here
03-26 13:28:15.183: E/WindowManager(16557): at android.view.ViewRoot.<init>(ViewRoot.java:277)
03-26 13:28:15.183: E/WindowManager(16557): at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:148)
03-26 13:28:15.183: E/WindowManager(16557): at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:91)
03-26 13:28:15.183: E/WindowManager(16557): at android.view.Window$LocalWindowManager.addView(Window.java:433)
03-26 13:28:15.183: E/WindowManager(16557): at android.app.Dialog.show(Dialog.java:265)
03-26 13:28:15.183: E/WindowManager(16557): at android.app.AlertDialog$Builder.show(AlertDialog.java:802)
03-26 13:28:15.183: E/WindowManager(16557): at android.widget.VideoView$4.onError(VideoView.java:386)
03-26 13:28:15.183: E/WindowManager(16557): at android.media.MediaPlayer$EventHandler.handleMessage(MediaPlayer.java:1476)
03-26 13:28:15.183: E/WindowManager(16557): at android.os.Handler.dispatchMessage(Handler.java:99)
03-26 13:28:15.183: E/WindowManager(16557): at android.os.Looper.loop(Looper.java:150)
03-26 13:28:15.183: E/WindowManager(16557): at android.app.ActivityThread.main(ActivityThread.java:4277)
03-26 13:28:15.183: E/WindowManager(16557): at java.lang.reflect.Method.invokeNative(Native Method)
03-26 13:28:15.183: E/WindowManager(16557): at java.lang.reflect.Method.invoke(Method.java:507)
03-26 13:28:15.183: E/WindowManager(16557): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
03-26 13:28:15.183: E/WindowManager(16557): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
03-26 13:28:15.183: E/WindowManager(16557): at dalvik.system.NativeStart.main(Native Method)
03-26 13:28:15.373: W/dalvikvm(16557): JNI: DeleteGlobalRef(0xde5deb2f) failed to find entry (valid=0)
03-26 13:28:15.373: W/dalvikvm(16557): JNI: DeleteGlobalRef(0xde5deb0f) failed to find entry (valid=0)
我在HTML5WebView中的removeAllViews()
中尝试了onDetachedFromWindow()
,但没有任何改变。
答案 0 :(得分:0)
由于在加载视频时遇到错误,它似乎正在泄漏一个它试图显示的AlertDialog
at android.app.AlertDialog$Builder.show(AlertDialog.java:802)
at android.widget.VideoView$4.onError(VideoView.java:386)
您是否可以从代码中访问VideoView?如果是这样,您可以尝试使用setOnErrorListener [1]在出错时运行空回调。我认为这是尝试弹出对话框的默认行为。