Sunday, September 7, 2014

Android ListView: Maintain your scroll position when you refresh

The Obvious

I figured that when I've downloaded the new list of stuff I want to show, that I could just create a new adapter and stuff it into the list.
EventLogAdapter eventLogAdapter = new EventLogAdapter(mContext, events);
mEventListView.setAdapter(eventLogAdapter);
This works, in that the list gets updated. But it always scrolls all the way back up to the top. Sometimes that might be what you want, but most of the time you'll want to maintain your scroll position.

The Naive

I tried getting pixel-level scroll position using getScrollY(), but it always returned 0. I don't know what it's supposed to do. I ended up going with a solution that got close to maintaining your scroll position.
int firstPosition = mEventListView.getFirstVisiblePosition();
EventLogAdapter eventLogAdapter = new EventLogAdapter(mContext, events);
mEventListView.setAdapter(eventLogAdapter);
mEventListView.setSelection(firstPosition);
This figures out the first item in the list you can see before resetting the adapter, and then scrolls you to it. This maintains your scroll position within some unknown/arbitrary range, and can cause you to jump around in the list a little bit when you refresh.
If you're scrolled halfway through a list item, it'll snap you to the top of it so it's completely visible. Unfortunately, if you're scrolled halfway through a list item, that probably wasn't the one you were paying the closest attention to.

The Elegant

There had to be a better way!
And, of course, there is. Romain Guy, an Android developer who haunts Stack Overflow and Google Groups dropping golden hints when people ask questions, pointed out:
The problem is that you are creating a new adapter every time you reload the data. That's not how you should use ListView and its adapter. Instead of setting a new adapter (which causes ListView to reset its state), simply update the content of the adapter already set on the ListView. And the selection/scroll position will be saved for you.
There are two problems with Romain Guy: 1) he doesn't have a central repository of these hints/answers so I can learn what to do before doing everything wrong first, and 2) they really are just hints, in that they point you in the right direction without getting you all the way there.
In this case, yes, updating the adapter without creating a new one every time will maintain your scroll position. Except that you'll frequently get an "IllegalStateException: The content of the adapter has changed but ListView did not receive a notification. Make sure the content of your adapter is not modified from a background thread, but only from the UI thread."
It turns out that you need to call notifyDataSetChanged() on your adapter after changing its contents; fortunately, that "only from the UI thread" bit was a red herring, because I didn't really want to do any processing that could/should be asynchronous on the UI thread.
I added a refill() method to my adapters:
public void refill(List events) {
    mEvents.clear();
    mEvents.addAll(events);
    notifyDataSetChanged();
}
And I call it when my download is complete:
if (mEventListView.getAdapter() == null) {
    EventLogAdapter eventLogAdapter = new EventLogAdapter(mContext, events);
    mEventListView.setAdapter(eventLogAdapter);
} else {
    ((EventLogAdapter)mEventListView.getAdapter()).refill(events);
}
If the list doesn't already have an adapter, then I create one. But if it does have an adapter, then I just refill it. And it maintains my scroll position exactly!

Monday, July 14, 2014

Android: Return search query to current activity

Android: Return search query to current activity

In your Application Manifest you need to define the current activity as a searchable activity.
 android:name="BrowseItems" android:label="@string/browseitems"
            android:launchMode="singleTop">
            
                 android:name="android.intent.action.SEARCH" />
            
android:name="android.app.searchable" android:resource="@xml/itemsearchable" /> You then use the following code, which is from http://developer.android.com/guide/topics/search/search-dialog.html#LifeCycle
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.search);
    handleIntent(getIntent());
}

@Override
protected void onNewIntent(Intent intent) {
    setIntent(intent);
    handleIntent(intent);
}

private void handleIntent(Intent intent) {
    if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
      String query = intent.getStringExtra(SearchManager.QUERY);
      // Do work using string
    }
}
You can then use the string to reload your activity, if its a list activity you can call your code that you use to load data and use the string in that.

Thursday, May 29, 2014

Promises – an alternative way to approach asynchronous JavaScript

from http://12devs.co.uk/articles/promises-an-alternative-way-to-approach-asynchronous-javascript/

Even if you’ve done very little JavaScript, you should be familiar with callbacks, which are used heavily for managing asynchronous operations in JavaScript. We’re going to look at an alternative way to handle such asychronous code by using Promises. The examples I’m going to cover are going to use Node.js, but the techniques and libraries involved work equally well for client side JavaScript too. And, you definitely don’t need be an expert on Node.js to follow this article.

