I'm using a grid view which is inflating the custom_layout from the layout. The grid view is loading the videos from the phone and populating it in the form of thumbnails. Everything is working fine. There is a problem in scrolling of the grid view. It is scrolling slow and in phone whose API > 20 is giving the message
The app is not responding
I've followed this link but didn't found the perfect solution: Gridview is scrolling slow
I've used asynchronous task to load the videos from the gallery. I'm giving out the code for the same. Here is my fragment:
AddFragment.java:
public class AddFragment extends Fragment {
private ImageButton imageButton;
private GridView gridView;
private ProgressDialog videoProgressDialog;
ArrayList<File> list = new ArrayList<>();
ImageAdapter imageAdapter;
public AddFragment() {
// Required empty public constructor
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_add, container, false);
imageButton = (ImageButton) view.findViewById(R.id.gotoButton);
gridView = (GridView) view.findViewById(R.id.grid_view);
gridView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
Log.e("ADD_VIDEOS","FRAGMENT CREATED");
videoProgressDialog = new ProgressDialog(getContext());
videoProgressDialog.setTitle("Loading Videos");
videoProgressDialog.setMessage("please wait.....");
videoProgressDialog.setCancelable(false);
videoProgressDialog.show();
LoadVideoTask videoTask = new LoadVideoTask();
videoTask.execute(new File("/mnt"));
return view;
}
//reading the file from the storage
void videoReader(File root) {
File[] file = root.listFiles();
if (file != null) {
for (File aFile : file) {
if (!aFile.isDirectory()) {
if (aFile.getName().endsWith(".mp4")) {
Log.e("VIDEO_FILE=====", aFile.getName());
list.add(aFile);
}
} else
videoReader(aFile);
}
} else{}
}
//Show hide select button if images are selected or deselected
public void showSelectButton() {
ArrayList<String> selectedItems = imageAdapter.getCheckedItems();
Log.e("CHECKED_ITEMS",imageAdapter.getCheckedItems().toString());
if (selectedItems.size() > 0) {
imageButton.setVisibility(View.VISIBLE);
} else
imageButton.setVisibility(View.GONE);
}
class ImageAdapter extends BaseAdapter {
private Bitmap bitmap;
private LayoutInflater inflater;
SparseBooleanArray mSparseBooleanArray;
private final Context context;
private ImageAdapter(Context c) {
context = c;
//changes done from here
mSparseBooleanArray = new SparseBooleanArray();
}
//Method to return selected Images
public ArrayList<String> getCheckedItems() {
ArrayList<String> mTempArry = new ArrayList<String>();
for (int i = 0; i < list.size(); i++) {
if (mSparseBooleanArray.get(i)) {
mTempArry.add(list.get(i).toString());
}
}
return mTempArry;
}
//for the video numbers
@Override
public int getCount() {
return list.size();
}
//for getting the video items position vise
@Override
public Object getItem(int position) {
return list.get(position);
}
@Override
public long getItemId(int i) {
return i;
}
@Override
public View getView(int position, View convertView, ViewGroup viewGroup) {
View v;
if (convertView == null) {
inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = inflater.inflate(R.layout.custom_gridview,viewGroup,false);
v.setLayoutParams(new AbsListView.LayoutParams(215,215));
} else {
// picturesView = (ImageView) convertView;
v = (View)convertView;
}
Viewholder viewHolder = new Viewholder(v);
//viewHolder.imageView.setId(position);
viewHolder.id = position;
//convertView.setTag(viewHolder);
//loading images from the videos
if (list.get(position).toString().contains(".jpg")) {
bitmap = BitmapFactory.decodeFile(list.get(position).toString()); //Creation of Thumbnail of image
// viewHolder.imageView.setImageBitmap(bitmap);
} else {
if (list.get(position).toString().contains(".mp4")) {
bitmap = ThumbnailUtils.createVideoThumbnail(list.get(position).toString(), 1); //Creation of Thumbnail of video
viewHolder.imageView.setImageBitmap(bitmap);
}
}
//picturesView.setScaleType(ImageView.ScaleType.CENTER_CROP);
//picturesView.setAdjustViewBounds(true);
//picturesView.setLayoutParams(new GridView.LayoutParams(215, 215));
//picturesView.setImageBitmap(bitmap);
//setting layout params for every device
viewHolder.checkBox.setTag(position);
viewHolder.checkBox.setChecked(mSparseBooleanArray.get(position));
CompoundButton.OnCheckedChangeListener mCheckedChangeListener = new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean isChecked) {
mSparseBooleanArray.put((Integer) compoundButton.getTag(), isChecked);//Insert selected checkbox value inside boolean array
showSelectButton();
}
};
viewHolder.checkBox.setOnCheckedChangeListener(mCheckedChangeListener);
//return picturesView;
return v;
}
class Viewholder {
public ImageView imageView;
public CheckBox checkBox;
public int id;
public Viewholder(View v){
imageView = (ImageView) v.findViewById(R.id.galleryImageView);
checkBox = (CheckBox) v.findViewById(R.id.selectCheckBox);
}
}
}
//asynch task has been done to do the processing in the background for loading the videos
//three parametres are Params,Progress,Result
private class LoadVideoTask extends AsyncTask<File,Integer, Integer>{
@Override
protected Integer doInBackground(File... files) {
for(int i=0;i<files.length;i++) {
videoReader(files[i]);
Log.e("VIDEO_LOAD", files[i].toString());
}
return files.length;
}
@Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
videoProgressDialog.setProgress(values[0]);
}
@Override
protected void onPostExecute(Integer integer) {
super.onPostExecute(integer);
updateUI();
}
}
private void updateUI() {
videoProgressDialog.dismiss();
//calling imageadapter class in here
imageAdapter = new ImageAdapter(getContext());
//for not repeating of the files
LinkedHashSet<File> fileList = new LinkedHashSet<>();
fileList.addAll(list);
list.clear();
list.addAll(fileList);
gridView.setAdapter(imageAdapter);
imageButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(getContext(), EditVideoActivity.class);
intent.putExtra("sendData", imageAdapter.getCheckedItems()); //passing the data
Log.e("SEND_DATA", imageAdapter.getCheckedItems().toString());
startActivity(intent);
}
});
}}
Since there is a lot of data and I know due to heavy data it is not scrolling slow. I need a solution for this.
After following this link I got a result and made some changes in the getView() according to the solution, which still does not solve my problem.
Link: GridView Smooth Scrolling Solution
My getView() method inside my Adapter class is like this now:
@Override
public View getView(int position, View convertView, ViewGroup viewGroup) {
Viewholder viewHolder = null;
if (convertView == null) {
viewHolder = new Viewholder();
inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.custom_gridview,viewGroup,false);
convertView.setLayoutParams(new AbsListView.LayoutParams(215,215));
convertView.setTag(viewHolder);
} else {
viewHolder = (Viewholder) convertView.getTag();
}
viewHolder.imageView = (ImageView) convertView.findViewById(R.id.galleryImageView);
viewHolder.checkBox = (CheckBox) convertView.findViewById(R.id.selectCheckBox);
viewHolder.id = position;
//loading images from the videos
if (list.get(position).toString().contains(".jpg")) {
bitmap = BitmapFactory.decodeFile(list.get(position).toString()); //Creation of Thumbnail of image
// viewHolder.imageView.setImageBitmap(bitmap);
} else {
if (list.get(position).toString().contains(".mp4")) {
bitmap = ThumbnailUtils.createVideoThumbnail(list.get(position).toString(), 1); //Creation of Thumbnail of video
viewHolder.imageView.setImageBitmap(bitmap);
}
}
viewHolder.checkBox.setTag(position);
viewHolder.checkBox.setChecked(mSparseBooleanArray.get(position));
CompoundButton.OnCheckedChangeListener mCheckedChangeListener = new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean isChecked) {
mSparseBooleanArray.put((Integer) compoundButton.getTag(), isChecked);//Insert selected checkbox value inside boolean array
showSelectButton();
}
};
viewHolder.checkBox.setOnCheckedChangeListener(mCheckedChangeListener);
return convertView;
}
Bitmaps can very easily exhaust an app's memory budget.
If your app is loading multiple bitmaps into memory, you need to skillfully manage memory and disk caching. So Whenever you load images from the videos, It must be exhaust an app's memory budget.
I recommend to use Picasso library.(http://square.github.io/picasso/)
You have to change it in your source code.
Also please read it
solving-the-android-image-loading-problem-volley-vs-picasso/
Handling Bitmaps