Wednesday 1 June 2016

Solving Memory leaks issue with custom font in Android

Today I will discuss some memory leak issue while using custom fonts in android.

Using custom fonts may leads to some serious memory leak issues so while using custom fonts you should avoid this memory leaks.

Steps to reproduce 
1. Write an application that calls Typeface.createFromAsset() multiple times.
2. Make sure that the typeface objects are out of scope and the garbage collector has completed at least one pass.
3. Run adb shell dumpsys meminfo <your app package>

For complete issue discussion please visit https://code.google.com/p/android/issues/detail?id=9904

Normally we use custom fonts as below
Typeface font = Typeface.createFromAsset(getContext().getAssets(), "fonts/Arial.ttf");
tv.setTypeface(font);

Please a take a look on memory dumb, when custom views are used.

** MEMINFO in pid 10045 [com.android.test] **
                         Shared  Private     Heap     Heap     Heap
                   Pss    Dirty    Dirty     Size    Alloc     Free
                ------   ------   ------   ------   ------   ------
       Native        0        0        0    15596    14337     1258
       Dalvik    44483    11156    44292    64775    43074    21701
       Cursor        0        0        0                           
       Ashmem        0        0        0                           
    Other dev        4       36        0                           
     .so mmap     5380     2196     4752                           
    .jar mmap        0        0        0                           
    .apk mmap      362        0        0                           
    .ttf mmap      102        0        0                           
    .dex mmap      964        0        0                           
   Other mmap     1283      320      204                           
      Unknown     9452      528     9448                           
        TOTAL    62030    14236    58696    80371    57411    22959

 Objects
               Views:      981         ViewRootImpl:        2
         AppContexts:        4           Activities:        3
              Assets:       28        AssetManagers:       28
       Local Binders:       16        Proxy Binders:       19
    Death Recipients:        0
     OpenSSL Sockets:        1

 SQL
         MEMORY_USED:        0
  PAGECACHE_OVERFLOW:        0          MALLOC_SIZE:        0


 Asset Allocations
    zip:/data/app/com.android.test-2.apk:/resources.arsc: 135K
    zip:/data/app/com.android.test-2.apk:/assets/fonts/Trebuchet MS.ttf: 133K
    zip:/data/app/com.android.test-2.apk:/assets/fonts/Trebuchet MS Bold.ttf: 123K
    zip:/data/app/com.android.test-2.apk:/assets/fonts/Trebuchet MS Bold.ttf: 123K
    zip:/data/app/com.android.test-2.apk:/assets/fonts/Trebuchet MS Bold.ttf: 123K
    zip:/data/app/com.android.test-2.apk:/assets/fonts/Trebuchet MS Bold.ttf: 123K
    zip:/data/app/com.android.test-2.apk:/assets/fonts/Trebuchet MS Bold.ttf: 123K
    zip:/data/app/com.android.test-2.apk:/assets/fonts/Trebuchet MS Bold.ttf: 123K
    zip:/data/app/com.android.test-2.apk:/assets/fonts/Trebuchet MS.ttf: 133K
    zip:/data/app/com.android.test-2.apk:/assets/fonts/Trebuchet MS Bold.ttf: 123K
    zip:/data/app/com.android.test-2.apk:/assets/fonts/Trebuchet MS Bold.ttf: 123K
    zip:/data/app/com.android.test-2.apk:/assets/fonts/Trebuchet MS Bold.ttf: 123K
    zip:/data/app/com.android.test-2.apk:/assets/fonts/Trebuchet MS Bold.ttf: 123K
    zip:/data/app/com.android.test-2.apk:/assets/fonts/Trebuchet MS Bold.ttf: 123K
    zip:/data/app/com.android.test-2.apk:/assets/fonts/Trebuchet MS Bold.ttf: 123K
    zip:/data/app/com.android.test-2.apk:/assets/fonts/Trebuchet MS Bold.ttf: 123K
    zip:/data/app/com.android.test-2.apk:/assets/fonts/Trebuchet MS.ttf: 133K
    zip:/data/app/com.android.test-2.apk:/assets/fonts/Trebuchet MS Bold.ttf: 123K
    zip:/data/app/com.android.test-2.apk:/assets/fonts/Trebuchet MS Bold.ttf: 123K
    zip:/data/app/com.android.test-2.apk:/assets/fonts/Trebuchet MS Bold.ttf: 123K
    zip:/data/app/com.android.test-2.apk:/assets/fonts/Trebuchet MS Bold.ttf: 123K
    zip:/data/app/com.android.test-2.apk:/assets/fonts/Trebuchet MS Bold.ttf: 123K
    zip:/data/app/com.android.test-2.apk:/assets/fonts/Trebuchet MS Bold.ttf: 123K
    zip:/data/app/com.android.test-2.apk:/assets/fonts/Trebuchet MS Bold.ttf: 123K
    zip:/data/app/com.android.test-2.apk:/assets/fonts/Trebuchet MS.ttf: 133K
    zip:/data/app/com.android.test-2.apk:/assets/fonts/Trebuchet MS Bold.ttf: 123K
