Android copies the latest 6.2 album and android copies the 6.2 album
I chose an image like a photo album and checked the big image. I did not write well. I hope my comments will not be enough. Sorry, I 'd like to introduce my basic ideas first.
Step 1Retrieve all image paths on your mobile phone:
Uri uri = MediaStore. images. media. EXTERNAL_CONTENT_URI; ContentResolver contentResolver = getContentResolver (); // obtain jpeg and png files, and perform reverse Cursor cursor = contentResolver by time. query (uri, null, MediaStore. images. media. MIME_TYPE + "= \" image/jpeg \ "or" + MediaStore. images. media. MIME_TYPE + "= \" image/png \ "", null, MediaStore. images. media. DATE_MODIFIED + "desc"); if (cursor! = Null) {while (cursor. moveToNext () {// do something} handler. sendEmptyMessage (0 );}
My storage format
/** List of all images sorted by time */private ArrayList <SingleImageModel> allImages;/** list of all images sorted by directory */private ArrayList <SingleImageDirectories> imageDirectories; /*** image data entity in a folder */private class SingleImageDirectories {/** parent directory path */public String directoryPath; /** all image objects in the directory */public ImageDirectoryModel images ;}
One is the storage order of all images, and the other is the storage order of images in the directory.
Step 2After obtaining the image, put it in the gridview for display, but BitmapFactory. the decodeFile () function is time-consuming. Therefore, to display images smoothly, create a class AlbumBitmapCacheHelper. class, used to asynchronously load images,
This class uses LruCache <String, Bitmap> cache to cache Bitmap, so that storing images does not cause oom. Here I set the initial cache size to 1/4 runtime memory.
Then, the ThreadPoolExecutor thread pool is used to process image display. The thread pool size should be set to moderate.
After completing these two tasks, you can load the image. The getBitmap method is used to return the image.
Bitmap bitmap = getBitmapFromCache (path, width, height); // if you can obtain images that meet the requirements from the cache, you can directly call back if (bitmap! = Null) {} else {// Add the new thread to the thread pool to process the display of the image} return bitmap;
If the image cannot be found in the cache, call BitmapFactory. decodeFile () to load the image. If the image cannot be loaded directly, OOM will occur. Therefore, the compression ratio must be calculated.
BitmapFactory. options options = new BitmapFactory. options (); options. inJustDecodeBounds = true; BitmapFactory. decodeFile (path, options); options. inSampleSize = computeScale (options, width, height); options. inJustDecodeBounds = false; bitmap = BitmapFactory. decodeFile (path, options); // After obtaining it, put it into the cache so that you can continue to use if (bitmap! = Null & cache! = Null) {cache. put (path, bitmap );}
The computeScale () method is mainly used to calculate the minimum image compression ratio,
In this way, you can call the getBitmap () method of AlbumBitmapCacheHelper. class in the getview method of the gridview, but there will be many problems:
One problem is that the image display will flash. This is mainly because the reuse of the getview view causes an imageview to be set multiple times. The solution is to use the settag method holder. iv_content.setTag (path); set the tag of the imageview to be displayed as the path of the image to be displayed. In this way, use the gridView method during callback. findViewWithTag (path), find this imageview for display, and the flash problem is solved.
The second problem is that the loading speed is very slow. When the pulling speed is very fast, it takes a long time for images to be loaded, especially large images, such as photos and photos,
Solution: the first solution is to maintain an ArrayList <String> currentShowString in the AlbumBitmapCacheHelper class. In the getview method, if the image is to be displayed, add the path to the list directly, if the tag of the view is not empty, the original path of the view does not need to be displayed. Therefore, you need to delete the path from the list:
// Optimize the display effect if (holder. iv_content.getTag ()! = Null) {String remove = (String) holder. iv_content.getTag (); AlbumBitmapCacheHelper. getInstance (). Equals (remove);} AlbumBitmapCacheHelper. getInstance (). addPathToShowlist (path );
In this way, the processing method in the thread pool is to first check whether the path to be displayed is in the list. If the path is not in the list, the thread closes directly. If the path is in the list, the image is displayed.
if (!currentShowString.contains(path)||cache==null) { return;}
The second solution is that if a large image is displayed, especially a photo or image, decode sometimes takes a few seconds and the display effect is very good. The solution I have come up with is
* ** Step 1: obtain from the temp directory of the application cache. If not, *** Step 2: Calculate the image compression ratio samplesize. If samplesize is less than 4, bitmapFactory of the image. decodeFile () takes a short time and returns an image directly. However, if samplesize is greater than 4, perform step 3 *** and save the compressed image to the temp directory, so that the next time you can quickly retrieve the displayed image, the display speed will not only be as slow as loading the first large image, but the subsequent display will be very fast,
If (! New File (CommonUtil. getDataPath ()). exists () new File (CommonUtil. getDataPath ()). mkdirs (); // temporary file name String tempPath = CommonUtil. getDataPath () + hash + ". temp "; // if the File exists if (new File (tempPath ). exists () bitmap = BitmapFactory. decodeFile (tempPath );...... // Step 3: if the scaling ratio is greater than 4, the graph loading will be very slow. Therefore, save the graph to a temporary directory so that the next time you can quickly load if (options. inSampleSize> = 4) {try {File file = new File (tempPath); if (! File. exists () file. createNewFile (); FileOutputStream fos = new FileOutputStream (file); ByteArrayOutputStream baos = new ByteArrayOutputStream (); bitmap. compress (Bitmap. compressFormat. PNG, 100, baos); fos. write (baos. toByteArray (); fos. flush (); fos. close ();} catch (FileNotFoundException e) {e. printStackTrace ();} catch (IOException e) {e. printStackTrace ();}}
The problem is almost solved.
Step 3To view a larger image, as long as the larger image is a combination of ZoomImageView and viewpagger found on the Internet, it is very easy to use OOM, no way, my processing method is to click into the big picture.
public void releaseHalfSizeCache() { cache.resize((int) (Runtime.getRuntime().maxMemory() / 1024 / 8));}
Directly change the cache size to half of the original size, because the memory occupied by loading a large image is very large, so the display effect page can be merged, there are other methods, leave a message to tell me
Note: To view a large image, you need to transmit data through intent, but the size of the data transmitted by intent cannot be too large. If there are thousands of images on your mobile phone, the data size may exceed the maximum amount that intent can transmit. Therefore, you can write data to a public location, memory, database, or file,
// TODO: the data transmitted by intent cannot be too large. Therefore, if necessary, you need to perform additional processing to write data to the memory or to the intent file. putExtra (PickBigImagesActivity. EXTRA_DATA, getAllImagesFromCurrentDirectory ());
I have not processed it yet ~~
Step 4After the image selection is complete, complete the aftercare and clear the cache in the AlbumBitmapCacheHelper class. This is almost the case. There are still many small problems, such as the display of the slice time. For details, refer to the source code.
Download the latest source code
Github address. If there is a bug, I will update it on github at any time.
Because the source code is an android studio project, you cannot directly import eclipse. You must manually copy the file and release all the files here to facilitate eclipse