javaandroid-viewpagerandroid-glideandroid-photoview

How to handle StackOveflowError: stack size 8MB using PhotoView in Viewpager with glidev4?


I get this error when trying to swipe in the ViewPager Activity using the photoView library, I use Glide for the image, and the url are from an Intent(url are array). I also in download data from a firebase database using a model class.

enter image description here

This is the log:

06-27 14:36:33.291 6520-6520/com.realty.drake.kunuk E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.realty.drake.kunuk, PID: 6520
java.lang.StackOverflowError: stack size 8MB
    at android.support.v4.view.PagerAdapter.startUpdate(PagerAdapter.java:96)
    at android.support.v4.view.ViewPager.populate(ViewPager.java:1116)
    at android.support.v4.view.ViewPager.setCurrentItemInternal(ViewPager.java:662)
    at android.support.v4.view.ViewPager.setCurrentItemInternal(ViewPager.java:624)
    at android.support.v4.view.ViewPager.dataSetChanged(ViewPager.java:1078)
    at android.support.v4.view.ViewPager$PagerObserver.onChanged(ViewPager.java:3089)
    at android.support.v4.view.PagerAdapter.notifyDataSetChanged(PagerAdapter.java:284)
    at com.realty.drake.kunuk.ViewPagerActivity$SamplePagerAdapter.instantiateItem(ViewPagerActivity.java:45)
    at com.realty.drake.kunuk.ViewPagerActivity$SamplePagerAdapter.instantiateItem(ViewPagerActivity.java:34)
    at android.support.v4.view.ViewPager.addNewItem(ViewPager.java:1002)
    at android.support.v4.view.ViewPager.populate(ViewPager.java:1216)
    at android.support.v4.view.ViewPager.setCurrentItemInternal(ViewPager.java:662)
    at android.support.v4.view.ViewPager.setCurrentItemInternal(ViewPager.java:624)
    at android.support.v4.view.ViewPager.dataSetChanged(ViewPager.java:1078)
    at android.support.v4.view.ViewPager$PagerObserver.onChanged(ViewPager.java:3089)
    at android.support.v4.view.PagerAdapter.notifyDataSetChanged(PagerAdapter.java:284)
    at com.realty.drake.kunuk.ViewPagerActivity$SamplePagerAdapter.instantiateItem(ViewPagerActivity.java:45)
    at com.realty.drake.kunuk.ViewPagerActivity$SamplePagerAdapter.instantiateItem(ViewPagerActivity.java:34)
    at android.support.v4.view.ViewPager.addNewItem(ViewPager.java:1002)
    at android.support.v4.view.ViewPager.populate(ViewPager.java:1216)
    at android.support.v4.view.ViewPager.setCurrentItemInternal(ViewPager.java:662)
    at android.support.v4.view.ViewPager.setCurrentItemInternal(ViewPager.java:624)
    at android.support.v4.view.ViewPager.dataSetChanged(ViewPager.java:1078)
    at android.support.v4.view.ViewPager$PagerObserver.onChanged(ViewPager.java:3089)
    at android.support.v4.view.PagerAdapter.notifyDataSetChanged(PagerAdapter.java:284)
    at com.realty.drake.kunuk.ViewPagerActivity$SamplePagerAdapter.instantiateItem(ViewPagerActivity.java:45)
    at com.realty.drake.kunuk.ViewPagerActivity$SamplePagerAdapter.instantiateItem(ViewPagerActivity.java:34)
    at android.support.v4.view.ViewPager.addNewItem(ViewPager.java:1002)
    at android.support.v4.view.ViewPager.populate(ViewPager.java:1216)
    at android.support.v4.view.ViewPager.setCurrentItemInternal(ViewPager.java:662)
    at android.support.v4.view.ViewPager.setCurrentItemInternal(ViewPager.java:624)
    at android.support.v4.view.ViewPager.dataSetChanged(ViewPager.java:1078)
    at android.support.v4.view.ViewPager$PagerObserver.onChanged(ViewPager.java:3089)
    at android.support.v4.view.PagerAdapter.notifyDataSetChanged(PagerAdapter.java:284)
    at com.realty.drake.kunuk.ViewPagerActivity$SamplePagerAdapter.instantiateItem(ViewPagerActivity.java:45)
    at com.realty.drake.kunuk.ViewPagerActivity$SamplePagerAdapter.instantiateItem(ViewPagerActivity.java:34)
    at android.support.v4.view.ViewPager.addNewItem(ViewPager.java:1002)
    at android.support.v4.view.ViewPager.populate(ViewPager.java:1216)
    at android.support.v4.view.ViewPager.setCurrentItemInternal(ViewPager.java:662)
    at android.support.v4.view.ViewPager.setCurrentItemInternal(ViewPager.java:624)
    at android.support.v4.view.ViewPager.dataSetChanged(ViewPager.java:1078)
    at android.support.v4.view.ViewPager$PagerObserver.onChanged(ViewPager.java:3089)
    at android.support.v4.view.PagerAdapter.notifyDataSetChanged(PagerAdapter.java:284)
    at com.realty.drake.kunuk.ViewPagerActivity$SamplePagerAdapter.instantiateItem(ViewPagerActivity.java:45)
    at com.realty.drake.kunuk.ViewPagerActivity$SamplePagerAdapter.instantiateItem(ViewPagerActivity.java:34)
    at android.support.v4.view.ViewPager.addNewItem(ViewPager.java:1002)
    at android.support.v4.view.ViewPager.populate(ViewPager.java:1216)
    at android.support.v4.vie
  06-27 14:36:33.411 6520-6520/com.realty.drake.kunuk E/JavaBinder: !!!     FAILED BINDER TRANSACTION !!!  (parcel size = 1275500)
  06-27 14:36:33.412 6520-6520/com.realty.drake.kunuk E/AndroidRuntime: Error reporting crash
