Tag Archives: solution

Research on LRU algorithm

LRU is least recently used algorithm.

A page replacement algorithm of memory management. For data blocks (internal memory blocks) that are in memory but not in use, it is called LRU. The operating system will move them out of memory according to which data belong to LRU to make room for loading other data.
What is LRU algorithm?LRU is the abbreviation of least recently used, that is, the least page replacement algorithm, which serves for virtual page storage management.
As for the memory management of the operating system, how to save the memory with small capacity and provide resources for the most processes has always been an important research direction. The virtual storage management of memory is the most common and successful way at present. In the case of limited memory, a part of external memory is expanded as virtual memory, and the real memory only stores the information used by the current runtime. This undoubtedly greatly expands the function of memory and greatly improves the concurrency of computer. Virtual page storage management is to divide the space required by the process into multiple pages, only the current required pages are stored in memory, and the rest pages are put into external memory.

Note:
for virtual page storage, the replacement of internal and external memory information is based on pages. When a page in external memory is needed, it should be transferred into memory. At the same time, in order to maintain the size of the original space, the less internal memory is transferred, the higher the efficiency of process execution. So, which page can be transferred out to achieve the purpose of transferring as little as possible?We need an algorithm.
In fact, the algorithm to achieve such a situation is the most ideal – the page swapped out each time is the latest one to be used in all memory pages – which can delay page swapping to the maximum extent. This algorithm is called ideal page replacement algorithm. Unfortunately, this algorithm can not be realized.

In order to minimize the gap with the ideal algorithm, a variety of ingenious algorithms have been produced, at least using page replacement algorithm is one of them. The LRU algorithm is based on the fact that the pages used frequently in the previous instructions are likely to be used frequently in the following instructions. Conversely, pages that have not been used for a long time are likely not to be used for a long time in the future. This is the famous locality principle. Cache, which is faster than memory, is also based on the same principle. Therefore, we only need to find the least used page to call out the memory in each swap. This is the whole content of LRU algorithm.

FIFO, LRU and LFU algorithms

When it comes to caching, there are two points that must be considered:
(1) the consistency between cached data and target data.
(2) Cache expiration policy (mechanism).
Among them, cache expiration strategy involves elimination algorithm. Common elimination algorithms are as follows:
(1) FIFO: first in first out, first in first out
(2) LRU: least recently used
(3) LFU: least frequently used
pay attention to the difference between LRU and LFU. LFU algorithm selects the least used data item according to the number of times the data item is used in a period of time, that is, it is determined according to the difference of the number of times. LRU is determined according to the difference of usage time.
An excellent caching framework must implement all the above caching mechanisms. For example, ehcache implements all the above policies.

Double linked list + hashtable

package com.example.test;

import java.util.Hashtable;

public class LRUCache{

    private int cacheSize;
    private Hashtable<Object,Entry> nodes;
    private int currentSize;
    private Entry first; 
    private Entry last; 

    public LRUCache(int i){
        currentSize = 0;
        cacheSize = i;
        nodes = new Hashtable<Object,Entry>(i);
    }

    /**
     *Get the object in the cache and put it at the top
     */
    public Entry get(Object key){
        Entry node = nodes.get(key);
        if(node != null){
            moveToHead(node);
            return node;
        }else{
            return null;
        }
    }

    /**
     * add 
     */
    public void put(Object key,Object value){
        //First see if the hashtable has the entry, if it exists, then only update it
        Entry node = nodes.get(key);

        if(node == null){
            if(currentSize >= cacheSize){
                nodes.remove(last.key);
                removeLast();
            }else{
                currentSize++;
            }
            node = new Entry();
        }
        node.value = value;
        //Place the most recently used node at the head of the chain table to indicate the most recently used
        moveToHead(node);
        nodes.put(key, node);
    }

    public void remove(Object key){
        Entry node = nodes.get(key);
        //Delete in the chain table
        if(node != null){
            if(node.prev != null){
                node.prev.next = node.next;
            }
            if(node.next != null){
                node.next.prev = node.prev;
            }
            if(last == node)
                last = node.prev;
            if(first == node)
                first = node.next;
        }
        //Delete in hashtable中
        nodes.remove(key);
    }

    /**
     * Delete the last node of the chain, i.e., use the last entry used
     */
    private void removeLast(){
        //The end of the chain table is not empty, then the end of the chain table to point to null, delete even the end of the table (delete the least reference)
        if(last != null){
            if(last.prev != null)
                last.prev.next = null;
            else
                first = null;
            last = last.prev;
        }
    }

    /**
     *Move to the head of the chain table to indicate the latest used
     */
    private void moveToHead(Entry node){
        if(node == first)
            return;
        if(node.prev != null)
            node.prev.next = node.next;
        if(node.next != null)
            node.next.prev = node.prev;
        if(last == node)
            last =node.prev;
        if(first != null){
            node.next = first;
            first.prev = node;
        }
        first = node;
        node.prev = null;
        if(last == null){
            last = first;
        }
    }
    /*
     * clear the cache
     */
    public void clear(){
        first = null;
        last = null;
        currentSize = 0;
    }


}

    class Entry{
        Entry prev;
        Entry next;
        Object value;
        Object key;
    }

Bitmap optimization and memory optimization

Is it necessary for bitmap to call recycle method in Android system

Before Android 3.0, bitmap image data was processed in the underlying C, so before Android 3.0, recycle() should be called. Although finalize() will call recycle(), students who are experienced in Java should know that there are many problems in releasing resources only by finalize()

After Android 3.0, the image data is put in a member variable mbuffer [] of the bitmap object. Therefore, it is not necessary to call recycle (). After the bitmap is set to null, the image data will be recycled by GC.

Now that Android is in the age of 5.0, it is recommended not to consider supporting versions before 3.0.

actually Bitmap.recycle This is an advanced call, and normally need not be called, since the normal GC process will free up this memory when there are no more references to this bitmap. When no reference points to a bitmap, GC will automatically free memory.)

Managing bitmap memory Google’s official explanation of bitmap

