1

私は通常約 110 ページを格納する ViewPager を持っています。各ページは SQLite データベースからのデータで満たされ、多くの TextView といくつかの ImageView があります。しかし、このような大量のビューは大量のメモリを消費するため、java.lang.OutOFMemoryError: ビットマップ サイズが VM の予算を超えています. だから私はこれを2つの方法で表示しようとしました-最初は3ページだけを使用して、ユーザーがページを中央のページから右のページにスワイプしたときにリッスンしようとしました。残念ながら、ページのスワイプはスムーズではなく、バグがありました。2回目の試行では、すべてのページを空白のビューで埋め、ユーザーの位置を聞き、位置、位置-1、および位置+1にデータで満たされたビューを追加しました。ページのスワイプは十分にスムーズでしたが、ユーザーが位置 2 (最初のページは任意) から ViewPager を実行し、位置 100 までスワイプすると、依然としてjava.lang.OutOFMemoryError: bitmap size exceeded VM Budget が発生します。

@Override
protected void onCreate(Bundle savedInstanceState) 
{
for (int i=0; i < ids.length;i++)
    {
        viewsToShow[i] = inflater.inflate(R.layout.blank, null);
        if(ids[i] == getIntent().getIntExtra(DBC.IE_ID, -1))
            currentIDPosition = i;
    }
    pagerAdapter = new MainPagerAdapter();
       pager = (ViewPager) findViewById (R.id.pagerszcz);
        pager.setAdapter (pagerAdapter);

        for (int i = 0; i < viewsToShow.length; i++)
        {
            if(i == currentIDPosition-1)
            {
                 viewsToShow[i] = (View) inflater.inflate(R.layout.szczegoly_item, null);
                 pobierzIZwiazDane(ids[i], viewsToShow[i]); // pobierzIZwiazDane fills view by data from SQLite database and images
                 pagerAdapter.addView (viewsToShow[i], i);
            }
            else if (i == currentIDPosition)
            {
                viewsToShow[currentIDPosition] = (View) inflater.inflate(R.layout.szczegoly_item, null);
                 pobierzIZwiazDane(ids[currentIDPosition], viewsToShow[currentIDPosition]);
                 pagerAdapter.addView (viewsToShow[i], i);
            }
            else if (i == currentIDPosition+1)
            {
                viewsToShow[i] = (View) inflater.inflate(R.layout.szczegoly_item, null);
                 pobierzIZwiazDane(ids[i], viewsToShow[i]);
                 pagerAdapter.addView (viewsToShow[i], i);
            }
            else
                pagerAdapter.addView (viewsToShow[i], i);

        }

        pagerAdapter.notifyDataSetChanged();

        pager.setCurrentItem(currentIDPosition);

         pager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {

            /* int oldPage=1;
             int newPage;*/

               public void onPageSelected(int position) {
                mSelectedPageIndex = position;
                //Log.d("mselect",position+" "+ pager.getCurrentItem());
               }

               public void onPageScrolled(int arg0, float arg1, int arg2) {
                   // Swipe to right page
                   if (pager.getCurrentItem()<currentIDPosition && pager.getCurrentItem() > 0)
                    {
                        Log.d("Zmniejszenie", pager.getCurrentItem()+" "+currentIDPosition);
                    currentIDPosition--;
                    pagerAdapter.removeView(pager, currentIDPosition-1);
                    viewsToShow[currentIDPosition-1] = (View) inflater.inflate(R.layout.szczegoly_item, null);
                     pobierzIZwiazDane(ids[currentIDPosition-1], viewsToShow[currentIDPosition-1]);
                                pagerAdapter.addView (viewsToShow[currentIDPosition-1], currentIDPosition-1);
                                new Handler().post(new Runnable() {
                                    public void run() { // Removing view at current postion +2 
                                        viewsToShow[currentIDPosition+2] = null;
                                         viewsToShow[currentIDPosition+2] = new View(SzczegolyViewPagerActivity.this);
                                         pagerAdapter.removeView(pager, currentIDPosition+2);
                                         pagerAdapter.addView (viewsToShow[currentIDPosition+2], currentIDPosition+2);
                                        }
                                    });

                                 pagerAdapter.notifyDataSetChanged();

                    }
                    else if (pager.getCurrentItem()>currentIDPosition && pager.getCurrentItem() < ids.length-1)
                    {// Swipe to left page
                        Log.d("Zwiekszenie", pager.getCurrentItem()+" "+currentIDPosition);
                        currentIDPosition++;
                    pagerAdapter.removeView(pager, currentIDPosition+1);
                     viewsToShow[currentIDPosition+1] = (View) inflater.inflate(R.layout.szczegoly_item, null);
                     pobierzIZwiazDane(ids[currentIDPosition+1], viewsToShow[currentIDPosition+1]);
                                pagerAdapter.addView (viewsToShow[currentIDPosition+1], currentIDPosition+1);
                                new Handler().post(new Runnable() {
                                    public void run() {
                                         viewsToShow[currentIDPosition-2] = new View(SzczegolyViewPagerActivity.this);
                                         pagerAdapter.removeView(pager, currentIDPosition-2);
                                         pagerAdapter.addView (viewsToShow[currentIDPosition-2], currentIDPosition-2);
                                        }
                                    });

                                 pagerAdapter.notifyDataSetChanged();
                    }
               }

               public void onPageScrollStateChanged(int state) {
                if (state == ViewPager.SCROLL_STATE_IDLE) {
                    Log.d("pagec", currentIDPosition+" "+pager.getCurrentItem() + " " +pagerAdapter.getCount() + " " + mSelectedPageIndex);

                }
               }
              });

}