Why (not) callbacks?

Let’s get started with a simple example of reading the contents of a file in Node.js:
// readFileExample.js
var FS = require('fs');

FS.readFile('file.txt', 'utf8', function(err, data) {
    if (err) throw err;     
    console.log('File has been read:', data);
});

console.log('After readFile.');
Here we give readFile a function to call (which we refer to as a “callback”). This callback function is invoked once the contents of the file has been read. This is an asynchronous operation because the readFile call is non-blocking and if you were to execute the above program, you will notice that After readFile. will be printed before File has been read.
$ node readFileExample.js
After readFile.
File has been read.
There is nothing wrong about the use of a callback in this example. It’s readable, simple and gets the job done. However, managing callbacks tends to get tricky when you want to do something more complex. I’m going to extend the above example to show what I mean. Let’s say we need to send the file’s data to a couple of web services concurrently and then show the results after both calls finish. Here’s how that will look:
var FS = require('fs'),
    request = require('request');

function getResults(pathToFile, callback) {
    FS.readFile(pathToFile, 'utf8', function(err, data) {
        if (err) return callback(err);
        var response1, response2;

        request.post('http://service1.example.com?data=' + data), function(err, response, body) {
            if(err) return callback(err);
            response1 = response;
            next();
        }); 

        request.post('http://service2.example.com?data=' + data), function(err, response, body) {
            if(err) return callback(err);
            response2 = response;
            next();
        });         

        function next(){
            if(response1 && response2){
                callback(null, [response1, response2]);
            }
        }
    });
}
Do you see what I mean? We had to define a couple of variables (response1 and response2) to track the state of the two requests. The callbacks to both the service calls have to call the next() function, which will then check the state of the requests and print the combined results if both requests are done. The above code is not even complete! For instance, notice that we will be invoking the callback twice if both the service calls fail.
Callbacks also lead to another problem, which you should be already familiar with: callback hell. When you have to perform a number of actions in a specific sequence, nesting your callbacks leads to code like this:
asyncCall(function(err, data1){
    if(err) return callback(err);       
    anotherAsyncCall(function(err2, data2){
        if(err2) return calllback(err2);
        oneMoreAsyncCall(function(err3, data3){
            if(err3) return callback(err3);
            // are we done yet?
        });
    });
});

Let’s try that again with Promises

There are ways to make those callbacks look prettier, but that’s not the point of this article. Instead, I want to show you an alternate way of handling such tricky asynchronous operations, through the use of Promises.
A Promise is a placeholder object that represents the result of an async operation. This object will hold the information about the status of the async operation and will notify us when the async operation succeeds or fails. Enough theory, let’s see re-write the nested callback example above using Promises.
asyncCall()
.then(function(data1){
    // do something...
    return anotherAsyncCall();
})
.then(function(data2){
    // do something...  
    return oneMoreAsyncCall();    
})
.then(function(data3){
   // the third and final async response
})
.fail(function(err) {
   // handle any error resulting from any of the above calls    
})
.done();
The asyncCall(), instead of requiring a callback, returns us a Promise object. The subsequent then() calls on the Promise object also return promises, thus allowing us to chain a sequence of asynchronous operations. The fail() takes a function that will be invoked when any of the preceding asynchronous calls fail. Since an error automatically cascades down to a separate handler, we don’t have to check for them in each stage, like we have to do in the callback-based approach. As you can see, this type of chaining “flattens” the code and drastically improves readability.

Q – a neat library for using Promises

With that rather large introduction to Promises out of the way, let’s look at some practical ways of using Promises when working with Node.js. The first challenge you will face in adopting promises is that all of Node’s core libraries and most of the user-land libraries work using callbacks. Thankfully, there are some awesome libraries that allow us to convert these callback-based APIs to promises. I’m going to use the Q promise library to show how to get going with Promises in Node.js.
Let’s go back to the very first file reading example we saw and re-write that using Q:
// readFileUsingPromises.js
var FS = require('fs'),
    Q = require('q');

Q.nfcall(FS.readFile, "file.txt", "utf-8")
.then(function(data) {      
    console.log('File has been read:', data);
})
.fail(function(err) {
    console.error('Error received:', err);
})
.done();
Q has a handy nfcall() utility function that converts ‘readFile()’ to a promise. With this simple wrapper, you can start using Promises even if a library uses callbacks. Go ahead and try executing the above code (make sure you have the Q module installed by running npm install q first).
Q also makes it very easy to run async operations concurrently. Let’s re-write the earlier example involving service calls using Q. This time, I’m going to choose a real-world API, so you can try executing this code on your own. A file contains the name of a Github repository in a single line, like this:
// repos.txt
joyent/github
We want to read the name of a repository from a file and then call Github’s APIs to get the information about the repository’s collaborators and also fetch the latest commits from the repository. Here’s how that will look:
var FS = require('fs'),
    Q = require('q'),
    request = require('request');