android.os.TransactionTooLargeException: data parcel size 1275500 bytes
    at android.os.BinderProxy.transactNative(Native Method)
    at android.os.BinderProxy.transact(Binder.java:503)
    at android.app.ActivityManagerProxy.handleApplicationCrash(ActivityManagerNative.java:4447)
    at com.android.internal.os.RuntimeInit$UncaughtHandler.uncaughtException(RuntimeInit.java:90)
    at  com.crashlytics.android.core.CrashlyticsUncaughtExceptionHandler.uncaughtExcep tion(CrashlyticsUncaughtExceptionHandler.java:51)
    at java.lang.ThreadGroup.uncaughtException(ThreadGroup.java:693)
    at java.lang.ThreadGroup.uncaughtException(ThreadGroup.java:690)

The ViewPager activity, There I take the url from an intent, parse it to turn it into an array because it is multiple string concatenated. The glide use it to display the image. The first image display and doesn't crash, but when I swipe to the second image, it took a few seconds then crash(only the activity crash not the app), but If I swipe from second to the third image it crash suddenly before even display it.

public class ViewPagerActivity extends AppCompatActivity {

String imageList = null;
String[] propertyImageArray = {};


@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_view_pager);
    //get imageList url from Intent
    imageList = getIntent().getStringExtra("imageList");
    propertyImageArray = imageList.split(",");
    ViewPager viewPager = findViewById(R.id.view_pager);
    viewPager.setAdapter(new SamplePagerAdapter());
}

class SamplePagerAdapter extends PagerAdapter {

    @Override
    public int getCount() {
        return propertyImageArray.length;
    }

