1

I am new to Android and am trying a sample application for showing ViewPagers in a Master-Detail Flow using custom PagerAdapters and FragmentStatePagerAdapters. My application has a list of dummy items managed by a SQLiteDatabase which contain a title String, a description String, a Boolean like status, and a list of images (I plan to implement them as downloading from String urls but presently I'm just trying with a single image resource). I am having two problems in the Detail View.

My intention is to use a ViewPager with a FragmentStatePagerAdapter to show the detail view, which consists of a ViewPager with a custom PagerAdapter for showing the list of images, TextView for title and description, a ToggleButton for the like status and a delete button for deleting items from the list.

Issues:

  1. The ViewPager with the custom PagerAdapter does not display the image. It occupies the expected space and swipes performed on it also behave as expected. Only the image is not visible.
  2. [RESOLVED] On using the delete button, I am able to delete the item from the database, and also update the Master View accordingly, but I am not able to update the Detail View, and the app crashes.

Here is my code:

Code that calls ItemDetailActivity.java

@Override
public void onClick(View v) {
    Intent detailIntent = new Intent(getContext(), ItemDetailActivity.class);
    detailIntent.putExtra(ItemDetailFragment.ARG_LIST_POSITION, holder.position);
    getContext().startActivity(detailIntent);
}

ItemDetailActivity.java

public class ItemDetailActivity extends FragmentActivity {

    static ItemDetailPagerAdapter idpa;

    static ViewPager detailPager;

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

        idpa = new ItemDetailPagerAdapter(getSupportFragmentManager());

        // Show the Up button in the action bar.
        getActionBar().setDisplayHomeAsUpEnabled(true);

        detailPager = (ViewPager) findViewById(R.id.item_detail_container);
        detailPager.setAdapter(idpa);
        detailPager.setCurrentItem(getIntent().getIntExtra(ItemDetailFragment.ARG_LIST_POSITION, 0));
    }
}

activity_item_detail.xml

<android.support.v4.view.ViewPager xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/item_detail_container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.trial.piclist.ItemDetailActivity"
    tools:ignore="MergeRootFrame" />

ItemDetailFragment.java

public class ItemDetailFragment extends Fragment {
    public static final String ARG_ITEM_ID = "item_id";
    public static final String ARG_LIST_POSITION = "list_index";
    public static final String ARG_TWO_PANE = "is_two_pane";
    int position = -1;
    long id = -1;
    boolean twoPane = false;
    ViewPager pager;
    private PicItem mItem;

    public ItemDetailFragment() {
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        twoPane = getArguments().getBoolean(ARG_TWO_PANE, false);
        position = getArguments().getInt(ARG_LIST_POSITION, -1);
        id = getArguments().getLong(ARG_ITEM_ID, -1);
        if (id == -1)
            id = ItemListFragment.getIdByPosition(position);
        setmItem(id);
    }

    public void setmItem(long id) {
        if (id >= 0) {
            try {
                ItemListActivity.lds.open();
                mItem = ItemListActivity.lds.getById(id);
                ItemListActivity.lds.close();
            } catch (Exception e) {
                System.out.println(e.getMessage());
            }
            if (mItem != null) {
                List<String> pics = new ArrayList<String>();
                pics.add("1");
                pics.add("2");
                pics.add("3");
                pics.add("4");
                pics.add("5");
                mItem.setPics(pics);
            }
        }
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        View rootView = inflater.inflate(R.layout.fragment_item_detail,
                container, false);
        DetailViewHolder holder = new DetailViewHolder();

        pager = (ViewPager) rootView.findViewById(R.id.pager);
        ImagePagerAdapter adapter = new ImagePagerAdapter(mItem, getActivity(),
                inflater, position);
        pager.setAdapter(adapter);

        holder.position = getArguments().getInt(ARG_LIST_POSITION);
        holder.ttv = (TextView) rootView.findViewById(R.id.item_title);
        holder.dtv = (TextView) rootView.findViewById(R.id.item_detail);
        holder.likeButton = (ToggleButton) rootView
                .findViewById(R.id.item_like);
        holder.deleteButton = (Button) rootView.findViewById(R.id.item_delete);
        rootView.setTag(holder);

        if (mItem != null) {

            holder.ttv.setText(mItem.getTitle());
            holder.dtv.setText(mItem.getDescription());
            holder.likeButton.setChecked(mItem.getIsLiked());
            holder.likeButton.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    ItemListActivity.lds.open();
                    ItemListActivity.lds.toggleLike(mItem.getId());
                    mItem.toggleIsLiked();
                    ItemListActivity.lds.close();
                    ItemListFragment.listDisplayHelper.toggleLiked(position);
                }
            });
            holder.deleteButton.setOnClickListener(new OnClickListener() {

                @Override
                public void onClick(View v) {
                    ItemListActivity.lds.open();
                    ItemListActivity.lds.removeItem(mItem.getId());
                    ItemListActivity.lds.close();

                    ItemListFragment.listDisplayHelper.remove(position);
                    ItemListActivity.idpa.notifyDataSetChanged();
                    // What do I do so that the FragmentStatePagerAdapter is
                    // updated and the viewpager shows the next item.
                }
            });
        }

        return rootView;
    }

    static private class DetailViewHolder {
        TextView ttv;
        TextView dtv;
        ToggleButton likeButton;
        Button deleteButton;
        int position;
    }
}