class MainPagerAdapter extends PagerAdapter
{
  // This holds all the currently displayable views, in order from left to right.
  private ArrayList<View> views = new ArrayList<View>();
    private LayoutInflater inflater;

  public MainPagerAdapter() 
  {

        inflater = getLayoutInflater();
}

  //-----------------------------------------------------------------------------
  // Used by ViewPager.  "Object" represents the page; tell the ViewPager where the
  // page should be displayed, from left-to-right.  If the page no longer exists,
  // return POSITION_NONE.
  @Override
  public int getItemPosition (Object object)
  {
    int index = views.indexOf (object);
    if (index == -1)
      return POSITION_NONE;
    else
      return index;
  }

  //-----------------------------------------------------------------------------
  // Used by ViewPager.  Called when ViewPager needs a page to display; it is our job
  // to add the page to the container, which is normally the ViewPager itself.  Since
  // all our pages are persistent, we simply retrieve it from our "views" ArrayList.
  @Override
  public Object instantiateItem (ViewGroup container, int position)
  {
    View v = views.get (position);
    //View cont = inflater.inflate(R.layout.szczegoly_item, container, false);

    container.addView (v);
    return v;
  }

  //-----------------------------------------------------------------------------
  // Used by ViewPager.  Called when ViewPager no longer needs a page to display; it
  // is our job to remove the page from the container, which is normally the
  // ViewPager itself.  Since all our pages are persistent, we do nothing to the
  // contents of our "views" ArrayList.
  @Override
  public void destroyItem (ViewGroup container, int position, Object object)
  {
    container.removeView (views.get (position));
  }

  //-----------------------------------------------------------------------------
  // Used by ViewPager; can be used by app as well.
  // Returns the total number of pages that the ViewPage can display.  This must
  // never be 0.
  @Override
  public int getCount ()
  {
    return views.size();
  }

  //-----------------------------------------------------------------------------
  // Used by ViewPager.
  @Override
  public boolean isViewFromObject (View view, Object object)
  {
    return view == object;
  }

