In the previousArticleOn Windows Phone, in Windows Phone, You can edit images, process images in Windows Phone, display GIF images in Windows Phone, save images, and load images, it can be seen that image processing accounts for a large proportion in Windows Phone development. Today I will introduce a simple image cache mechanism.
David Anson published a lowprofileimageloader to download images without affecting the UI thread (mango has removed image processing from the UI thread, so there is no such impact, you can also refer to this Article ).
The lowprofileimageloader idea is to put all the image Uris into a queue, and then traverse the queue in sequence to request image resources. After downloading the queue, it notifies the UI to return the stream, every time a new UI is inserted, it will wake up the working thread, and we can set the working thread to process several Uris at a time. The default value is 5.
After understanding the lowprofileimageloader idea, we can customize a simple image cache based on lowprofileimageloader. That is, if we have downloaded this image, we will save the image to the local device and wait until the next startup.ProgramCheck whether the image has been cached locally. If the image has been cached, read the image from the local device and return it. If the image has not been cached, notify the UI after the download, save the image to your local device.
Add a judgment before the request network in workerthreadproc, the main method of thread work, to determine whether the image is cached
If (Pendingrequest. Uri. isabsoluteuri ){ // Load from isolated storage if has been cached If (Isimagecached (pendingrequest. Uri )){ If ( Null ! = Loadcachedimage (pendingrequest. Uri) {pendingcompletions. enqueue ( New Pendingcompletion (Pendingrequest. Image, pendingrequest. Uri, loadcachedimage (pendingrequest. Uri )));}} Else { // Download from Network VaR Webrequest = Httpwebrequest . Createhttp (pendingrequest. Uri); webrequest. allowreadstreambuffering =True ; // Don't want to block this thread or the UI thread on Network Access Webrequest. begingetresponse (handlegetresponseresult, New Responsestate (Webrequest, pendingrequest. Image, pendingrequest. Uri ));}}
If the cache is already cached, push it directly into the Completion queue, that is, prepare to callback to the UI.
Add processing in the callback. If no cache is available, cache the image.
// Decode the image and set the source VaR Pendingcompletion = pendingcompletions. dequeue (); If (Geturisource (pendingcompletion. Image) = pendingcompletion. Uri ){ // If has been cached, do not cache If (! Isimagecached (pendingcompletion. Uri) {cacheimage (pendingcompletion. Stream, pendingcompletion. Uri );} Try { Imagesource Bitmap; VaR Bitmapimage = New Bitmapimage (); Bitmapimage. setsource (pendingcompletion. Stream); bitmap = bitmapimage; pendingcompletion. image. Source = bitmap ;} Catch ( Exception Ex ){ // Ignore Image Decode exceptions (ex: Invalid image) }}
The following method is used to determine whether the image is cached.
Private Static boolIsimagecached (UriU ){StringFilepath =Path. Combine (Constants. Cache_dir_images, getparsepath (U. tostring ()));Using(VaRStore =Isolatedstoragefile. Getuserstoreforapplication ()){If(Store. fileexists (filepath )){Return true;}}Return false;}
This involves parsing the image Uri, because the URI of the image is generally http ://.... JPG and so on. In order to avoid unnecessary troubles, You Need To transcode the URI:
Private Static stringGetparsepath (StringURL ){ReturnURL. Replace ("://",""). Replace ("/","_");}
The following method reads the image stream from the cache:
Private StaticStreamLoadcachedimage (UriU ){StringFilepath =Path. Combine (Constants. Cache_dir_images, getparsepath (U. tostring ()));Using(VaRStore =Isolatedstoragefile. Getuserstoreforapplication ()){If(! Store. fileexists (filepath )){Return null;}ReturnStore. openfile (filepath,Filemode. Open,Fileaccess. Read );}}
And how to cache images:
Private Static bool Cacheimage ( Stream Source, Uri U ){ String Filepath = Path . Combine ( Constants . Cache_dir_images, getparsepath (U. tostring ())); Using ( VaR Store = Isolatedstoragefile . Getuserstoreforapplication ()){ Try { If (! Store. directoryexists ( Constants . Cache_dir_images) {store. createdirectory ( Constants . Cache_dir_images );} Using ( VaR Stream = store. openfile (filepath, Filemode . Openorcreate, Fileaccess . Write )){ Byte [] Bytes = New byte [Source. Length]; source. Read (bytes, 0 ,( Int ) Source. Length); stream. Write (bytes, 0 ,( Int ) Source. Length );}Return true ;} Catch ( Exception ){ Return false ; Throw ;}}}
The calling method is as follows:
<ImageDelay:Lowprofileimageloader. urisource= "{BindingLogo}"Grid. Column= "0"Height= "100"Width= "100"/>
Add the precedingCodeAs soon as the image is downloaded, it will be cached locally for the next use.
Of course, you can add a dependency attribute to determine whether the cache is enabled currently. Another thing to consider is when to delete the image cache, which is determined by your app!
The modified lowprofileimageloader can be found here. Hope that helps.