In addition to the steps described in Caching Bitmaps, there are specific things you can do to facilitate garbage collection and bitmap reuse. The recommended strategy depends on which version(s) of Android you are targeting. The BitmapFun sample app included with this class shows you how to design your app to work efficiently across different versions of Android.

To set the stage for this lesson, here is how Android’s management of bitmap memory has evolved:

On Android Android 2.2 (API level 8) and lower, when garbage collection occurs, your app’s threads get stopped. This causes a lag that can degrade performance. Android 2.3 adds concurrent garbage collection, which means that the memory is reclaimed soon after a bitmap is no longer referenced.

On Android 2.3.3 (API level 10) and lower, the backing pixel data for a bitmap is stored in native memory. It is separate from the bitmap itself, which is stored in the Dalvik heap. The pixel data in native memory is not released in a predictable manner, potentially causing an application to briefly exceed its memory limits and crash. As of Android 3.0 (API level 11), the pixel data is stored on the Dalvik heap along with the associated bitmap.

The following sections describe how to optimize bitmap memory management for different Android versions.

Memory optimization

Memory optimization from: http://my.oschina.net/u/1753339/blog/223379

It’s easy to load a picture on the UI of your application, but when you need to load a lot of pictures on the UI, the situation becomes more complicated. In many cases (such as using listview, GridView or viewpager), the images displayed on the screen can be increased continuously by sliding the screen and other events, which eventually leads to oom.

In order to ensure that the use of memory is always maintained in a reasonable range, the removed screen images are usually recycled. At this time, the garbage collector will also think that you no longer hold the reference of these images, so it will GC these images. It’s very good to use this idea to solve the problem, but in order to make the program run quickly and load pictures on the interface quickly, you have to consider the situation that the user slides some pictures back into the screen after they are recycled. At this time, reloading the image just loaded is undoubtedly the bottleneck of performance. You need to find a way to avoid this situation.

At this time, the use of memory caching technology can solve this problem, it can let components quickly reload and process images. Now let’s take a look at how to use memory caching technology to cache images, so that your application can improve the response speed and fluency when loading many images.

Memory caching technology provides a fast way to access images that occupy a lot of valuable memory of applications. The core class is lrucache (this class is provided in the package of android-support-v4). This class is very suitable for caching images. Its main algorithm principle is to store the most recently used objects in LinkedHashMap with strong references, and remove the least recently used objects from memory before the cache value reaches the preset value.

In the past, we often used a very popular implementation of memory caching technology, namely soft reference or weak reference. However, this method is no longer recommended, because since Android 2.3 (API level 9), the garbage collector tends to recycle objects with soft references or weak references, which makes soft references and weak references unreliable. In addition, in Android 3.0 (API level 11), the image data will be stored in the local memory, so it can not be released in a predictable way, which has the potential risk of causing the memory overflow and crash of the application.

In order to select an appropriate cache size for lrucache, the following factors should be considered, for example:

How much memory can your device allocate for each application?

How many pictures can be displayed on the device screen at a time?How many images need to be preloaded because they may be displayed on the screen soon?

What is the screen size and resolution of your device?A super-high resolution device (such as Galaxy nexus) needs more cache space than a lower resolution device (such as nexus s) when holding the same number of images.

The size and size of the image, and how much memory space each image will occupy.

How often are images visited?Will some pictures be visited more frequently than others?If so, you may want to keep some images resident in memory, or use multiple lrucache objects to distinguish different groups of images.

Can you keep the balance between quantity and quality?Sometimes, it’s more effective to store multiple low pixel images, but it’s more effective to load high pixel images in the background.

There is no specified cache size for all applications, which is up to you. You should analyze the memory usage of the program, and then work out an appropriate solution. A too small cache space may cause images to be released and reloaded frequently, which is not good. However, if the cache space is too large, it may still cause problems java.lang.OutOfMemory It’s abnormal.

Here is an example of using lrucache to cache images:

private LruCache<String, Bitmap> mMemoryCache;  
@Override
protected void onCreate(Bundle savedInstanceState) { 
    // Get the maximum value of available memory, using memory beyond this value will raise an OutOfMemory exception. 
    // LruCache passes in the cache value in KB through the constructor. 
    int maxMemory = (int) (Runtime.getRuntime().maxMemory() /1024); 
    // Use 1/8 of the maximum available memory value as the size of the cache. 
    int cacheSize = maxMemory/8; 
    mMemoryCache = new LruCache<String, Bitmap>(cacheSize) { 
        @Override
        protected int sizeOf(String key, Bitmap bitmap) { 
            // Override this method to measure the size of each image and return the number of images by default. 
            return bitmap.getByteCount()/1024; 
        } 
    }; 
} 

public void addBitmapToMemoryCache(String key, Bitmap bitmap) { 
    if (getBitmapFromMemCache(key) == null) { 
        mMemoryCache.put(key, bitmap); 
    } 
} 

public Bitmap getBitmapFromMemCache(String key) { 
    return mMemoryCache.get(key); 
}

In this example, one eighth of the memory allocated by the system to the application is used as the cache size. In medium and high configuration mobile phones, there will be about 4 megabytes (32g8) of cache space. If a full screen GridView is filled with four 800×480 resolution images, it will occupy about 1.5 megabytes of space (800 * 480 * 4). Therefore, this cache size can store 2.5 pages of images.

When a picture is loaded into ImageView, it will be checked in the cache of lrucache first. If the corresponding key value is found, the ImageView will be updated immediately. Otherwise, a background thread will be started to load the image.

public void loadBitmap(int resId, ImageView imageView) { 
    final String imageKey = String.valueOf(resId); 
    final Bitmap bitmap = getBitmapFromMemCache(imageKey); 
    if (bitmap != null) { 
        imageView.setImageBitmap(bitmap); 
    } else { 
        imageView.setImageResource(R.drawable.image_placeholder); 
        BitmapWorkerTask task = new BitmapWorkerTask(imageView); 
        task.execute(resId); 
    } 
}

Bitmapworkertask also puts the key value pair of the newly loaded image into the cache.

