Search code examples
androidimageandroid-studiotabsbaseadapter

Android how to refresh image grid view adapter on tab change/swipe?


I am new to native android development. I have 3 tabs (Map, Camera, Pictures). Mapis displaying my current gps location with marker on map. Camera is used to take picture and Pictures have a grid view to show saved pictures taken from camera. The screen look like below

enter image description here

Now when i take picture from the camera (in second tab) and then go to the 3rd tab the picture is not there, but when i close the app and then go to the pictures tab the picture is shown. I want to refresh the image adapter when swiping to the picture tab. For this i searched many articles and found that notifyDataSetChanged() is used for this purpose, so i tried to implement it on my picture class but it doesn't refresh it.

Below is my adapter code

public class GridViewImageAdapter extends BaseAdapter {

private Activity _activity;
private ArrayList<String> _filePaths = new ArrayList<String>();
private int imageWidth;

public GridViewImageAdapter(Activity activity, ArrayList<String> filePaths,
                            int imageWidth) {
    this._activity = activity;
    this._filePaths = filePaths;
    this.imageWidth = imageWidth;
}

@Override
public int getCount() {
    return this._filePaths.size();
}

@Override
public Object getItem(int position) {
    return this._filePaths.get(position);
}

@Override
public long getItemId(int position) {
    return position;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    ImageView imageView;
    if (convertView == null) {
        imageView = new ImageView(_activity);
    } else {
        imageView = (ImageView) convertView;
    }

    // get screen dimensions
    Bitmap image = decodeFile(_filePaths.get(position), imageWidth,
            imageWidth);

    imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
    imageView.setLayoutParams(new GridView.LayoutParams(imageWidth,
            imageWidth));
    imageView.setImageBitmap(image);

    // image view click listener
    imageView.setOnClickListener(new OnImageClickListener(position));

    return imageView;
}

class OnImageClickListener implements OnClickListener {

    int _postion;

    // constructor
    public OnImageClickListener(int position) {
        this._postion = position;
    }

    @Override
    public void onClick(View v) {
        // on selecting grid view image
        // launch full screen activity
        /*Intent i = new Intent(_activity, FullScreenViewActivity.class);
        i.putExtra("position", _postion);
        _activity.startActivity(i);*/
    }

}

/*
 * Resizing image size
 */
public static Bitmap decodeFile(String filePath, int WIDTH, int HIGHT) {
    try {

        File f = new File(filePath);

        BitmapFactory.Options o = new BitmapFactory.Options();
        o.inJustDecodeBounds = true;
        BitmapFactory.decodeStream(new FileInputStream(f), null, o);

        final int REQUIRED_WIDTH = WIDTH;
        final int REQUIRED_HIGHT = HIGHT;
        int scale = 1;
        while (o.outWidth / scale / 2 >= REQUIRED_WIDTH
                && o.outHeight / scale / 2 >= REQUIRED_HIGHT)
            scale *= 2;

        BitmapFactory.Options o2 = new BitmapFactory.Options();
        o2.inSampleSize = scale;
        return BitmapFactory.decodeStream(new FileInputStream(f), null, o2);
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    }
    return null;
}}

Below is my code for picture

public class Pictures extends Fragment {

private Utils utils;
private ArrayList<String> imagePaths = new ArrayList<String>();
private GridViewImageAdapter adapter;
private GridView gridView;
private int columnWidth;


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

    gridView = (GridView) rootView.findViewById(R.id.grid_view);
    utils = new Utils(getContext());

    // Initilizing Grid View
    InitilizeGridLayout();

    // loading all image paths from SD card
    imagePaths = utils.getFilePaths();

    // Gridview adapter

    adapter = new GridViewImageAdapter(getActivity(), imagePaths, columnWidth);
    /*adapter = new GridViewImageAdapter(Pictures.this, imagePaths,
            columnWidth);*/

    // setting grid view adapter
    gridView.setAdapter(adapter);

   // called the method here
    adapter.notifyDataSetChanged();


    return rootView;
}

private void InitilizeGridLayout() {

    Resources r = getResources();
    float padding = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
            AppConstant.GRID_PADDING, r.getDisplayMetrics());

    columnWidth = (int) ((utils.getScreenWidth() - ((AppConstant.NUM_OF_COLUMNS + 1) * padding)) / AppConstant.NUM_OF_COLUMNS);

    gridView.setNumColumns(AppConstant.NUM_OF_COLUMNS);
    gridView.setColumnWidth(columnWidth);
    gridView.setStretchMode(GridView.NO_STRETCH);
    gridView.setPadding((int) padding, (int) padding, (int) padding,
            (int) padding);
    gridView.setHorizontalSpacing((int) padding);
    gridView.setVerticalSpacing((int) padding);
}}

