cari

Rumah  >  Soal Jawab  >  teks badan

android-studio - android webview 内存泄漏

每次启动这个activity memory allocated 逐渐增加,且不会被回收
求解决方案,下面是具体实现

public class NetWork {

    private static AuthApi authApi;
    private static UserApi userApi;

    private static Converter.Factory gsonConverterFactory= GsonConverterFactory.create();
    private static CallAdapter.Factory rxJavaCallAdapterFactory= RxJavaCallAdapterFactory.create();

    public static AuthApi getAuthApi(){
        Log.d("NetWork", "authApi==null:" + (authApi == null));
        if(authApi == null){
            Retrofit retrofit=new Retrofit.Builder()
                    .baseUrl(UrlConfig.ACCESS_TOKEN)
                    .addCallAdapterFactory(rxJavaCallAdapterFactory)
                    .addConverterFactory(gsonConverterFactory)
                    .build();
            authApi=retrofit.create(AuthApi.class);

        }
        return authApi;
    }

    public static UserApi getUserApi(){
        Log.d("NetWork", "userApi==null:" + (userApi == null));
        if(userApi == null){
            Retrofit retrofit=new Retrofit.Builder()
                    .baseUrl(UrlConfig.BASE_URL)
                    .addCallAdapterFactory(rxJavaCallAdapterFactory)
                    .addConverterFactory(gsonConverterFactory)
                    .build();
            userApi=retrofit.create(UserApi.class);

        }
        return userApi;
    }
}
public class OAuthLoginActivity extends AppCompatActivity {
    private WebViewProgress mWebView;

    Subscription mSubscription;
    Subscription mProgressSubscription;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_oauth);
        initView();
        /*
        * 1.getCode client_id scope
        * 2.getToken client_id client_secret code
        * */

        mWebView.loadUrl(UrlConfig.LOGIN_URL);
        Log.d("webViewURL",mWebView.getUrl());

    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mWebView.removeAllViews();        
        mWebView.destroy();
        if(mSubscription!=null){
            mSubscription.unsubscribe();
        }
        if(mProgressSubscription!=null){
            mProgressSubscription.unsubscribe();
        }
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {

        switch (item.getItemId()){
            case android.R.id.home:
                finish();
                return true;
        }
        return super.onOptionsItemSelected(item);
    }

    class MyWebViewClient extends WebViewClient{
        @Override
        public void onPageStarted(WebView view, String url, Bitmap favicon) {
            super.onPageStarted(view, url, favicon);
            Log.d("MyWebViewClient", url);
            if(url.contains("?code=")){
                Uri uri=Uri.parse(url);
                String code=uri.getQueryParameter("code");
                getUser(code);
            }
        }

        @Override
        public void onPageFinished(WebView view, String url) {
            super.onPageFinished(view, url);
            mProgressSubscription=Observable.timer(1, TimeUnit.SECONDS)
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribe(new Action1<Long>() {
                @Override
                public void call(Long aLong) {
                    mWebView.mProgressBar.setVisibility(View.GONE);
                }
            });

        }

    }

    private void initView(){

        Toolbar toolbar=(Toolbar) findViewById(R.id.toolbar);
        mWebView=(WebViewProgress) findViewById(R.id.web_view);
        toolbar.setTitle("授权登录");
        setSupportActionBar(toolbar);
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        WebSettings webSettings=mWebView.getSettings();
        webSettings.setJavaScriptEnabled(true);
        webSettings.setSupportZoom(true);
        webSettings.setBuiltInZoomControls(true);
        webSettings.setCacheMode(WebSettings.LOAD_NO_CACHE);
        mWebView.requestFocusFromTouch();
        mWebView.setWebViewClient(new MyWebViewClient());

    }

    private void getUser(String code){

        mSubscription=NetWork.getAuthApi().getAccessToken(UrlConfig.CLIENT_ID,UrlConfig.CLIENT_SECRET,code)
                .flatMap(new Func1<AccessToken, Observable<User>>() {
                    @Override
                    public Observable<User> call(AccessToken accessToken) {
                        return NetWork.getUserApi().getUser(accessToken.getAccess_token());
                    }
                })
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Observer<User>() {
                    @Override
                    public void onCompleted() {
                        Log.d("OAuthLoginActivity", "completed");
                    }

                    @Override
                    public void onError(Throwable e) {
                        Log.d("OAuthLoginActivity", "e:" + e);
                    }

                    @Override
                    public void onNext(User user) {
                        Log.d("OK",user.getLogin());
                        Toast.makeText(OAuthLoginActivity.this, user.getLogin(), Toast.LENGTH_SHORT).show();
                    }
                });
    }
}
PHP中文网PHP中文网2772 hari yang lalu689

membalas semua(3)saya akan balas

  • 迷茫

    迷茫2017-04-17 17:39:45

    补充:感谢@DOS提醒,增加LayoutParams布局参数设置。

    你可以试试我的方法:

    1. 不要在布局文件中声明<WebView>,改成在Activity中创建 如,WebView mWebView = new WebView(this);

    2. 在布局文件中用容器类布局,比如FrameLayout作为WebView的容器,在Activity中主动把WebView添加到容器中。

    3. 在OnDestory()中移除、销毁WebView。

    举个例子吧:我们用FrameLayout作为WebView的父容器

    1: 使用容器包裹WebView

    <FrameLayout
        android:id="@+id/container"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"/>
    

    2:在Activity中创建WebView,在OnDestroy()方法中从容器中移除、销毁WebView

    public class MyActivity extends Activity {
        private FrameLayout mContainer;
        private WebView mWebView;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
    
             ...
                
            mContainer = (FrameLayout) findViewById(R.id.container);
            mWebView = new WebView(this);
            ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(
                                   ViewGroup.LayoutParams.MATCH_PARENT,
                                   ViewGroup.LayoutParams.MATCH_PARENT);
            mWebView.setLayoutParams(p);
            mContainer.addView(mWebView);
        }
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
            mContainer.removeAllViews();
            mWebView.destroy();
        }
    }
    

    之所以这么做的原因是在XML文件中创建WebView,会把Activity作为Context传给WebView,而不是Application Context。所以在finishingActivity的时候,WebView任然持有Activity引用,导致Activity无法被回收。更多详情,戳这里

    balas
    0
  • 伊谢尔伦

    伊谢尔伦2017-04-17 17:39:45

    楼主可以使用MAT分析一下,具体是哪个对象在持有Activity对象,然后在就可以定位到问题了。

    balas
    0
  • PHPz

    PHPz2017-04-17 17:39:45

    再加个:独立进程

    balas
    0
  • Batalbalas