0

I'm developing an Android app using Xamarin studio, but this is not important.

I use the pageViewer to upload the fragment (12 more or less). To the one display fragment i use a webView to display a local html page and with a swipe to the left, the webview content change to the next one.

So, at the fifth frgament memory problems started even if i used different tasks in my code.

My question is: Is there a way to 'detach' the fragment when i'm not displaying them? Can they not remain into my memory?

Thanks for all

This is my code, N.B: Java answers are accepeted as well

 protected override void OnCreate (Bundle bundle)
    {
        base.OnCreate (bundle);

        SetContentView (Resource.Layout.BookView);

        _loader = ProgressDialog.Show (this, "Loading...", "Please wait...", true);


        //return chapters count
        chapters = 12 //example

        //var dp = (int)Resources.DisplayMetrics.Density;

        _layout = FindViewById<DrawerLayout> (Resource.Id.drawer_layout);


        _view = FindViewById<ViewPager>(Resource.Id.bView);
        _view.SetBackgroundColor (Color.White);

        _currentAdapter = new AwesomeFragmentAdapter (SupportFragmentManager, path, name, chapters, this, _view);

        _view.Adapter = _currentAdapter;
        _view.OffscreenPageLimit = chapters;


        List<int> positions = new List<int> ();

        _view.PageSelected += (object sender, ViewPager.PageSelectedEventArgs e) => {

            //get details
            var page_load = new Task (() => {
                //return an object with the chapter details
                _chap = object;
            });
            page_load.Start();

            //find the webview
            _web = (WebView)_view.FindViewWithTag(300 + e.Position);

            WebSettings setting = _web.Settings;
            setting.CacheMode = CacheModes.Default;
            setting.JavaScriptEnabled = true;
            setting.BuiltInZoomControls = true;
            setting.DisplayZoomControls = false;
            setting.PluginsEnabled = true;
            setting.SetPluginState(WebSettings.PluginState.On);
            //setting.JavaScriptCanOpenWindowsAutomatically = true;

            if (positions.Contains(e.Position)) {
                _web.ClearCache(true);
                _web.ClearView();

            } 

        //Start when the scroll is finished

            _view.PageScrollStateChanged += (object sendero, ViewPager.PageScrollStateChangedEventArgs ex) => {
                if (ex.State == 0 ) {
                    if (positions.Contains(e.Position)) {
                        //_web.Reload(); --> doesn't work
                        //Doesn't reload the .js animations

                        _web.LoadUrl ("file://" + path + "/" + _chap.Name);
                    } else {
                        _web.LoadUrl ("file://" + path + "/" + _chap.Name); 
                        positions.Add(e.Position);
                    }
                } 
            };
        };    

}



public class BWebClient : WebViewClient
{
    int _position;
    string _path;
    Activity _parent;
    ViewPager _pager;
    string _chapName;
    public BWebClient (int position, string Path, Activity Parent, ViewPager Pager, string ChapName){
        _position = position;
        _parent = Parent;
        _path = Path;
        _pager = Pager;
        _chapName = ChapName;
    }


    public override void OnPageFinished (WebView view, string url)
    {
        base.OnPageFinished (view, url);
        view.ScrollTo (0, _position);
    }

    public override bool ShouldOverrideUrlLoading (WebView view, string url)
    {

        if (url.StartsWith ("navigate")) {
            string destination = url.Substring (url.IndexOf ("navigate://") + "navigate://".Length);
            int DestinationChapter = Int32.Parse (destination.Substring (0, destination.IndexOf("_")));
            int l = destination.IndexOf("_") + 1;
            int b = destination.Length - l;
            int DestinationPage = Int32.Parse (destination.Substring (l,b));



            if (DestinationPage == 0) {
                _pager.SetCurrentItem(DestinationChapter ,true);
                WebView _web = (WebView)_pager.FindViewWithTag(300 + DestinationChapter);
                _web.LoadUrl ("file://" + _path + "/" + _chapName);
            }



        } else if (url.StartsWith ("pdf")) {
            string file_path = System.IO.Path.Combine (_path, url.Substring (url.IndexOf ("pdf://") + "pdf://".Length));
            Android.Net.Uri pdfFile = Android.Net.Uri.FromFile (new Java.IO.File (file_path));
            Intent pdfIntent = new Intent (Intent.ActionView);
            pdfIntent.SetDataAndType (pdfFile, "application/pdf");
            _parent.StartActivity (pdfIntent);
        }

        return true;
    }
}




public class AwesomeFragmentAdapter : FragmentPagerAdapter
{
    string _path;
    string _filename;
    int _chapters;
    Activity _parent;
    FileUtilities _fUtils;
    ViewPager _pager;

    public AwesomeFragmentAdapter (Android.Support.V4.App.FragmentManager fm, 
        string path, 
        string filename,  
        int chapters,
        Activity  parent,
        FileUtilities FUtils,
        ViewPager Pagers): base(fm)
    {
        _path = path;
        _filename = filename;
        _chapters = chapters;
        _parent = parent;
        _fUtils = FUtils;
        _pager = Pagers;
    }

