Search code examples
androidlistviewandroid-fragmentslistadapter

Android : FragmentList items repeating themselves


I have created a ViewPager in my MainActivity that contains 5 tabs. In the first tab I have put a ListView in order to display some items. The problem is that whenever I swipe to a different tab and then return to the first, the items in the list are duplicated (i.e list contains A-B-C and then A-B-C-A-B-C). The odd thing is that this occurs only when I swipe further than the second tab. Here is my code :

MainActivity :

public class MainActivity extends FragmentActivity implements ActionBar.TabListener {
    private ViewPager viewPager;
    private TabsPagerAdapter mAdapter;
    private ActionBar actionBar;

    //private String[] tabs = { "Mixed", "Videos", "Audio", "Text", "Picture" };
    final int[] ICONS = new int[] {
            R.drawable.mixed,
            R.drawable.video,
            R.drawable.audio,
            R.drawable.note,
            R.drawable.photo
    };

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


        viewPager = (ViewPager) findViewById(R.id.pager);
        actionBar = getActionBar();
        mAdapter = new TabsPagerAdapter(getSupportFragmentManager());

        viewPager.setAdapter(mAdapter);
        actionBar.setHomeButtonEnabled(false);
        actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);

        // Adding Tabs
        for (int i=0;i<ICONS.length;i++) {

            actionBar.addTab(actionBar.newTab().setIcon(MainActivity.this.getResources().getDrawable(ICONS[i]))
                    .setTabListener(this));
        }

        viewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {

            @Override
            public void onPageSelected(int position) {
                // on changing the page
                // make respected tab selected
                actionBar.setSelectedNavigationItem(position);
            }

            @Override
            public void onPageScrolled(int arg0, float arg1, int arg2) {
            }

            @Override
            public void onPageScrollStateChanged(int arg0) {
            }
        });

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

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }

    @Override
    public void onTabSelected(ActionBar.Tab tab, FragmentTransaction ft) {
        viewPager.setCurrentItem(tab.getPosition());
    }

    @Override
    public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction ft) {

    }

    @Override
    public void onTabReselected(ActionBar.Tab tab, FragmentTransaction ft) {

    }
    public class TabsPagerAdapter extends FragmentPagerAdapter {

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

        @Override
        public android.support.v4.app.Fragment getItem(int index) {

            switch (index) {
                case 0:
                    return MixedFragment.newInstance();
                case 1:
                    return new VideosFragment();
                case 2:
                    return new AudioFragment();
                case 3:
                    return new TextFragment();
                case 4:
                    return new PictureFragment();
            }

            return null;
        }

        @Override
        public int getCount() {
            // get item count - equal to number of tabs
            return 5;
        }

    }
}

Fragment Class :

public class MixedFragment extends ListFragment implements AdapterView.OnItemClickListener {
    ListView mixed;
    JSONArray videos =null;
    List<NameValuePair> row;
    ArrayAdapter<VideoRow> adapter;

    private List<VideoRow> listRow = new ArrayList<>();
    private List<String> pathList = new ArrayList<>();


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

        View v = inflater.inflate(R.layout.mixed, container, false);
        mixed = (ListView) v.findViewById(android.R.id.list);

        row = new ArrayList<>();

//        mixed.setOnItemClickListener(this);
        new populateLists().execute();
        return v;
    }

    public static MixedFragment newInstance(){

        MixedFragment mx = new MixedFragment();
        return mx;
    }



    public void onItemClick(AdapterView<?> l, View v, int position, long id) {
        String sendPath = pathList.get(position);
        Intent start = new Intent(getActivity(), PlayVideo.class);
        start.putExtra("Path", sendPath);
        startActivity(start);
    }

    class populateLists extends AsyncTask<String,String,String> {

        @Override
        protected void onPreExecute() {
            super.onPreExecute();

        }

        @Override
        protected String doInBackground(String... params) {


            JSONParser jParser = new JSONParser();
            JSONObject obj = jParser.makeHttpRequest(Config.URL_Populate,"GET",row);
            try {
                // Checking for SUCCESS TAG

                int success = obj.getInt("success");

                if (success == 1) {
                    // videos found
                    // Getting Array of videos
                    videos = obj.getJSONArray("video");

                    // looping through All videos
                    for (int i = 0; i < videos.length(); i++) {
                        JSONObject c = videos.getJSONObject(i);

                        // Storing each json item in variable
                        String path = Config.URL_2server+c.getString("path");
                        String thumbnail = c.getString("thumbnail");
                        String title = c.getString("title");
                        String name =c.getString("name");
                        title = "\""+title+"\"";

                        byte[] bytes = Base64.decode(thumbnail,Base64.DEFAULT);
                        Bitmap thumb = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
                        pathList.add(path);
                        listRow.add(new VideoRow(path,thumb, name, title));

                    }
                }
                adapter = new MyListAdapterFrag(getActivity(), R.layout.enlarged_list_row, listRow,1);


            } catch (JSONException e) {
                e.printStackTrace();
            }
            return null;
        }

        protected void onPostExecute(String file_url) {
            mixed.setAdapter(adapter);

        }
    }
}  

ListAdapter :

public class MyListAdapterFrag extends ArrayAdapter<VideoRow> {
    List<VideoRow> lRow;
    Bitmap myThumb;
    int activity;

    public MyListAdapterFrag(Context context, int resource, List<VideoRow> listRow, int i) {
        super(context, resource, listRow);
        lRow=listRow;
        activity=i;
    }


    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder viewHolder;

        View row = convertView;

        if (row == null) {
            LayoutInflater inflater = LayoutInflater.from(getContext());
            if (activity == 1) {
                row = inflater.inflate(R.layout.list_row, parent, false);
            } else if (activity == 2) {
                row = inflater.inflate(R.layout.enlarged_list_row, parent, false);
            }

            viewHolder = new ViewHolder();

            viewHolder.txtName = (TextView) row.findViewById(R.id.name);
            viewHolder.txtTitle = (TextView) row.findViewById(R.id.title);
            viewHolder.imageThumb = (ImageView) row.findViewById(R.id.thumbnail);

            row.setTag(viewHolder);

        } else {
            viewHolder = (ViewHolder) row.getTag();

        }
        VideoRow thisRow = lRow.get(position);

        viewHolder.txtName.setText(thisRow.getName());

        Bitmap thumb = thisRow.getThumb();
        if (activity == 1) {
            myThumb = Bitmap.createScaledBitmap(thumb, 40, 40, true);
        } else if (activity == 2) {
            myThumb = Bitmap.createScaledBitmap(thumb, 60, 60, true);
        }
        viewHolder.imageThumb.setImageBitmap(myThumb);

        viewHolder.txtTitle.setText(thisRow.getTitle());

        return row;
    }


    private static class ViewHolder {
        ImageView imageThumb;
        TextView txtTitle;
        TextView txtName;
    }
}

So, do you guys have any idea what causes this bug ?


Solution

  • The problem is caused by the fact that your fragment gets reinitialized when the ViewPager goes past a certain point.

    This is called the off screen page limit.

    This means, that once your first Fragment is past the limit, when you return to it, the onCreateView function will be called again. You need to check whether the populateLists AsyncTask really needs to fire or not.

    Alternatively, you can increase your off screen page limit, to retain all your Fragments.