class BitmapWorkerTask extends AsyncTask<Integer, Void, Bitmap> { 
    // loading the pictures
    @Override
    protected Bitmap doInBackground(Integer... params) { 
        final Bitmap bitmap = decodeSampledBitmapFromResource( 
                getResources(), params[0], 100, 100); 
        addBitmapToMemoryCache(String.valueOf(params[0]), bitmap); 
        return bitmap; 
    } 
}

(how to define the key of image key value pair?Path to image (URI)

What are the common memory leaks in Android

Query database without closing cursor

In Android, Cursor is a very common object, but in writing code, people often forget to call close, or because of the code logic problem situation, close is not called.

Usually, in an activity, we can call startmanagingcursor or directly use managedquery to let the activity automatically manage the cursor object.
However, it should be noted that when activity is introduced, cursor will no longer be available!
If the code of operating cursor is not synchronized with UI (such as background thread), there is no need to judge whether the activity has ended or wait for the background thread to end before calling ondestroy.
In addition, the following is also a common case that the cursor will not be closed:
although it seems that, Cursor.close () has been called, but if there is an exception, close () will be skipped, resulting in a memory leak.
Therefore, our code should be written in the following way:

Cursor c = queryCursor(); 
try { 
int a = c.getInt(1); 
...... 
} catch (Exception e) { 
} finally { 
c.close(); //Call close() in finally, ensuring that it will be called 
} 
try { 
Cursor c = queryCursor(); 
int a = c.getInt(1); 
...... 
c.close(); 
} catch (Exception e) { 
} 

Unregisterreceiver() was not called after calling registerreceiver

After calling registerreceiver, if unregisterreceiver is not called, it will occupy a large amount of memory.
We can often see the following code:
this is a very serious error, because it will cause the broadcastreceiver not to be unregistered, resulting in memory leakage.

registerReceiver(new BroadcastReceiver() { 
... 
}, filter); ... 

*InputStream/OutputStream not closed*

When using files or accessing network resources, using InputStream/OutputStream will also lead to memory leakage

Recycle () is not called after bitmap is used
according to the description of SDK, it is not necessary to call recycle. However, when we call recycle (), we no longer use memory as much as possible.

Context leak
this is a very obscure memory leak.
Let’s take a look at the following code:
in this code, we use a static drawable object.
This usually happens when we need to call a drawable frequently, and its loading is time-consuming. We don’t want to create the drawable every time we load an activity.
At this point, using static is undoubtedly the fastest way to write code, but it is also very bad.
When a drawable is attached to a view, the view will be set to the callback of the drawable Drawable.setCallback () Implementation).
This means that the drawable has a reference to textview, which in turn has a reference to activity.
As a result, the memory will not be released after the activity is destroyed.

Bitmap, cache and fresco Android image loading Library

Fresco Android image loading Library — Facebook

Fresco is a powerful image loading component.

A module called image pipeline is designed in fresco. It is responsible for loading images from network, local file system and local resources. In order to save space and CPU time to the greatest extent, it contains 3-level cache design (2-level memory, 1-level file).

There is a module called drawings in fresco, which can easily display the loading graph. When the picture is no longer displayed on the screen, it can release the memory and space in time.

Fresco supports Android 2.3 (API level 9) and above.

memory management

The extracted image, that is, the bitmap in Android, takes up a lot of memory. Large memory consumption is bound to lead to more frequent GC. Below 5.0, GC will cause interface stuck.

In systems below 5.0, fresco places the image in a special memory area. Of course, when the picture is not displayed, the occupied memory will be released automatically. This will make the app smoother and reduce the oom caused by image memory occupation.

Fresco does just as well on low-end machines, so you don’t have to think twice about how much image memory you’re using.

Progressive image presentation #
the progressive JPEG image format has been popular for several years. The progressive image format first presents the outline of the image, and then presents the gradually clear image as the image download continues, which is of great benefit to mobile devices, especially the slow network, and can bring better user experience.

Android’s own image library does not support this format, but fresco does. When using it, as usual, you just need to provide a URI of the image, and fresco will handle the rest.

It is very important to display pictures quickly and efficiently on Android devices. In the past few years, we have encountered many problems in how to efficiently store images. The picture is too big, but the memory of the phone is very small. The R, G, B and alpha channels of each pixel take up a total of 4 bytes of space. If the screen of the mobile phone is 480 * 800, a picture of the screen size will occupy 1.5m of memory. The memory of mobile phones is usually very small, especially Android devices need to allocate memory for various applications. On some devices, only 16MB of memory is allocated to the Facebook app. A picture will occupy one tenth of its memory.

What happens when your app runs out of memory?Of course it will collapse! We developed a library to solve this problem. We call it fresco. It can manage the images and memory used, and the app will no longer crash.

Memory area

In order to understand what Facebook does, we need to understand the difference between the heap memory that Android can use. The Java heap memory size of every app in Android is strictly limited. Each object is instantiated in heap memory using java new, which is a relatively safe area in memory. Memory has garbage collection mechanism, so when the app is not using memory, the system will automatically recycle this memory.

Unfortunately, the process of garbage collection in memory is the problem. When the memory is garbage collected, the memory is not only garbage collected, but also the Android application is completely terminated. This is also one of the most common reasons for users to get stuck or temporarily feign death when using the app. This will make the users who are using the app very depressed, and then they may anxiously slide the screen or click the button, but the only response of the app is to ask the user to wait patiently before the app returns to normal

In contrast, the native heap is allocated by the new of the C + + program. There is more available memory in the native heap. App is only limited by the physical available memory of the device, and there is no garbage collection mechanism or other things. But the C + + programmer must recycle every memory allocated by himself, otherwise it will cause memory leakage and eventually lead to program crash.

Android has another memory area called ashmem. It operates more like a native heap, but with additional system calls. When Android operates the ashmem heap, it will extract the memory area in the heap that contains data from the ashmem heap instead of releasing it, which is a weak memory release mode; the extracted memory will be released only when the system really needs more memory (the system memory is not enough). When Android puts the extracted memory back to the ashmem heap, as long as the extracted memory space is not released, the previous data will be restored to the corresponding location.

