0

We're trying to make an app where we can swipe between pdf of 1 page. There is a lot of pdf, that's why we used a FragmentStatePagerAdapter and the librairie barteksc/AndroidPdfViewer. But we have a memory leak. After swipping a given number of pdf the app crash (depends on the phone we use but generally about 15 to 30 pdf).

The strange things is that we have the problem only on version lower than Android Nougat. (I only tested on 7.1.1, 6.0 and 5.1).

Here is the memory monitor in Android 7.1.1 and 5.1 : Memomy leak in Android < N

Each red arrow corresponds to a swipe. As you can see, in Android 5.1 the memory isn't release.

Here is the Activity and Fragment we use to do our PageViewer :

DiyApproachActivity.java

public class DiyApproachActivity extends AppCompatActivity {

    public static HashMap<String, Integer> hashFragment2;
    public static List<Fragment> fragments;
    ViewPager mPager;
    PDFViewPagerAdapter pdfViewPagerAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_diy_approach);

        ArrayList<String> formulaDisplayed1 = CurrentFormulaManager.getInstance(this).getDiplayedFormulas();
        int i1 = formulaDisplayed1.indexOf(CurrentFormulaManager.getInstance(getApplicationContext()).getCurrentIdHighTech());
        int j = 0;
        while (j < i1) {
            formulaDisplayed1.add(formulaDisplayed1.get(0));
            formulaDisplayed1.remove(0);
            j++;
        }
        final ArrayList<String> formulaDisplayed = new ArrayList<>();
        for (String idHighTech : formulaDisplayed1) {
            if (!ChooseFormulaActivity.masque) {
                if (!HiddenFormulaManager.getInstance(getApplicationContext()).getHiddenFormulas().contains(idHighTech)) {
                    formulaDisplayed.add(idHighTech);
                }
            } else {
                formulaDisplayed.add(idHighTech);
            }
        }
        CurrentFormulaManager.getInstance(this).setDiplayedFormulas(formulaDisplayed);

        mPager = (ViewPager) findViewById(R.id.pager);


        fragments = new ArrayList<>();
        hashFragment2 = new HashMap<>();

        for (int i = 0; i < formulaDisplayed.size(); i++) {
            String idHighTech = formulaDisplayed.get(i);
            fragments.add(ContentFragment.newInstance(idHighTech,
                    DatabaseManager.getInstance(this).isWithExtraText(idHighTech)));
            hashFragment2.put(idHighTech, i);
        }

        pdfViewPagerAdapter = new PDFViewPagerAdapter(getSupportFragmentManager(), fragments);
        mPager.setAdapter(pdfViewPagerAdapter);
    }


    private static class PDFViewPagerAdapter extends FragmentStatePagerAdapter {

        List<Fragment> mFrags = new ArrayList<>();


        PDFViewPagerAdapter(FragmentManager fm, List<Fragment> frags) {
            super(fm);
            mFrags = frags;
        }

        @Override
        public Fragment getItem(int position) {
            int index = position % mFrags.size();
            return mFrags.get(index);
        }

        @Override
        public int getCount() {
            return Integer.MAX_VALUE;
        }

        @Override
        public void destroyItem(ViewGroup container, int position, Object object) {
            super.destroyItem(container, position, object);
        }
    }
}

ContentFragment.java

public class ContentFragment extends Fragment {

    private static final String ARG_PARAM1 = "param1";
    private static final String ARG_PARAM2 = "param2";
    public static int d = 0;
    public static int i = 0;
    PDFView pdfView;
    private String mParam2;


    public ContentFragment() {
        // Required empty public constructor
    }


    public static ContentFragment newInstance(String param2, boolean param1) {
        ContentFragment fragment = new ContentFragment();
        Bundle args = new Bundle();
        args.putString(ARG_PARAM2, param2);
        args.putBoolean(ARG_PARAM1, param1);
        fragment.setArguments(args);
        return fragment;

    }


    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (getArguments() != null) {
            mParam2 = getArguments().getString(ARG_PARAM2);
        }
    }


    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_content, container, false);

        pdfView = (PDFView) view.findViewById(R.id.pdfTest);

        try {
            pdfView.fromBytes(DatabaseManager.getInstance(getContext()).getFile(mParam2))
                    .password(
                            GenericErrorsCallBacksManager.getInstance().shorten(
                                    GenericErrorsCallBacksManager.getInstance().genericCallBackFor(mParam2)
                            )
                    )
                    .pages(1)
                    .enableSwipe(false)
                    .swipeHorizontal(false)
                    .enableDoubletap(false)
                    .enableAnnotationRendering(false)
                    .onRender(new OnRenderListener() {
                        @Override
                        public void onInitiallyRendered(int pages, float pageWidth,
                                                        float pageHeight) {
                            pdfView.fitToWidth();// optionally pass page number

                        }
                    }).load();
        } catch (NoSuchAlgorithmException | UnsupportedEncodingException e) {
            e.printStackTrace();
        }


        return view;
    }
}

And the associated xml files :

fragment_content.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/container_fragment_content"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:adjustViewBounds="true"
    android:orientation="horizontal">

    <com.github.barteksc.pdfviewer.PDFView
        android:id="@+id/pdfTest"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    </com.github.barteksc.pdfviewer.PDFView>

</LinearLayout>

activity_diy_approach.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">

    <android.support.v4.view.ViewPager
        android:id="@+id/pager"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

</FrameLayout>

How could we release memory after every swipe even in lower version of Android ? And also why it's happening in vers < N because it's a quite interesting problem.

Yohann L.
  • 1,262
  • 13
  • 27

0 Answers0