The journey of life, the future is very far, also very dark. However, do not be afraid, not afraid of the people before the road. --Lu Xun
Since the last blog post, has been a long time not updated blog, has been busy to pay the things, here to apologize to everyone.
Put a picture first:
Do not be surprised, this is the first time to get pictures from the network speed, feel more than the speed of local reading of the picture is faster. Load 100 pictures really just 2 seconds, you do not believe, do not trust you to see.
I. Overview
In many app
, the cache can be used as a measure of the quality of a product, both to save traffic, reduce power consumption, the most important is the user experience good. Would you like to use a product 100M
that consumes more of your traffic per month? Of course there is nothing but games. So how do you cache it? Here to introduce two important concepts, one is the memory cache LruCache
, one is the hard disk cache DiskLruCache
, we are certainly not unfamiliar with these two concepts, if you do not understand the words please link Guo Shen android Disklrucache full Parse, The best solution for hard disk caching It's really good to write. It can be seen from the title that today there is a thread pool that is the concept I have heard a long time ago, but not specifically to study, I will only use it.
Related articles Please link the address:
Retrofit2 and Rxjava usage analysis
Understanding and using the thread pool in Android
Android Disklrucache full parsing, hard disk caching best practices
Second, executors probe into thread pool
Android commonly used thread pool has the following several, in the Executors
corresponding method:
- Newfixedthreadpool each time a thread pool is executed with a limited number of tasks
- Newcachedthreadpool thread pool where all tasks are started at once
- Newsinglethreadexecutor thread pool that executes only one task at a time
- Newscheduledthreadpool creates a thread pool that can perform tasks at a specified time, and can be executed repeatedly
To get an instance:
Executors.newSingleThreadExecutor();// 每次只执行一个线程任务的线程池Executors.newFixedThreadPool(3);// 限制线程池大小为3的线程池// 一个没有限制最大线程数的线程池Executors.newScheduledThreadPool(3);// 一个可以按指定时间可周期性的执行的线程池
Let's take a look at the following example:
new Thread(new Runnable() { @Override publicvoidrun() { } }).start();
Functionally equivalent to:
mMyHandler.post(new Runnable() { @Override publicvoidrun() { } });
Also equivalent to:
executors.execute(new Runnable() { @Override publicvoidrun() { } });
Why should we use ExecutorService
it instead of using Thread
and Handler
? Using thread pooling I think it's important to follow up on threads that we've turned on, to be able to reuse this, to reduce memory consumption, and of course to specify the number of thread pools that perform tasks, and create a pool of threads that can perform tasks at a specified time.
Thread pool Usage
Three, Disklrucache simple introduction
If you would like more information, please link to the relevant article.
Note: Depending on the package in your project retrofit
, the DiskLruCache
class is included, so you can avoid repeating the guide.
First look at DiskLruCache
The example method:
publicstaticopenintintlong maxSize)
open()
The method receives four parameters, the first parameter specifies the cached address of the data, the second parameter specifies the version number of the current application, the third parameter specifies how many cache files the same key can correspond to, the basic is 1, and the fourth parameter specifies the maximum number of bytes of data that can be cached, so I will not repeat the explanation here. Please see the related articles link.
Let's take a look at the beginning of the article how to quickly load out the image of the program is how to achieve. I try to make the picture load so fast, still quite excited.
1. XML layout
<ListView android:id="@+id/lv" android:layout_width="match_parent" android:layout_height="match_parent"> </ListView>
Just one ListView
, there's nothing to say.
2. Activity file
lv= (ListView) findViewById(R.id.lv); mAdapter=new TestAdapter(Images.imageThumbUrls,R.layout.photo_layout,this,lv); lv.setAdapter(mAdapter);
is a more general wording, here Adapter
the main argument:
publicTestAdapterint layoutId, Context context, ViewGroup view)
The first parameter represents an array of picture addresses
The second parameter represents a sub-layout Id
The third parameter represents a context context
The fourth parameter represents the current one ListView
, and the request network is asynchronously loaded to prevent picture dislocation
3. Adapter File
Member variables:
/** * A core class of image caching technology that caches all downloaded images and removes the least recently used images when the program memory reaches the set value. */ PrivateLrucache<string, bitmap> Mmemorycache;/** * Picture hard disk Cache core class. */ PrivateDisklrucache Mdisklrucache;/** * thread pool Download Picture * * PrivateExecutorservice executors;PrivateString[] datas;//Data source Private intLayoutID;//Layout ID PrivateContext Mcontext;//Context PrivateViewGroup Mviewgroup;//corresponding to the ListView PrivateMyHandler Mmyhandler;//hanler
The corresponding initialization:
Public Testadapter(string[] Datas,intLayoutID, Context context, ViewGroup view) { This. datas = datas; This. LayoutID = LayoutID; Mcontext = context; Mviewgroup = view;//taskcollection = new hashset<bitmapworkertask> (); //Get the maximum available memory for the application intMaxMemory = (int) Runtime.getruntime (). MaxMemory ();intCacheSize = maxmemory/8;//Set the picture cache size to the 1/8 of the program's maximum available memoryMmemorycache =NewLrucache<string, bitmap> (cacheSize) {@Override protected int sizeOf(String key, Bitmap Bitmap) {returnBitmap.getbytecount (); } };Try{//Get Picture cache pathFile Cachedir = Getdiskcachedir (Context,"Bitmap");if(!cachedir.exists ()) {Cachedir.mkdirs (); }//Create Disklrucache instance, initialize cache dataMdisklrucache = disklrucache. Open (Cachedir, getappversion (context),1, -*1024x768*1024x768); }Catch(IOException e) {E.printstacktrace (); } executors = Executors.newfixedthreadpool (3); Mmyhandler =NewMyHandler ( This); }
Next look at the getView
method:
@Override publicgetView(int position, View convertView, ViewGroup parent) { String url = (String) getItem(position); View view; ifnull) { view = LayoutInflater.fromnull); else { view = convertView; } ImageView imageView = (ImageView) view.findViewById(R.id.photo); imageView.setTag(url);//防止图片错位 imageView.setImageResource(R.drawable.empty_photo); loadBitmaps(imageView, url); return view; }
loadBitmaps
Method:
public void loadbitmaps (ImageView ImageView, String imageUrl) {try {Bitmap Bitmap = Getbitmapfrommemorycache (IMAGEURL); if (Bitmap = = null ) {Startexecutor (IMAGEURL); } else {if (ImageView! = null && Bitmap! = null ) {Imageview.seti Magebitmap (bitmap); }}} catch (Exception e) {e.printstacktrace (); } }
Loads the Bitmap
object. This method LruCache
checks all the visible objects in the screen, ImageView
and Bitmap
if any ImageView
of the objects are found Bitmap
not in the cache, then it is then checked to see if it is LruCache
Bitmap
in DiskLruCache
, and if not, open the asynchronous thread to download the picture. Instead, add them to the LRUCache and show them. The DiskLruCache
file is converted into a Bitmap
time-consuming operation that prevents the UI
thread from incurring, so it takes place in the thread pool.
startExecutor
How is the method implemented:
Public void Startexecutor(FinalString imageUrl) {Executors.execute (NewRunnable () {@Override Public void Run() {FileDescriptor FileDescriptor =NULL; FileInputStream FileInputStream =NULL; Disklrucache.snapshot Snapshot =NULL;Try{//Generate image URL corresponding to key FinalString key = Hashkeyfordisk (IMAGEURL);//Find the corresponding cache for keySnapShot = Mdisklrucache.get (key);if(SnapShot = =NULL) {//If no corresponding cache is found, prepare to request data from the network and write to the cacheDisklrucache.editor Editor = Mdisklrucache.edit (key);if(Editor! =NULL) {OutputStream OutputStream = Editor.newoutputstream (0);if(Downloadurltostream (IMAGEURL, OutputStream)) {Editor.commit (); }Else{Editor.abort (); } }after the cache is written, find the cache for key againSnapShot = Mdisklrucache.get (key); }if(SnapShot! =NULL) {FileInputStream = (FileInputStream) Snapshot.getinputstream (0); FileDescriptor = Fileinputstream.getfd (); }//Parse the cached data into a bitmap objectBitmap Bitmap =NULL;if(FileDescriptor! =NULL) {bitmap = Bitmapfactory.decodefiledescriptor (FileDescriptor); }if(Bitmap! =NULL) {//Add the bitmap object to the memory cacheAddbitmaptomemorycache (ImageUrl, bitmap); } mmyhandler.post (NewRunnable () {@Override Public void Run() {ImageView ImageView = (ImageView) mviewgroup.findviewwithtag (IMAGEURL); Bitmap Bitmap = Getbitmapfrommemorycache (IMAGEURL);if(ImageView! =NULL&& Bitmap! =NULL) {Imageview.setimagebitmap (bitmap); } } }); }Catch(IOException e) {E.printstacktrace (); }finally{if(FileDescriptor = =NULL&& FileInputStream! =NULL) {Try{Fileinputstream.close (); }Catch(IOException e) { } } } } }); }
The representative is longer and needs to be resistant to look.
Get Picture stream:
/** * Establish an HTTP request and get the bitmap object. * * @param The URL address of the urlstring image * @return parsed Bitmap Object * * Private Boolean Downloadurltostream(String urlstring, OutputStream outputstream) {HttpURLConnection URLConnection =NULL; Bufferedoutputstream out =NULL; Bufferedinputstream in =NULL; InputStream InputStream =NULL;Try{in =NewBufferedinputstream (NewURL (urlstring). OpenStream ()); out =NewBufferedoutputstream (OutputStream);intb while((b = In.read ())! =-1) {Out.write (b); }return true; }Catch(FinalIOException e) {e.printstacktrace (); }finally{if(URLConnection! =NULL) {urlconnection.disconnect (); }Try{if(Out! =NULL) {out.close (); }if(In! =NULL) {in.close (); }if(InputStream! =NULL) {inputstream.close (); } }Catch(FinalIOException e) {e.printstacktrace (); } }return false; }
The fastest new URL(urlString).openStream()
way to get a picture stream has been tested. Here to get the stream can also be used retrofit
:
try { ResponseBody responseBody = client.getRectService().downBitmaps(urlPath).execute().body(); ifnull) { return responseBody.byteStream();//返回图片流 } catch (IOException e) { e.printStackTrace(); }
Because of retrofit
some internal encapsulation, it is not recommended to get the stream for a long time.
You can also get flows like this:
finalnew URL(urlString); urlConnection = (HttpURLConnection) url.openConnection(); urlConnection.getInputStream();
Iv. Conclusion
The first time is the time to start loading the first picture
The second time is when the last picture is loaded
They have a timestamp of more than 2 seconds.
Take a look at monitors:
The source waiting to upload ... github
Retrofit2+executors+disklrucache 2 seconds to load 100 pictures from the trouble of Oom