function getResults(pathToFile) {   
    return Q.nfcall(FS.readFile, pathToFile, "utf-8")
    .then(function(repo) {
        var options = { headers: {'User-Agent': 'MyAgent'} }; // github requires user agent string
        return [Q.nfcall(request, 'https://api.github.com/repos/'+repo+'/collaborators', options),
                Q.nfcall(request, 'https://api.github.com/repos/'+repo+'/commits', options)];
    })
    .spread(function(collaboratorsRes, commitsRes) {        
        return [collaboratorsRes[1], commitsRes[1]];  // return the response body
    })
    .fail(function(err) {
        console.error(err)
        return err;
    });
}

// actual call
getResults('repos.txt').then(function(responses) {
    // do something with the responses
});
This example builds on top of the basic constructs of Promises that we have already seen, except for the use of the spread function. Notice how we make 2 concurrent API calls for fetching the collaborators and commits independently. These two calls are returned as an array of promises, which are then “spread” over their eventually fulfilled results. Slick isn’t it? We don’t have to track the state of the individual requests anymore, as we did with the callback based version.

What’s next?

With that, we have covered the basics of Promises and hopefully you got a glimpse of the powerful abstractions they provide us. You should definitely consider using them whenever you’re having trouble managing multiple, inter-dependent asynchronous calls. You will find that Promises definitely makes asynchronous operations easier to reason about. If you want to read more about Q, this guide will be really helpful.

Sunday, April 13, 2014

Why not use always android:configChanges=“keyboardHidden|orientation”?

Quick Background

By default, when certain key configuration changes happen on Android (a common example is an orientation change), Android fully restarts the running Activity to help it adjust to such changes.
When you define android:configChanges="keyboardHidden|orientation" in your AndroidManifest, you are telling Android: "Please don't do the default reset when the keyboard is pulled out, or the phone is rotated; I want to handle this myself. Yes, I know what I'm doing"
Is this a good thing? We shall soon see...

No worries?

One of the pros you start with is that there is:
no need to worry about your activity been rotated
In many cases, people mistakenly believe that when they have an error that is being generated by an orientation change ("rotation"), they can simply fix it by putting in android:configChanges="keyboardHidden|orientation".
However, android:configChanges="keyboardHidden|orientation" is nothing more than a bandaid. In truth, there are many ways a configuration change can be triggered. For example, if the user selects a new language (i.e. the locale has changed), your activity will be restarted in the same way it does by an orientation change. If you want you can view a list of all the different types of config changes.
Edit: More importantly, though, as hackbod points out in the comments, your activity will also be restarted when your app is in the background and Android decides to free up some memory by killing it. When the user comes back to your app, Android will attempt to restart the activity in the same way it does if there was some other configuration change. If you can't handle that - the user will not be happy...
In other words, using android:configChanges="keyboardHidden|orientation" is not a solution for your "worries." The right way is to code your activities so that they are happy with any restart Android throws at them. This is a good practice that will help you down the road, so get used to it.

So when should I use it?

As you mentioned there is a distinct advantage. Overwriting the default configuration change for a rotation by handling it yourself will speed things up. However, this speed does come with a price of convenience.
To put it simply, if you use the same layout for both portrait and landscape you're in good shape by doing the overwrite. Instead of a full-blown reload of the activity, the views will simply shift around to fill the remaining space.
However, if for some reason you use a different layout when the device is in landscape, the fact that Android reloads your Activity is good because it will then load up the correct layout. [If you use the override on such an Activity, and want to do some magical re-layout at runtime... well, good luck - it's far from simple]

Quick Summary

By all means, if android:configChanges="keyboardHidden|orientation" is right for you, then use it. But PLEASE be sure to test what happens when something changes, because an orientation change is not the only way a full Acitivity restart can be triggered.

Friday, September 20, 2013

Thursday, August 29, 2013

Android database java.lang.IllegalArgumentException: Invalid column ...

The column undoubtedly does exist in your database, but if you haven't added the column to a thing called the projection map, you'll get the "invalid column" error you're seeing.

So add the column being marked as missing into the projection map.

Saturday, August 25, 2012