fragment_item_detail.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="16dp"
    tools:context="com.trial.piclist.ItemDetailFragment" >
    <android.support.v4.view.ViewPager xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/pager"
        android:layout_width="match_parent"
        android:layout_height="200dip">
    </android.support.v4.view.ViewPager>

    <TableRow
        android:id="@+id/tableRow1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" >

        <TextView
            android:id="@+id/item_title"
            style="?android:attr/textAppearanceLarge"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/hello"
            android:textIsSelectable="true" />

        <Space
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_weight="1" />

        <include
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            layout="@layout/controls_layout" />
    </TableRow>

    <ScrollView
        android:id="@+id/descScrollView"
        android:layout_width="match_parent"
        android:layout_height="0dip"
        android:layout_weight="1" >

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical" >

            <TextView
                android:id="@+id/item_detail"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/hello" />
        </LinearLayout>
    </ScrollView>

</LinearLayout>

controls_layout.xml

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

<ToggleButton
    android:id="@+id/item_like"
    android:layout_width="30dip"
    android:layout_height="30dip"
    android:layout_gravity="right"
    android:background="@android:drawable/btn_star"
    android:gravity="center"
    android:text="@string/like_list_item"
    android:textOff="@string/empty_text"
    android:textOn="@string/empty_text" />

<Button
    android:id="@+id/item_delete"
    style="?android:attr/buttonStyleSmall"
    android:layout_width="30dip"
    android:layout_height="30dip"
    android:background="@android:drawable/ic_menu_delete"
    android:text="@string/empty_text" />

</LinearLayout>

Custom PagerAdapter ImagePagerAdapter.java

public class ImagePagerAdapter extends PagerAdapter {
    LayoutInflater inflater;
    List<View> layouts = new ArrayList<>(5);

    // Constructors.

    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        if (layouts.get(position) != null) {
            return layouts.get(position);
        }
        View layout = inflater.inflate(R.layout.detail_image, 
            ((ViewPager) container), true);
        try {
            ImageView loadSpace = (ImageView) layout
                    .findViewById(R.id.detail_image_view);
            loadSpace.setBackgroundColor(0x000000);
            loadSpace.setImageResource(R.drawable.light_grey_background);
            loadSpace.setAdjustViewBounds(true);
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
        layout.setTag(images.get(position));
        layouts.set(position, layout);
        return layout;
    }

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

    @Override
    public int getCount() {
        return 5;
    }

    @Override
    public boolean isViewFromObject(View view, Object object) {
        return (((View) object).findViewById((view.getId())) != null);
    }

}

FragmentPagerAdapter ItemDetailPagerAdapter.java

public class ItemDetailPagerAdapter extends FragmentStatePagerAdapter {

    public ItemDetailPagerAdapter(FragmentManager fm) {
        super(fm);
    }

    @Override
    public Fragment getItem(int position) {
        Fragment fragment = new ItemDetailFragment();
        Bundle args = new Bundle();
        args.putLong(ItemDetailFragment.ARG_ITEM_ID, ItemListFragment.getIdByPosition(position));
        args.putInt(ItemDetailFragment.ARG_LIST_POSITION, position);
        args.putBoolean(ItemDetailFragment.ARG_TWO_PANE, ItemListActivity.mTwoPane);
        fragment.setArguments(args);
        return fragment;
    }