Three level cache
1. Bitmap cache
bitmap cache stores bitmap objects, which can be immediately used for display or post-processing

In systems below 5.0, the bitmap cache is located in ashmem, so that the creation and release of bitmap objects will not cause GC, and fewer GC will make your app run more smoothly.

In contrast, memory management has been greatly improved, so the bitmap cache is directly located on the heap of Java.

When the application is running in the background, the memory will be cleared.

    1. memory cache of undeciphered pictures
    this cache stores pictures in the original compressed format. The pictures retrieved from the cache need to be decoded before being used.

If there is any resizing, rotation, or webp transcoding work to be done, it will be done before decoding.

When the app is in the background, the cache will also be cleared.

    1. file cache
    is similar to UN decoded memory cache. File cache stores UN decoded images in original compressed format, which also needs decoding before use.

Unlike the memory cache, when the app is in the background, the content will not be cleared. Not even if it’s turned off. Users can clear the cache at any time in the system’s settings menu.

Bitmap and cache

Bitmap is special in Android, because Android limits the memory of single APP, for example, allocate 16MB, and the domestic custom system will be larger than 16. There are two common caching strategies in Android, LruCache and DiskLruCache. The former is used as memory cache method and the latter is used as storage cache method.

android.support Brief reading of lrucache source code in. V4 package

package android.util;  

import java.util.LinkedHashMap;  
import java.util.Map;  

/** 
 * A cache that holds strong references to a limited number of values. Each time 
 * a value is accessed, it is moved to the head of a queue. When a value is 
 * added to a full cache, the value at the end of that queue is evicted and may 
 * become eligible for garbage collection. 
 * Cache keeps a strong reference to limit the number of contents. Whenever an Item is accessed, this Item is moved to the head of the queue.
 * When a new item is added when the cache is full, the item at the end of the queue is reclaimed.
 * <p>If your cached values hold resources that need to be explicitly released, 
 * override {@link #entryRemoved}. 
 * If a value in your cache needs to be explicitly freed, override entryRemoved()
 * <p>If a cache miss should be computed on demand for the corresponding keys, 
 * override {@link #create}. This simplifies the calling code, allowing it to 
 * assume a value will always be returned, even when there's a cache miss. 
 * If the item corresponding to the key is lost, rewrite create(). This simplifies the calling code and always returns it even if it is lost.
 * <p>By default, the cache size is measured in the number of entries. Override 
 * {@link #sizeOf} to size the cache in different units. For example, this cache 
 * is limited to 4MiB of bitmaps: The default cache size is the number of items measured, rewrite sizeof to calculate the size of different items
 * size.
 * <pre>   {@code 
 *   int cacheSize = 4 * 1024 * 1024; // 4MiB 
 *   LruCache<String, Bitmap> bitmapCache = new LruCache<String, Bitmap>(cacheSize) { 
 *       protected int sizeOf(String key, Bitmap value) { 
 *           return value.getByteCount(); 
 *       } 
 *   }}</pre> 
 * 
 * <p>This class is thread-safe. Perform multiple cache operations atomically by 
 * synchronizing on the cache: <pre>   {@code 
 *   synchronized (cache) { 
 *     if (cache.get(key) == null) { 
 *         cache.put(key, value); 
 *     } 
 *   }}</pre> 
 * 
 * <p>This class does not allow null to be used as a key or value. A return 
 * value of null from {@link #get}, {@link #put} or {@link #remove} is 
 * unambiguous: the key was not in the cache.
 * Do not allow key or value to be null
 * When get(), put(), remove() return null, the corresponding item of the key is not in the cache
 */  
public class LruCache<K, V> {  
    private final LinkedHashMap<K, V> map;  

    /** Size of this cache in units. Not necessarily the number of elements. */  
    private int size; //The size of the already stored
    private int maxSize; //the maximum storage space specified

    private int putCount; //the number of times to put
    private int createCount; //the number of times to create
    private int evictionCount; //the number of times to recycle
    private int hitCount; //number of hits
    private int missCount; //number of misses

    /** 
     * @param maxSize for caches that do not override {@link #sizeOf}, this is 
     *     the maximum number of entries in the cache. For all other caches, 
     *     this is the maximum sum of the sizes of the entries in this cache. 
     */  
    public LruCache(int maxSize) {  
        if (maxSize <= 0) {  
            throw new IllegalArgumentException("maxSize <= 0");  
        }  
        this.maxSize = maxSize;  
        this.map = new LinkedHashMap<K, V>(0, 0.75f, true);  
    }  

    /** 
     * Returns the value for {@code key} if it exists in the cache or can be 
     * created by {@code #create}. If a value was returned, it is moved to the 
     * head of the queue. This returns null if a value is not cached and cannot 
     * be created. The corresponding item is returned by key, or created. the corresponding item is moved to the head of the queue.
     * If the value of the item is not cached or cannot be created, null is returned.
     */  
    public final V get(K key) {  
        if (key == null) {  
            throw new NullPointerException("key == null");  
        }  

        V mapValue;  
        synchronized (this) {  
            mapValue = map.get(key);  
            if (mapValue != null) {  
                hitCount++;  
                return mapValue;  
            }  
            missCount++;  
        }  

        /* 
         * Attempt to create a value. This may take a long time, and the map 
         * may be different when create() returns. If a conflicting value was 
         * added to the map while create() was working, we leave that value in 
         * the map and release the created value. 
         * If it's missing, try to create an item
         */  

        V createdValue = create(key);  
        if (createdValue == null) {  
            return null;  
        }  

        synchronized (this) {  
            createCount++;
            mapValue = map.put(key, createdValue);  

            if (mapValue != null) {  
                // There was a conflict so undo that last put  
                //If oldValue exists before it, then undo put() 
                map.put(key, mapValue);  
            } else {  
                size += safeSizeOf(key, createdValue);  
            }  
        }  

        if (mapValue != null) {  
            entryRemoved(false, key, createdValue, mapValue);  
            return mapValue;  
        } else {  
            trimToSize(maxSize);  
            return createdValue;  
        }  
    }  