    @Override
    public View instantiateItem(ViewGroup container, int position) {
        //Must call notifyDataSetChanged before adding imageList to View
        //otherwise it'll crash
        notifyDataSetChanged();
        PhotoView photoView = new PhotoView(ViewPagerActivity.this);
        GlideApp.with(ViewPagerActivity.this)
                .load(propertyImageArray[position])
                .fitCenter()
                .into(photoView);

        // Now just add PhotoView to ViewPager and return it
        container.addView(photoView,
                ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
        return photoView;


    }

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

    @Override
    public boolean isViewFromObject(View view, Object object) {
        return view == object;
    }

This is the class that send the intent to ViewPagerActivity,

public class PropertyLotDetail extends AppCompatActivity implements Toolbar.OnMenuItemClickListener {


@Override
protected void onCreate( Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.property_lot_detail);
    Toolbar myToolbar = (Toolbar) findViewById(R.id.kunuk_toolbar);
    myToolbar.inflateMenu(R.menu.menu_detail);
    setSupportActionBar(myToolbar);

    myToolbar.setOnMenuItemClickListener(this);

    //collect our intent
    Intent intent = getIntent();
    Property property = intent.getParcelableExtra("Property");

    //collect all property values from Parcelable
    int price = property.getPrice();
    String address = property.getAddress();
    final  String propertyImage = property.getPropertyImage();
    float lotDim = property.getLotDim();
    String propertyDesc = property.getPropertyDesc();
    String lotTerrainType = property.getLotTerrainType();
    String lotTerrainDimExt = property.getLotTerrainDimExt();
    String lotTerrainSteepness = property.getLotTerrainSteepness();
[...]
 //Bind the data from the Parcelable to the Views
    TextView addressDetail = findViewById(R.id.post_address);
    addressDetail.setText(String.valueOf(address));

    String currencyPrice = NumberFormat //Format the price variable in currency form
            .getCurrencyInstance(Locale.US)
            .format(price);
    TextView priceDetail = findViewById(R.id.post_price);
    priceDetail.setText(currencyPrice);

    ImageView imageView = findViewById(R.id.post_propertyImage);
    imageView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            startActivity(new Intent(getApplicationContext(),
                    ViewPagerActivity.class)
                    .putExtra("imageList", propertyImage)
                    .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));

        }
    });

    //take one long string containing multiple url and parse it
    String propertyImageArray[] = propertyImage.split(",");

    //TODO add loading icon for placeholder

    // Download directly from StorageReference using Glide
    // (See MyAppGlideModule for Loader registration)
    GlideApp.with(getApplication())
            .load(propertyImageArray[0])
            .fitCenter()
            .into(imageView);

That's the most relevant information. Please help


Solution

  • I just got rid of the notifyDataChanged() method call. I presume it has been automatically called, I didn't need to do it, and that's why the stack trace leads to an endless recursion. It's just what I think.

    public class ViewPagerActivity extends AppCompatActivity {
    
    String imageList = null;
    String[] propertyImageArray = {};
    
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_view_pager);
    //get imageList url from Intent
    imageList = getIntent().getStringExtra("imageList");
    propertyImageArray = imageList.split(",");
    ViewPager viewPager = findViewById(R.id.view_pager);
    viewPager.setAdapter(new SamplePagerAdapter());
    }
    
    class SamplePagerAdapter extends PagerAdapter {
    
    @Override
    public int getCount() {
        return propertyImageArray.length;
    }
    
    @Override
    public View instantiateItem(ViewGroup container, int position) {
        //Must call notifyDataSetChanged before adding imageList to View
        //otherwise it'll crash
    

    notifyDataSetChanged();

        PhotoView photoView = new PhotoView(ViewPagerActivity.this);
        GlideApp.with(ViewPagerActivity.this)
                .load(propertyImageArray[position])
                .fitCenter()
                .into(photoView);
    
        // Now just add PhotoView to ViewPager and return it
        container.addView(photoView,
                ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
        return photoView;
    
    
    }
    
    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        container.removeView((View) object);
    }
    
    @Override
    public boolean isViewFromObject(View view, Object object) {
        return view == object;
    }
    

    Sorry for the bad formatting, don't know how to make striketrough in code