    public override int Count
    {
        /* --- return chapter count --- */
        get { return  _chapters;}
    }


    public override Android.Support.V4.App.Fragment GetItem(int _position)
    {
        /* --- get specific item --- */
        return new AwesomeFragment (_path, _filename, _position, _parent, _fUtils, _pager);
    }
}

public class AwesomeFragment : Android.Support.V4.App.Fragment
{
    string _path;
    WebView web_view;
    string _filename;
    int _position;
    Activity _parent;
    BanjiChapter _chap;
    FileUtilities _fUtils;
    ViewPager _pager;

    public AwesomeFragment () {}

    public AwesomeFragment (string path, 
        string filename, 
        int position,
        Activity parent,
        FileUtilities FUtils,
        ViewPager Pager)
    {
        _path = path;
        _filename = filename;
        _position = position;
        _parent = parent;
        _fUtils = FUtils;
        _pager = Pager;
    }

    public override View OnCreateView (LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
    {
        /* --- Create the view --- */
        var view = inflater.Inflate (Resource.Layout.BookWebView, container, false);

    //return the chapter
        _chap = _fUtils.ReturnChapterDetails(_filename, _position);

        web_view = view.FindViewById<WebView> (Resource.Id.webview);


        web_view.SetWebViewClient(new BanjiWebClient(_position,_path,_parent, _pager, _chap.Name ));



        web_view.SetBackgroundColor(Color.Transparent);
        web_view.Settings.JavaScriptEnabled = true;
        web_view.Tag = 300 + _position;

        switch(Resources.DisplayMetrics.DensityDpi){
            case Android.Util.DisplayMetricsDensity.Medium:
                {
                    web_view.SetLayerType (LayerType.Software, null);
                    break;
                }
            case Android.Util.DisplayMetricsDensity.High:
                {
                    web_view.SetLayerType (LayerType.Hardware, null);
                    break;
                }
            case Android.Util.DisplayMetricsDensity.Xhigh:
                {
                    web_view.SetLayerType (LayerType.Hardware, null);
                    break;
                }
            }




        if (_chap.Background == null) {
            view.SetBackgroundColor (Color.White);
        } else {
            view.SetBackgroundDrawable (new BitmapDrawable (BitmapFactory.DecodeByteArray (_chap.Background, 0, _chap.Background.Length)));
        }

        if (_position == 0) {
            web_view.LoadUrl ("file://" + _path + "/" + _chap.Name);
        }

        return view;

    }

    public BChapter GetCurrentBChapter()
    {
        return _chap;
    }

}    

EDIT:

BookView.axml

    <?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#ffececec">
<!-- The main content view -->
    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/mainView">
        <android.support.v4.view.ViewPager
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:id="@+id/bookView" />
        <ImageButton
            android:layout_height="wrap_content"
            android:layout_width="wrap_content"
            android:layout_gravity="left|center"
            android:background="@null"
            android:id="@+id/menuButton"
             />
    </FrameLayout>
<!-- The navigation drawer -->
    <LinearLayout
        android:id="@+id/left_menu"
        android:layout_width="250dp"
        android:layout_height="match_parent"
        android:choiceMode="singleChoice"
        android:layout_gravity="start"
        android:divider="@android:color/transparent"
        android:dividerHeight="0dp"
        android:background="#111">
        <Button
            android:id="@+id/backStep"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            style="@style/button_text"
            android:background="#ff000000"
            android:fitsSystemWindows="false" />
        <Space
            android:layout_width="fill_parent"
            android:layout_height="wrap_content" />
        <ScrollView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:id="@+id/screllArea">
            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:id="@+id/ThumbLayout" />
        </ScrollView>
    </LinearLayout>
</android.support.v4.widget.DrawerLayout>

BookWebView

   <?xml version="1.0" encoding="utf-8"?>
<WebView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/webview"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />
BlackShawarna
  • 247
  • 8
  • 23

1 Answers1

1

Use a FragmentStatePagerAdapter instead; it is designed to minimise memory overhead by possibly destroying the fragment when it is not visible, saving only the state information of that fragment.

From the developers docs:

This version of the pager is more useful when there are a large number of pages, working more like a list view. When pages are not visible to the user, their entire fragment may be destroyed, only keeping the saved state of that fragment. This allows the pager to hold on to much less memory associated with each visited page as compared to FragmentPagerAdapter at the cost of potentially more overhead when switching between pages.

See here for documentation.

matthewrdev
  • 11,930
  • 5
  • 52
  • 64
  • Nope, unfortunately the memory problems still to exist. – BlackShawarna Sep 02 '14 at 23:22
  • Can you include the code for the BookView layout? There was an ongoing issue with WebViews being created through layout files being leaked. http://stackoverflow.com/questions/3130654/memory-leak-in-webview – matthewrdev Sep 03 '14 at 00:23
  • You may need to use both a state pager and create your webviews programatically to fix your mem-leak issues. I'll update answer a bit later. – matthewrdev Sep 03 '14 at 00:24