    /** 
     * Caches {@code value} for {@code key}. The value is moved to the head of 
     * the queue. 
     * 
     * @return the previous value mapped by {@code key}. 
     */  
    public final V put(K key, V value) {  
        if (key == null || value == null) {  
            throw new NullPointerException("key == null || value == null");  
        }  

        V previous;  
        synchronized (this) {  
            putCount++;  
            size += safeSizeOf(key, value);  
            previous = map.put(key, value);  
            if (previous != null) {  //The previous value returned
                size -= safeSizeOf(key, previous);  
            }  
        }  

        if (previous != null) {  
            entryRemoved(false, key, previous, value);  
        }  

        trimToSize(maxSize);  
        return previous;  
    }  

    /** 
     * @param maxSize the maximum size of the cache before returning. May be -1 
     *     to evict even 0-sized elements. 
     *  Empty cache space
     */  
    private void trimToSize(int maxSize) {  
        while (true) {  
            K key;  
            V value;  
            synchronized (this) {  
                if (size < 0 || (map.isEmpty() && size != 0)) {  
                    throw new IllegalStateException(getClass().getName()  
                            + ".sizeOf() is reporting inconsistent results!");  
                }  

                if (size <= maxSize) {  
                    break;  
                }  

                Map.Entry<K, V> toEvict = map.eldest();  
                if (toEvict == null) {  
                    break;  
                }  

                key = toEvict.getKey();  
                value = toEvict.getValue();  
                map.remove(key);  
                size -= safeSizeOf(key, value);  
                evictionCount++;  
            }  

            entryRemoved(true, key, value, null);  
        }  
    }  

    /** 
     * Removes the entry for {@code key} if it exists. 
     * Delete the corresponding cache item of the key and return the corresponding value
     * @return the previous value mapped by {@code key}. 
     */  
    public final V remove(K key) {  
        if (key == null) {  
            throw new NullPointerException("key == null");  
        }  

        V previous;  
        synchronized (this) {  
            previous = map.remove(key);  
            if (previous != null) {  
                size -= safeSizeOf(key, previous);  
            }  
        }  

        if (previous != null) {  
            entryRemoved(false, key, previous, null);  
        }  

        return previous;  
    }  

    /** 
     * Called for entries that have been evicted or removed. This method is 
     * invoked when a value is evicted to make space, removed by a call to 
     * {@link #remove}, or replaced by a call to {@link #put}. The default 
     * implementation does nothing. 
     * Called when the item is recycled or deleted. Change method is called by remove when value is reclaimed to free up storage space.
     * or put called when the value of the item is replaced, the default implementation does nothing.
     * <p>The method is called without synchronization: other threads may 
     * access the cache while this method is executing. 
     * 
     * @param evicted true if the entry is being removed to make space, false 
     *     if the removal was caused by a {@link #put} or {@link #remove}. 
     * true---is deleted for free space; false - put or remove causes
     * @param newValue the new value for {@code key}, if it exists. If non-null, 
     *     this removal was caused by a {@link #put}. Otherwise it was caused by 
     *     an eviction or a {@link #remove}. 
     */  
    protected void entryRemoved(boolean evicted, K key, V oldValue, V newValue) {}  

    /** 
     * Called after a cache miss to compute a value for the corresponding key. 
     * Returns the computed value or null if no value can be computed. The 
     * default implementation returns null. 
     * Called when an Item is missing and returns the corresponding calculated value or null
     * <p>The method is called without synchronization: other threads may 
     * access the cache while this method is executing. 
     * 
     * <p>If a value for {@code key} exists in the cache when this method 
     * returns, the created value will be released with {@link #entryRemoved} 
     * and discarded. This can occur when multiple threads request the same key 
     * at the same time (causing multiple values to be created), or when one 
     * thread calls {@link #put} while another is creating a value for the same 
     * key. 
     */  
    protected V create(K key) {  
        return null;  
    }  

    private int safeSizeOf(K key, V value) {  
        int result = sizeOf(key, value);  
        if (result < 0) {  
            throw new IllegalStateException("Negative size: " + key + "=" + value);  
        }  
        return result;  
    }  

    /** 
     * Returns the size of the entry for {@code key} and {@code value} in 
     * user-defined units.  The default implementation returns 1 so that size 
     * is the number of entries and max size is the maximum number of entries. 
     * Return the size of the user-defined item, the default return 1 represents the number of items, the maximum size is the maximum item value
     * <p>An entry's size must not change while it is in the cache. 
     */  
    protected int sizeOf(K key, V value) {  
        return 1;  
    }  

    /** 
     * Clear the cache, calling {@link #entryRemoved} on each removed entry. 
     * 清空cacke
     */  
    public final void evictAll() {  
        trimToSize(-1); // -1 will evict 0-sized elements  
    }  

    /** 
     * For caches that do not override {@link #sizeOf}, this returns the number 
     * of entries in the cache. For all other caches, this returns the sum of 
     * the sizes of the entries in this cache. 
     */  
    public synchronized final int size() {  
        return size;  
    }  

    /** 
     * For caches that do not override {@link #sizeOf}, this returns the maximum 
     * number of entries in the cache. For all other caches, this returns the 
     * maximum sum of the sizes of the entries in this cache. 
     */  
    public synchronized final int maxSize() {  
        return maxSize;  
    }  

    /** 
     * Returns the number of times {@link #get} returned a value that was 
     * already present in the cache. 
     */  
    public synchronized final int hitCount() {  
        return hitCount;  
    }  

    /** 
     * Returns the number of times {@link #get} returned null or required a new 
     * value to be created. 
     */  
    public synchronized final int missCount() {  
        return missCount;  
    }  

    /** 
     * Returns the number of times {@link #create(Object)} returned a value. 
     */  
    public synchronized final int createCount() {  
        return createCount;  
    }  

    /** 
     * Returns the number of times {@link #put} was called. 
     */  
    public synchronized final int putCount() {  
        return putCount;  
    }  