  //-----------------------------------------------------------------------------
  // Add "view" to right end of "views".
  // Returns the position of the new view.
  // The app should call this to add pages; not used by ViewPager.
  public int addView (View v)
  {
    return addView (v, views.size());
  }

  //-----------------------------------------------------------------------------
  // Add "view" at "position" to "views".
  // Returns position of new view.
  // The app should call this to add pages; not used by ViewPager.
  public int addView (View v, int position)
  {
    views.add (position, v);
    return position;
  }

  //-----------------------------------------------------------------------------
  // Removes "view" from "views".
  // Retuns position of removed view.
  // The app should call this to remove pages; not used by ViewPager.
  public int removeView (ViewPager pager, View v)
  {
    return removeView (pager, views.indexOf (v));
  }

  //-----------------------------------------------------------------------------
  // Removes the "view" at "position" from "views".
  // Retuns position of removed view.
  // The app should call this to remove pages; not used by ViewPager.
  public int removeView (ViewPager pager, int position)
  {
    // ViewPager doesn't have a delete method; the closest is to set the adapter
    // again.  When doing so, it deletes all its views.  Then we can delete the view
    // from from the adapter and finally set the adapter to the pager again.  Note
    // that we set the adapter to null before removing the view from "views" - that's
    // because while ViewPager deletes all its views, it will call destroyItem which
    // will in turn cause a null pointer ref.
   // pager.setAdapter (null);
    views.remove (position);
   // pager.setAdapter (this);

    return position;
  }

  //-----------------------------------------------------------------------------
  // Returns the "view" at "position".
  // The app should call this to retrieve a view; not used by ViewPager.
  public View getView (int position)
  {
    return views.get (position);
  }

  // Other relevant methods:

  // finishUpdate - called by the ViewPager - we don't care about what pages the
  // pager is displaying so we don't use this method.
}

pobierzIZwiazDane(database record id, view) は、データベースからのデータでページを埋める責任があります。

4

3 に答える 3

2

申し訳ありませんが、viewpager を使用しないことを検討してください。

Viewpager はすべてのフラグメントを一度に開始しますが、携帯電話で処理するには多すぎます。

FragmentStatePagerAdapterを使用してみてください:

http://developer.android.com/reference/android/support/v4/app/FragmentStatePagerAdapter.html

一度にいくつかのフラグメントのみをロードする必要があります。

フラグメントを手動で管理し、カスタム アニメーションを追加するだけでなく、ジェスチャー検出をアプリに追加することもできます。これは少し難しいかもしれません。

于 2013-09-29T11:39:33.977 に答える
0

事前にすべてのビューを作成しています! 100 ページを表示したい場合は、メモリ内にビューでいっぱいの 100 ページがあります。OutOfMemoryError をスローする必要があります。

解決策は次のとおりです。

  • ViewPager が要求したときにビューを作成します (instantiateItem(ViewGroup container, int position)アダプター内)。
  • それらを削除(削除)しますdestroyItem(ViewGroup container, int position, Object object)

正しく実装すると、メモリ内のビューでいっぱいになるページが 3 つを超えることはありません。

次の例ではInteger.MAX_VALUE、ページを に表示しViewPagerます。

public class MainActivity extends Activity {

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

    MyPagerAdapter adapter = new MyPagerAdapter();

    ViewPager pager = (ViewPager) findViewById(R.id.pagerszcz);
    pager.setAdapter(adapter);

    pager.setCurrentItem(Integer.MAX_VALUE/2);
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.main, menu);
    return true;
}

private static class MyPagerAdapter extends android.support.v4.view.PagerAdapter{

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

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

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        //Remove the view added in instantiateItem from the container
        container.removeView((View)object);

        //delete objects created in instantiateItem (non View classes like Bitmap) if necessary
    }

    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        TextView tv = new TextView(container.getContext());
        tv.setText("#"+position);

        //Add you View to the container
        container.addView(tv);

        return tv;
    }       
}

}

于 2013-09-29T12:09:05.000 に答える