So instead of this we should cache the Typeface as below


public class FontCache {

    private static Hashtable<String, Typeface> fontCache = new Hashtable<String, Typeface>();

    public static Typeface get(String name, Context context) {
        Typeface tf = fontCache.get(name);
        if(tf == null) {
            try {
                tf = Typeface.createFromAsset(context.getAssets(), name);
            }
            catch (Exception e) {
                return null;
            }
            fontCache.put(name, tf);
        }
        return tf;
    }
}



Usage
Typeface tf = FontCache.get("fonts/MavenPro-Regular.ttf", this);
mTestTV.setTypeface(tf);
mTestTV.setText("Safe typeface use");


References
https://stackoverflow.com/questions/16901930/memory-leaks-with-custom-font-for-set-custom-font

https://stackoverflow.com/questions/23977114/custom-font-in-android-leaking-memory

Please try to use custom font with and without caching in a listview of some 100 items you will get the difference

Source code : https://github.com/gaikwadChetan93/SafeCustomFonts

Try it yourself
Please suggest if any update.
Updates are always welcome
HAPPY CODING :)

My Apps MobileUtility

Friday 20 May 2016

Faster sqlite database insertion

Many a time we have the requirement to insert bulk of data into Android SQLite database, but the normal database insert() operation provided by SQLiteDatabase.java class will take more time in such situation.
So today we will see how to make database insertion faster for bulk data insertion by using transaction with database insert() operation.
Let's see a sqlite database operation example
Here I will take an example of managing student database with just insert operation


Student.java
public class Student {

   private int id;
   private String name;

   public long getId() {
      return id;
   }

   public void setId(int id) {
      this.id = id;
   }

   public String getName() {
      return this.name;
   }

   public void setName(String name) {
      this.name = name;
   }

   @Override   public String toString() {
      return name;
   }
}






DataBaseWrapper.java


import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;

public class DataBaseWrapper extends SQLiteOpenHelper {

   public static final String STUDENTS = "Students";
   public static final String STUDENT_ID = "_id";
   public static final String STUDENT_NAME = "_name";

   private static final String DATABASE_NAME = "Students.db";
   private static final int DATABASE_VERSION = 1;

  // creation SQLite statement
private static final String DATABASE_CREATE = "create table " + STUDENTS + "(" + STUDENT_ID + "" +
      " integer primary key autoincrement, " + STUDENT_NAME + " text not null);";

public DataBaseWrapper(Context context) {
   super(context, DATABASE_NAME, null, DATABASE_VERSION);
}

@Overridepublic void onCreate(SQLiteDatabase db) {
   db.execSQL(DATABASE_CREATE);
}
@Overridepublic void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
   db.execSQL("DROP TABLE IF EXISTS " + STUDENTS);
   onCreate(db);
}
}
StudentOperations.java
import android.content.ContentValues;
import android.content.Context;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;

public class StudentOperations {

   // Database fields   private DataBaseWrapper dbHelper;
   private String[] STUDENT_TABLE_COLUMNS = { DataBaseWrapper.STUDENT_ID,
 DataBaseWrapper.STUDENT_NAME };
   private SQLiteDatabase database;

   public StudentOperations(Context context) {
      dbHelper = new DataBaseWrapper(context);
   }

   public void open() throws SQLException {
      database = dbHelper.getWritableDatabase();
   }

//normal database insert operation
   public void addStudent(String name) {

      for(int i=0; i<1000;i++) {
         ContentValues values = new ContentValues();
         values.put(DataBaseWrapper.STUDENT_NAME, name);
         long studId = database.insert(DataBaseWrapper.STUDENTS, null, values);
      }
   }

//faster database insert operation
public void addStudentbulk(String name) { database.beginTransaction(); for(int i=0; i<1000;i++) { ContentValues values = new ContentValues(); values.put(DataBaseWrapper.STUDENT_NAME, name); database.insert(DataBaseWrapper.STUDENTS, null, values); } database.setTransactionSuccessful(); database.endTransaction(); } }
MainActivity.java 
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

public class MainActivity extends AppCompatActivity {

    private StudentOperations studentDBoperation;

    @Override    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        studentDBoperation = new StudentOperations(this);
        studentDBoperation.open();
        long startTime = System.nanoTime();
        //studentDBoperation.addStudent("Chetan");        
        studentDBoperation.addStudentbulk("Chetan");
        long endTime = System.nanoTime();
        long duration = (endTime - startTime)/1000000000;
        System.out.println("time taken : "+duration);
    }

}
You can calculate the time taken by both the operation I have also 
include the logic of time calculation to perform each operation.
You can comment the either operation and can get result
For me
Time take to insert 1000 students record is
by normal database operation operation : 
6+ seconds
by faster database operation operation :
less than one seconds
Try it yourself
Please suggest if any update.
Updates are always welcome
HAPPY CODING :)


source code  https://github.com/gaikwadChetan93/FasterDatabaseOperation

My Apps MobileUtility