    /** 
     * Returns the number of values that have been evicted. 
     * Return the number of recycled
     */  
    public synchronized final int evictionCount() {  
        return evictionCount;  
    }  

    /** 
     * Returns a copy of the current contents of the cache, ordered from least 
     * recently accessed to most recently accessed. Returns a copy of the current cache, from least recently accessed to most accessed
     */  
    public synchronized final Map<K, V> snapshot() {  
        return new LinkedHashMap<K, V>(map);  
    }  

    @Override public synchronized final String toString() {  
        int accesses = hitCount + missCount;  
        int hitPercent = accesses != 0 ?(100 * hitCount/accesses) : 0;  
        return String.format("LruCache[maxSize=%d,hits=%d,misses=%d,hitRate=%d%%]",  
                maxSize, hitCount, missCount, hitPercent);  
    }  
}

Local refresh of listview and GridView

As we all know, listview and GridView refresh the interface by calling adapter.notifyDataSetChanged () refresh the interface. But this method has its disadvantages. It refreshes all the data in the interface, no matter whether the data has changed or not. If listview loads a lot of data (e.g. 100 entries)

When refreshing, it will cause a lot of system overhead. How to refresh only one like QQ space personal dynamic

Main principles:
refresh an item in listview
1. Get the current index position and data of the item to be refreshed
2. Reset the acquired data
3. Put the reset data in the original position of the data set in the adapter (refresh a piece of data in the original data set according to the position)
4. Get the view of the sub item to be refreshed in listview
5. Get new data from the updated data set and update the data in viwe (operate in handler to refresh the interface)

The functions are as follows, with detailed comments in the code:

public class MainActivity extends Activity  
{  

    private ArrayList<MyListItem> list = null;  
    private ListView              lv;  
    private MyListAdapter         adapter;  

    @Override  
    protected void onCreate(Bundle savedInstanceState)  
    {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.activity_main);  
        intitData();  
        lv = (ListView) findViewById(R.id.listView1);  
        adapter = new MyListAdapter(list, getApplicationContext());  
        adapter.setListView(lv);  
        lv.setAdapter(adapter);  

        lv.setOnItemClickListener(new OnItemClickListener()  
        {  

            @Override  
            public void onItemClick(AdapterView<?> parent, View view, int position, long id)  
            {  
                // Get the data of the clicked item in the listview   
                MyListItem item = (MyListItem) parent.getItemAtPosition(position);  
                Log.i("eee", item.getData() + " == " + item.getPosition());  
                // Update data  
                item.setData("update item " + position);  
                // Update Interface  
                adapter.updateItemData(item);  
            }  
        });  

    }  

    /** 
     * Initialization data 
     */  
    private void intitData()  
    {  
        list = new ArrayList<MyListItem>();  
        for (int i = 0; i < 20; i++)  
        {  
            MyListItem item = new MyListItem();  
            item.setData("item " + i);  
            item.setPosition(i);  
            list.add(item);  
        }  
    }  

    /** 
     * Customize item data type 
     */  
    class MyListItem  
    {  
        /** 
         * data id 
         */  
        private int    dataId;  
        /** 
         * datas 
         */  
        private String data;  

        public int getPosition()  
        {  
            return dataId;  
        }  

        public void setPosition(int position)  
        {  
            this.dataId = position;  
        }  

        public String getData()  
        {  
            return data;  
        }  

        public void setData(String data)  
        {  
            this.data = data;  
        }  

    }  
}  
activity to call, the function operation is mainly encapsulated in the adapter as follows.

public class MyListAdapter extends BaseAdapter  
{  

    /** 
     * Data sets in listview 
     */  
    private ArrayList<MyListItem> mDataList;  

    private Context               mContext;  
    private ListView              mListView;  

    public MyListAdapter(ArrayList<MyListItem> list, Context cont)  
    {  
        this.mDataList = list;  
        this.mContext = cont;  
    }  

    /** 
     * Set the listview object 
     *  
     * @param lisv 
     */  
    public void setListView(ListView lisv)  
    {  
        this.mListView = lisv;  
    }  

    /** 
     * update listview Single data 
     *  
     * @param item New data object 
     */  
    public void updateItemData(MyListItem item)  
    {  
        Message msg = Message.obtain();  
        int ids = -1;  
        // Compare data to get the position of the corresponding data in the list  
        for (int i = 0; i < mDataList.size(); i++)  
        {  
            if (mDataList.get(i).getPosition() == item.getPosition())  
            {  
                ids = i;  
            }  
        }  
        msg.arg1 = ids;  
        // Update the data in the corresponding position of mDataList  
        mDataList.set(ids, item);  
        // handle refreshes the interface  
        han.sendMessage(msg);  
    }  

    @SuppressLint("HandlerLeak")  
    private Handler han = new Handler()  
                        {  
                            public void handleMessage(android.os.Message msg)  
                            {  
                                updateItem(msg.arg1);  
                            };  
                        };  

    /** 
     * Refresh the specified item 
     *  
     * @param index item's position in listview 
     */  
    private void updateItem(int index)  
    {  
        if (mListView == null)  
        {  
            return;  
        }  

        // Get the currently visible position of the item  
        int visiblePosition = mListView.getFirstVisiblePosition();  
        // If you add headerview, firstview is hearderview  
        // All indexes + 1 to get the first view  
        // View view = listview.getChildAt(index - visiblePosition + 1);  
        // Get the clicked view  
        View view = mListView.getChildAt(index - visiblePosition);  
        TextView txt = (TextView) view.findViewById(R.id.textView1);  
        // get mDataList.set(ids, item); the updated data  
        MyListItem data = (MyListItem) getItem(index);  
        // Reset the interface to display data  
        txt.setText(data.getData());  
    }  

    @Override  
    public int getCount()  
    {  
        // TODO Auto-generated method stub  
        return mDataList.size();  
    }  

    @Override  
    public Object getItem(int position)  
    {  
        // TODO Auto-generated method stub  
        return mDataList.get(position);  
    }  