    @Override
    public int getCount() {
        openDatabase();
        int c = database.getCount();
        closeDatabase();
        return c;
    }

    @Override
    public int getItemPosition(Object object) {
        long mId = ((ItemDetailFragment) object).getmId();
        int pos = POSITION_NONE;
        openDatabase();
        if (database.contains(mId)) {
            pos = database.getPositionById(mId);
        }
        closeDatabase();
        return pos;
    }
}

Any help is much appreciated. Thanks :)

CodePro_NotYet
  • 621
  • 6
  • 17
  • The delete issue has been solved. Please give a solution for the disappearance of the images from the ImagePagerAdapter – CodePro_NotYet May 29 '14 at 14:40
  • The delete issue was solved by overriding the `GetItemPosition(Object)` method of the FragmentPagerAdapter. This has been updated in the question code. The issue of the transparent image was partially solved by inflating the `ImageView` inside the `PagerAdapter` rather than outside. However, even then only one `ImageView` can be seen in one fragment, the others are still transparent. – CodePro_NotYet Jun 03 '14 at 13:46

2 Answers2

0

In your ItemDetailFragment, remove the viewpager from the holder, it should be directly into the returned view, something like this:

public View onCreateView(LayoutInflater inflater, ViewGroup container,
    Bundle savedInstanceState) {

    View rootView = inflater.inflate(R.layout.fragment_item_detail,
            container, false);

    pager = (ViewPager) rootView.findViewById(R.id.pager);
    ImagePagerAdapter adapter = new ImagePagerAdapter(mItem, getActivity(),inflater, position);
    pager.setAdapter(adapter);

    return rootView;
}

and the ViewHolder pattern should be applied inside your PagerAdapter.

ILovemyPoncho
  • 2,762
  • 2
  • 24
  • 37
  • I removed the viewpager from the holder, no changes. Although I still have to inflate R.layout.image_detail and attach it to the pager, otherwise it gives NullPointerException when I try to access the ImageView in the adapter. – CodePro_NotYet May 27 '14 at 03:53
  • You are passing an inflater to `ImagePagerAdapter`, use it to inflate `R.layout.detail_image` inside `instantiateItem()`. Take a look at this example http://stackoverflow.com/a/7278217/2017375 – ILovemyPoncho May 27 '14 at 05:34
  • I had tried that too but I was returning `container` itself instead of the inflated layout in `instantiateItem()`. Now that I corrected it, the issue is only partially resolved. Only the first image is visible in the pager, the 4 images after that are still not visible. I am correcting the code in the question. Please look at the **ImagePagerAdapter.java** file again. Thanks :) – CodePro_NotYet May 27 '14 at 06:39
  • There is a peculiarity in the issue. As I said before, the swiping works correctly as if the images are there, only invisible. However, when I swipe backwards (e.g from image 4 to image 3), the incoming image (image 3) is visible as long as it is transitioning into place. Once I lift my finger and it has stopped in the appropriate place, it vanishes. When I swipe forward, the image remains invisible all the time. – CodePro_NotYet May 27 '14 at 08:00
  • aren't you adding the view to the viewpager inside instantiateItem `((ViewPager)container).addView(layout)` ? – ILovemyPoncho May 27 '14 at 15:48
  • Specifying true in `inflater.inflate(R.layout.detail_image, ((ViewPager) container), true);` automatically adds container as the parent. Still, I also tried the `addView(layout)` approach. Same result. – CodePro_NotYet May 28 '14 at 04:45
0
  1. In ImagePagerAdapter.java, correct the isViewFromObject method -

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

    This will correct the issue of the ImageView.

  2. In ItemDetailPagerAdapter.java, override the getItemPosition method -

    @Override
    public int getItemPosition(Object object) {
        int ret = POSITION_NONE;
        long id = ((ItemDetailFragment) object).getId();
        openDatabase();
        if (databaseContains(id)) {
            ret = positionInDatabase(id);
        }
        closeDatabase();
        return ret;
    }
    

    On deleting call the FragmentStatePagerAdapter.NotifyDataSetChanged() method. This will make the Adapter update itself on deleting. Although, the FragmentStatePagerAdapter uses a list of Fragments and of stored states to implement the adapter. That is also causing trouble. To remove that, implement your own list of Fragments.

CodePro_NotYet
  • 621
  • 6
  • 17