-
Recent Posts
Recent Comments
Cookies are wiped on… on Persisting Cookies through Act… Xursi on New Academic Blog Vignaya on CursorAdapter with Alphabet-in… Alex on Syncing cookies between an Htt… Bashar Labadi on CursorAdapter with Alphabet-in… Archives
Categories
Meta
New Academic Blog
Posted in Uncategorized
1 Comment
Using SQLite Transactions with your ContentProvider
In the world of databases, a transaction is a unit of work (including insertions, deletions, updates) that is Atomic, Consistent, Isolated, and Durable. By default in SQLite, each insertion is a transaction. And to preserve data integrity, SQLite will wait until data is stored on the disk before completing the transaction. So if you have a large data set that you’re trying to insert into your database, inserting each piece individually is going to seem extremely slow.
You want to use transactions, not just because they will increase the performance of your database operations. Because transactions are atomic, they will help you ensure your database is consistent. For example, if you need to process a large batch of instructions, then either everything happened correctly, or if something went wrong then that whole transaction failed (so it’s all or nothing).
By default the ContentResolver API provides a bulkInsert() method, but its not atomic and its slow as hell, so let’s override the bulkInsert() method in our ContentProvider.
public class YourProvider extends ContentProvider { //..... define constants for the UriMatcher public static final int EVENTS = 1; public static final int FESTIVITIES = 2; //.... private static final UriMatcher sUriMatcher = buildUriMatcher(); private YourDatabase mOpenHelper; /** * Creates the Uri matcher */ private static UriMatcher buildUriMatcher(){ final UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH); final String authority = YOUR_CONTENT_AUTHORITY; //let the matcher match URIs with your defined constants matcher.addURI(authority, "events", EVENTS); matcher.addURI(authority, "festivities", FESTIVITIES); //..... return matcher; } @Override public boolean onCreate() { mOpenHelper = new YourDatabase(getContext()); return true; } @Override public String getType(Uri uri) { final int match = sUriMatcher.match(uri); switch(match){ case EVENTS: return EVENTS.CONTENT_TYPE; case FESTIVITIES: return FESTIVITIES.CONTENT_TYPE; //...... default: throw new UnsupportedOperationException("unknown: uri " + uri); } } @Override public int bulkInsert(Uri uri, ContentValues[] values) { final SQLiteDatabase db = mOpenHelper.getWritableDatabase(); final int match = sUriMatcher.match(uri); switch(match){ case EVENTS: int numInserted= 0; db.beginTransaction(); try { //standard SQL insert statement, that can be reused SQLiteStatement insert = db.compileStatement("insert into " + YOUR TABLE + "(" + COLUMN1 + "," + COLUMN2 + "," + COLUMN3 + ")" +" values " + "(?,?,?"); for (ContentValues value : values){ //bind the 1-indexed ?'s to the values specified insert.bindString(1, value.getAsString(COLUMN1)); insert.bindString(2, value.getAsLong(COLUMN2)); insert.bindString(3, value.getAsString(COLUMN3)); insert.execute(); } db.setTransactionSuccessful(); numInserted = values.length } finally { db.endTransaction(); } return numInserted; //.... default: throw new UnsupportedOperationException("unsupported uri: " + uri); }} }
So, for each ContentURI you are suppporting (each table in your db), write its respective bulkInsert case as above. And now you will witness an absolutely HUGE increase in performance (for me it cut the bulkInsert() time from 20 seconds to 1), and the return value of the bulkInsert() will now let you know if the transaction was successful or not. Also look here to see the transaction API.
Posted in Android
Tagged bulkinsert, contentprovider, contentresolver, insert, sqlite, transaction
2 Comments
Persisting Cookies through Activity Life Cycle
If you are coding an Android REST application using the Apache HttpClient, there may be times when you bring another application into the foreground (like Google Maps to get driving directions), and the process containing your application is killed because of low system memory. Your instance of the HttpClient is dead, and so it no longer has the session information cookies needed to run the app.
After the process is killed, navigating back to your activity causes onCreate() to be called (Application Fundamentals). Thus, in the onCreate() method, we can first check to see if the session cookies are gone, and if so, re-add them to the HttpClient.
In order to put the Cookie in a Bundle, we must make it serialiazable. Unfortunately Cookie is not serializable in the Apache API version that Android currently uses, so we must define our own class to do this.
public class SerializedCookie implements Serializable { private static final long serialVersionUID = 5327445113190674523L; //arbitrary private String name; private String value; private String domain; public SerializedCookie(Cookie cookie){ this.name = cookie.getName(); this.value = cookie.getValue(); this.domain = cookie.getDomain(); } public String getName(){ return name; } public String getValue(){ return value; } public String getDomain(){ return domain; } }
Now in our Activities we need to override the onCreate() and onSaveInstanceState() methods.
DefaultHttpClient client; //declared here, but get the client however you must. @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); List<Cookie> cookies =client.getCookies(); if (!cookies.isEmpty()){ Cookie sessionInfo = cookies.get(0); outState.putSerializable("sessionInfo", new SerializedCookie(sessionInfo)); }
DefaultHttpClient client; //declared here, but get the client however you must. @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (client.getCookies().isEmpty()){ if (savedInstanceState.containsKey("sessionInfo")){ SerializedCookie cookie = (SerializedCookie) savedInstanceState. getSerializable("sessionInfo"); BasicClientCookie newCookie = new BasicClientCookie(cookie.getName(), cookie.getValue()); newCookie.setDomain(cookie.getDomain()); client.addCookie(newCookie); } else { //for whatever reason the session information couldn't be obtained, //take action here } }
Now if you open another application and the process running your app is killed, when you navigate back to it, your activity will try to re-insert the session cookie into the HttpClient, and your app will run normally.
Posted in Android
Tagged android, cookies, httpclient, kill process, low memory, persistent cookie
3 Comments
Converting a Hex String to N-bit Binary String
Recently I have wanted to keep track of unique IDs of the Android devices using one of my applications. These are found under Settings.Secure.ANDROID_ID and are 64bit numbers given as Hex Strings, but I needed the actual binary number, with leading zeros included. I did a lot of research but couldn’t find a complete elegant solution, so here is what I came up with:
private static String hexStringToNBitBinary(String hexString, int N){ long decimalResult = 0; int length = hexString.length(); //store the length in memory, for devices without a JIT int i; for (i = 0; i < length; i++){ //equivalent to multiplying the result by 16 and adding the value of the new digit, but uses bit operations for performance decimalResult = (decimalResult << 4 ) | Character.digit(hexString.charAt(i), 16); } String binary = Long.toBinaryString(decimalResult); //gives us a binary string, but is missing leading zeros length = binary.length(); if (length == N){ return binary; } else if (length < N){ int difference = N-length; char[] buffer = new char[N]; //allocate a new char buffer of the desired length for (i = 0; i < difference; i ++){ buffer[i] = '0'; //fill in the needed number of leading zeros } binary.getChars(0, length, buffer, difference); //copies the original binary string into the buffer after leading zeros return new String(buffer); } else{ throw new IllegalArgumentException("Hex String is not a N bit number!"); } }
I believe that this is has better performance than using String concatenations or StringBuilder appends, since we allocate just the number of memory we know we need immediately. Let me know if there is a more efficient way.
Posted in Programming
Tagged convert hex to binary, hex string to binary, java, leading zeros
1 Comment
Syncing cookies between an HttpClient and a WebView
Hey all,
Today I would like to show how to share cookies between an HttpClient and a WebView. This is necessary when your application use an HttpClient to make POST/GET calls, and then opens a WebView to a webpage that needs the same session information. Say that we are using a DefaultHttpClient named client.
DefaultHttpClient client; //gets all cookies from the HttpClient's cookie jar List<Cookie> cookies = client.getCookieStore().getCookies(); if (! cookies.isEmpty()){ CookieSyncManager.createInstance(YourContext.this); CookieManager cookieManager = CookieManager.getInstance(); //sync all the cookies in the httpclient with the webview by generating cookie string for (Cookie cookie : cookies){ sessionInfo = cookie; String cookieString = sessionInfo.getName() + "=" + sessionInfo.getValue() + "; domain=" + sessionInfo.getDomain(); cookieManager.setCookie(YOUR_DOMAIN, cookieString); CookieSyncManager.getInstance().sync(); } }
Make sure that YOUR_DOMAIN corresponds to the domain of the website you need session info from, else this won’t work.
On StackOverflow there is a similar solution, but I found that calling cookieManager.removeSessionCookie() makes it often not work for me (in particular if I got a new session cookie by logging out/changing user). I’m not sure why, since in the thread they have the opposite happening. But, the above code has never failed for me.
The Singleton Design Pattern
Often in object-oriented programming, we run into situations where we need to have a single instance of an object that can be globally accessed from the whole application. For example, if we needed to use an HTTP client for our whole application, the most efficient approach would be to use a single one maintaining session information. In such cases, the singleton pattern is extremely useful.
In particular to Android, the Singleton can be referenced by all classes in your application, but one must be careful to tear-down the singleton when its no longer needed (for example when the application calls onDestroy()) because the Singleton’s life cycle is not managed by the system.
Why not just make a class with all methods being static? It turns out that this is bad for modularity (since we are forced to use THAT particular class in our code). Also since access is global, we must also worry about concurrency (that is, if the singleton is created at the same time from two independent threads, resulting in the creation of multiple singletons).
Let’s see how we can implement this in Java.
public class Singleton { private final Singleton instance = new Singleton(); private Singleton(){ //... implementation goes here } public Singleton getInstance(){ return this.instance; } }
This is thread-safe because the singleton is created as soon as the class is initialized, so we don’t need to worry that two different threads may try to create it. There is another approach, which allows the singleton to be loaded only when needed.
public class Singelton { private Singleton(){ //... implementation goes here } private static class SingletonHolder { private final Singleton instance = new Singleton(); } public static Singleton getInstance(){ return SingletonHolder.instance; } }
This is also thread-safe because the Singleton (which is final) is created the very first time getInstance() is called. Note in both examples that the constructors are private, to prevent other classes from accessing them.
Posted in Programming
Leave a comment
First post
Hey all. This is where I’m going to post about all the interesting things I come across. We learn more by explaining to others, so hopefully this will further my own understanding too. Enjoy!
Posted in Reflection
1 Comment