    @Override  
    public long getItemId(int position)  
    {  
        // TODO Auto-generated method stub  
        return position;  
    }  

    @Override  
    public View getView(int position, View convertView, ViewGroup parent)  
    {  
        // TODO Auto-generated method stub  
        if (convertView == null)  
        {  
            convertView = LayoutInflater.from(mContext).inflate(R.layout.list_item, null);  
        }  
        TextView txt = (TextView) convertView.findViewById(R.id.textView1);  
        txt.setText(mDataList.get(position).getData());  
        return convertView;  
    }  

}  

No matter how far and hard the road ahead is, as long as the direction is right, no matter how rugged, it is closer to happiness than standing in the same place!

19 Android must kill gadgets

19 Android must kill gadgets

1. Xappdbg
xappdbg is an application development tool that can change the parameters in the code during operation. This tool can save you a lot of time, because you don’t have to recompile and run your program for every small change of the application.

2. Chkbugreport
this tool can quickly check the output Android error reports. It does semantic analysis from a large number of text files output by Android error reporting tool, and then parses them into a more readable document, which is easier to analyze. Chkbugreport is also an open source project.
3. Apkanalyser
this is a static and virtual analysis tool. You can have a comprehensive overview of the application architecture. You can use it to check API references, check application dependencies, and decompile bytecode. Apkanalyser is a complete open source tool chain. It supports modifying the application binary code. You can repackage, install, run and verify the results of logcat.

4. Appxplore
with the appxplore tool, you can browse all the apps installed on your Android device, and analyze the details of many apps — app version, package name, certificate, permission, signature, activities and other information that can’t be viewed on many devices. Appxplore is especially useful for checking the memory size occupied by the application when it is running and whether the files can be moved to the SD card. Similarly, developers can test and ensure the quality of the application. This ensures that the application displays the appropriate permissions on the manifest file.
5. Memory analyzer (MAT)
memory analyzer on eclipse is a fast and functional Java heap analysis tool, which can help you find memory leaks and reduce memory overhead. Using memory analyzer, we can analyze millions of objects and multiple heap dumps, quickly count the number of objects left, so that we can see which objects prevent the garbage collector from collecting. Finally, run a report to automatically report the suspicious place that caused the leak.
6. Eclipse Plug-in sqlitemanger
this plug-in can help developers view and modify SQLite database on eclipse.
7. Robotium
robotium is a testing framework, which can simply write a powerful and robust automatic black box test container for Android applications. With robotium, test developers can support a variety of Android activities to write function, system and acceptance test scripts. Robotics fully supports activity, dialogues, toast, menus and context menus.
8. Acra
acra is a function library that allows Android applications to automatically issue Google doc format crash reports. Android developers can get the data of application crash or wrong behavior through acra. If a crash occurs, your application will not add user alerts beyond the existing system crash alerts or reporting functions. If toast, status bar or direct dialog mode is used, the “forced close” dialog will no longer be displayed. Even if the reminder function of the native system on the device is turned on, another report cannot be sent.
Br> the Android binder will convert all of your Android layout statements into a series of XML files. Type a prefix, select the range to paste on the XML file, and then click generate. Select “verb” to find out why all the areas are skipped.
10. The ever expanding ecosystem of Android devices has brought unique challenges to test applications. Spoon simplifies this task by assigning execution of instrumentation tests and displaying results in a more meaningful way. Instead of trying to be a new form of testing, spoon makes the current instrumentation testing more useful. With the application’s APK and instrumentation APK, spoon can run tests on multiple devices at the same time. Once all the tests are completed, a static HTML summary is generated that includes the details of the various device tests.
11. Android content provider code generator
do you often copy and paste a lot of code to write a content provider?Then this code generation tool can help you.
12. Start your next android app in 10 seconds. Android KickStarter uses the most popular library to help you quickly build a configured android app. It creates and configures projects for you, and focuses directly on the code!
13. Android holo color generator
this Android holo color generator allows you to simply create Android components for your application, such as editext or spinner, and use your own colors. It will generate all nine necessary patch assets and related XML drawables and styles files, which can be directly copied into your project.
14. Actionbar style generator
this actionbar style generator allows you to easily create a concise, attractive and bug free custom actionbar. It will generate all nine necessary patch assets and related XML drawables and styles files, which can be copied directly into your project.
15. Asset studio
asset Studio allows you to quickly and easily generate icons from existing images, clip art or text resources.
16. Little eye labs
little eye labs is a performance analysis tool for Android applications. Its product has been renamed “little eye” instead of “little eye appinsight”. Keep our product catalog concise, consistent with the overall theme that we focus on simplicity in each part of our work.
Main features:
outline any application;
record and playback video;
front end and background usage;
consumption of CPU, memory and data;
manual or automatic heap dump;
save and share.
17. The concept of “overdraw” is considered to be very important in the Android world. At the Google I/O conference, few speeches emphasized the importance of reducing overdraft. This is the first tool (the best I know) that can help us easily identify overdrafts.
Main features
3D query;
find overdraft;
box model;
combine with DDMS;
view hierarchy;
background/content;
webgl;
2D to 3D to 2D;
· more
18. Android Button Maker
Android Button Maker is a tool that can generate button code online. The Android API provides drawable resources for geometric shapes defined by XML files, including colors, boundaries, and gradients. The generation of these buttons is based on XML code in drawable form, which can load faster than ordinary PNG buttons. You can customize the properties of the button on the settings panel and get its source code.
19. Jsonschema2pojo
is used to generate POJO (plain old Java object) class on JSON architecture. This small and powerful tool can save you the time to write POJO.

Android gets the height and width of the screen

Android gets the height and width of the screen and uses the WindowManager class

There are two methods

1、WindowManager wm = (WindowManager) getContext()
                    .getSystemService(Context.WINDOW_SERVICE);

     int width = wm.getDefaultDisplay().getWidth();
     int height = wm.getDefaultDisplay().getHeight();

2、WindowManager wm = this.getWindowManager();

     int width = wm.getDefaultDisplay().getWidth();
     int height = wm.getDefaultDisplay().getHeight();

