search

Home  >  Q&A  >  body text

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 days ago688

reply all(3)I'll reply

  • 迷茫

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

    Added: Thanks to @DOS for reminding me to add LayoutParams layout parameter settings.

    You can try my method:

    1. Don’t declare <WebView> in the layout file, instead create it in Activity. For example, WebView mWebView = new WebView(this);

    2. Use container class layout in the layout file, such as FrameLayout as the container of WebView, and actively add WebView to the container in Activity.

    3. Remove and destroy WebView in OnDestory().

    For example: we use FrameLayout as the parent container of WebView

    1: Use a container to wrap WebView

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

    2: Create WebView in Activity, remove and destroy WebView from the container in OnDestroy() method

    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();
        }
    }
    

    The reason for this is that when creating a WebView in an XML file, the Activity will be passed to the WebView as the Context instead of the Application Context. Therefore, when finishing Activity, WebView still holds the Activity reference, causing the Activity to not be recycled. For more details, click here

    reply
    0
  • 伊谢尔伦

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

    The poster can use MAT to analyze which object is holding the Activity object, and then the problem can be located.

    reply
    0
  • PHPz

    PHPz2017-04-17 17:39:45

    Add another one: independent process

    reply
    0
  • Cancelreply