Update 1

Below is my code for FragmentPagerAdapter which is in my MainActivity

public class SectionsPagerAdapter extends FragmentPagerAdapter {

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

    @Override
    public Fragment getItem(int position) {
        switch (position) {
            case 0:
                MyLocation loc = new MyLocation();
                return loc;
            case 1:
                Camera cam= new Camera();
                return cam;
           case 2:
                Pictures pic = new Pictures();
                return pic;

            default:
                return null;
        }

    }

    @Override
    public int getCount() {
        // Show 3 total pages.
        return 3;
    }

    @Override
    public CharSequence getPageTitle(int position) {
        switch (position) {
            case 0:
                return "MyLocation";
            case 1:
                return "Camera";
           case 2:
                return "Pictures";
        }
        return null;
    }
}

Update 2

I have followed the suggestion of Valentino S. but still unable to view the image capture from the camera in second tab.

Below is the updated code

**MainActivity.java **

public class MainActivity extends AppCompatActivity {
  ........
          public interface Updateable
          {
                public void update();
          }

 public class SectionsPagerAdapter extends FragmentPagerAdapter {

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

    @Override
    public int getItemPosition(Object object)
    {
        if(object != null && object instanceof Pictures)
        {
            Pictures p = (Pictures) object;
            p.update();
        }
        return super.getItemPosition(object);
    }

    @Override
    public Fragment getItem(int position) {
        switch (position) {
            case 0:
                MyLocation loc = new MyLocation();
                return loc;
            case 1:
                Camera cam= new Camera();
                return cam;
           case 2:
                Pictures pic = new Pictures();
                return pic;

            default:
                return null;
        }

    }

    @Override
    public int getCount() {
        // Show 3 total pages.
        return 3;
    }

    @Override
    public CharSequence getPageTitle(int position) {
        switch (position) {
            case 0:
                return "MyLocation";
            case 1:
                return "Camera";
           case 2:
                return "Pictures";
        }
        return null;
     }// end charsequence

  }// end SectionsPagerAdapter 

}// end mainactivity

Pictures.java

public class Pictures extends Fragment implements MainActivity.Updateable {
........
 @Override
public void update() {
    if(adapter !=null)
    {
        adapter.notifyDataSetChanged();

    }
    else
    {
        Log.d(getTag(),"null");
    }
  }
.......
}

So when i run the app, take the picture from the camera and then go to Pictures tab i won't see my picture. I am still facing the same issue.

Moreover i have debugged my code, it never goes to the update and getItemPostion method and that worries me the most.

I am stuck to it and really don't have a clue how to do it. Any help would be highly appreciated


Solution

  • Ok, you can try in this way:

    In your MainActivity add this interface:

    public interface Updateable {
        public void update();
    }
    

    Now, implement this interface in your fragment and write the code to notify the adapter inside the update method:

    public class Pictures extends Fragment implements MainActivity.Updateable {
        ...
        @Override
        public void update() {
            if ( adapter != null ) {
                adapter.notifyDataSetChanged();
            } else {
                Log.d(LOG_TAG, "null");
            }
        }
        ...
    }
    

    What remains to do is to call the update method from the Main Activity when the fragment loads first. You can do this just Onverriding the getItemPosition method in your SectionPagerAdapter, like this:

    @Override
    public int getItemPosition(Object object) {    
        if ( object != null && object instanceof Pictures ) {
            Pictures f = (Pictures) object;
    
            f.update();
        }
        return super.getItemPosition(object);
    }
    

    To have the work done, finally, you have to call notifyDataSetChanged() of your viewPager adapter. This will force the adapter of your viewpager to call the getItemPosition method.

    Hope this works!

    Update 1

    Another approach that I can think is to Override the getItemPosition method in this way:

    @Override
    public int getItemPosition(Object object) {    
        return POSITION_NONE;    
    }
    

    And then, when in your MainActivity you call viewPagerAdapter.notifyDataSetChanged(), the view pager will remove all views and reload them. Maybe you can try to call this when your image is saved, or in this way:

    mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
            int previousState;
            @Override
            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
    
            }
    
            @Override
            public void onPageSelected(int position) {
    
            }
    
            @Override
            public void onPageScrollStateChanged(int state) {
    
                if (previousState == ViewPager.SCROLL_STATE_SETTLING && state == ViewPager.SCROLL_STATE_IDLE) {
    
                    if ( viewPagerAdapter.getItem(viewpager.getCurrentItem()) instanceof Pictures ) {
                        Log.d(LOG_TAG, "New Position=" + viewpager.getCurrentItem());
    
                        viewPagerAdapter.notifyDataSetChanged();
                    }
    
                }
                previousState = state;
            }
        });
    

    Hope this works!