Android EditText cursor control, color modification, show and hide

Modify the Android EditText cursor color:

QQ group: 372135639

EditText has one property: android:textCursorDrawable This property is used to control the color of the cursor

android:textCursorDrawable= ”@The function of “null” and “@ null” is to make the cursor color the same as text color

Android set EditText cursor color and thickness:

In the Android input box, if you want to change the color and thickness of the cursor, you can do it in the following two steps:

1. Create a new cursor control color in the resource file drawable_ cursor.xml

<?xml version="1.0" encoding="utf-8"?>  
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">  
    <size android:width="1dp" />  
    <solid android:color="#008000"  />  
</shape>  

Set the EditText cursor to show/hide

android:cursorVisible= ”True “//displays
the android:cursorVisible= ”False “//hide

Note: default display

//The cursor displays the problem by default. It will not be displayed by default on Meizu mx6. (it is better to control the display and hiding of cursor by code)

Android get screen width and height and get control width and height

The width and height of a control have a drawing process. The width and height of the control are directly obtained in the oncreate method, which is generally 0. Therefore, we need to use the following methods to obtain the width and height of the control:
Load onmeasure twice, but the callback function only calls back once

ViewTreeObserver vto2 = imageView.getViewTreeObserver();    
        vto2.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {  
            @Override    
            public void onGlobalLayout() {  
                imageView.getViewTreeObserver().removeGlobalOnLayoutListener(this);    
                textView.append("\n\n"+imageView.getHeight()+","+imageView.getWidth());  
            }    
        });    

Listview remembers location not itme location

In order to achieve better user experience in application development, listview needs to remember the last sliding position. Getscroll () always returns 0, because getscroll () is the view method.

Finally, I found this on Google:

// save index and top position  
int index = mList.getFirstVisiblePosition();  
View v = mList.getChildAt(0);  
int top = (v == null) ?0 : v.getTop();  

// ...  

// restore  
mList.setSelectionFromTop(index, top);  

The problem can not be viewed in the corner log of the Mac computer

Write the custom directory title here

The problem can not be viewed in the corner log of the Mac computer

The problem can not be viewed in the corner log of the Mac computer

First of all, make sure that your version is cracked or genuine.

If it is a cracked version, the package name is: com.zennaware.cornerstone3 . MAS
the original is: com zennaware.Connerstone

If you use cornerstone to manage SVN, and the first time you view the log, you tragically choose download instead of never. Congratulations, you will not be able to view the log, and you will not be able to roll back. The solution is as follows:

Exit from cornerstone

Open the terminal, execute defaults delete com. Com zennaware.Connerstone HistoryCacheUsage

Go to the folder ~/library/caches/cornerstone to empty the files in the folder

Restart cornerstone and select never when viewing the log again
OK————————————————

~/Resource library/containers/ com.zennaware.cornerstone3 . MAS/data/library/caches/use this, I can find it. com.zennaware.cornerstone3 . MAS is because I use the cracked version.

About OSS file download and rename

Option 1

Add the response header through nginx, and add the parameter & amp; attname = filename after the download address

 location/{
           proxy_pass https://xxxx.oss-cn-shenzhen.aliyuncs.com;
           if ($query_string ~* ^(.*)attname=([^&]+)$) {
                add_header Content-Disposition "attachment;filename=$arg_attname";
           }
        }

Disadvantages: the download speed depends on the bandwidth of the server deployed by nginx, which affects the user experience
so there is a problem

Option 2

Get the source code of the file download address by viewing OSS:

@Override
    public URL generatePresignedUrl(String bucketName, String key, Date expiration) throws ClientException {
        return generatePresignedUrl(bucketName, key, expiration, HttpMethod.GET);
    }

    @Override
    public URL generatePresignedUrl(String bucketName, String key, Date expiration, HttpMethod method)
            throws ClientException {
        GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(bucketName, key);
        request.setExpiration(expiration);
        request.setMethod(method);

        return generatePresignedUrl(request);
    }

    @Override
    public URL generatePresignedUrl(GeneratePresignedUrlRequest request) throws ClientException {

        assertParameterNotNull(request, "request");

        if (request.getBucketName() == null) {
            throw new IllegalArgumentException(OSS_RESOURCE_MANAGER.getString("MustSetBucketName"));
        }
        ensureBucketNameValid(request.getBucketName());

        if (request.getExpiration() == null) {
            throw new IllegalArgumentException(OSS_RESOURCE_MANAGER.getString("MustSetExpiration"));
        }
        String url;

        if (serviceClient.getClientConfiguration().getSignatureVersion() != null && serviceClient.getClientConfiguration().getSignatureVersion() == SignVersion.V2) {
            url = SignV2Utils.buildSignedURL(request, credsProvider.getCredentials(), serviceClient.getClientConfiguration(), endpoint);
        } else {
            url = SignUtils.buildSignedURL(request, credsProvider.getCredentials(), serviceClient.getClientConfiguration(), endpoint);
        }

        try {
            return new URL(url);
        } catch (MalformedURLException e) {
            throw new ClientException(e);
        }
    }

It is found that the final call is generatepreseignedurl (generatepreseignedurlrequest request) method
so we study generatepreseignedurlrequest
and find a method to rewrite the response header

 /**
     * Sets the response headers to override.
     *
     * @param responseHeaders
     *            The response headers to override.
     */
    public void setResponseHeaders(ResponseHeaderOverrides responseHeaders) {
        this.responseHeaders = responseHeaders;
    }

Then test the following code

GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(BUCKETNAME, key);
request.setExpiration(new Date(System.currentTimeMillis() + 3600 * 1000 * 24 * 7));
request.setMethod(HttpMethod.GET);
ResponseHeaderOverrides header = new ResponseHeaderOverrides();
header.setContentDisposition("attachment;filename=" + fileName);
request.setResponseHeaders(header);
URL url = ossClient.generatePresignedUrl(request);

The returned URL contains more & amp; response content disposition = attachment% 3bfilename% 3dfilname
test links, which can be renamed