Posted on 22 Mar 2013
When setting up a ContentProvider
, I didn’t really see any good explanation of how to use the UriMatcher
class. Here is a small example of it in a ContentProvider
.
public class MyProvider extends ContentProvider {
private static final int ORDERS = 1;
private static final int ORDERS_ID = 2;
private static final int ITEMS = 3;
private static final int ITEMS_ID = 4;
private static final UriMatcher mUriMatcher = new UriMatcher(
UriMatcher.NO_MATCH);
// The # sign will match numbers
static {
mUriMatcher.addURI(Constants.AUTHORITY, "orders", ORDERS);
mUriMatcher.addURI(Constants.AUTHORITY, "orders/#", ORDERS_ID);
mUriMatcher.addURI(Constants.AUTHORITY, "items", ITEMS);
mUriMatcher.addURI(Constants.AUTHORITY, "items/#", ITEMS_ID);
}
@Override
public int delete(Uri uri, String where, String[] whereArgs) {
int count = 0;
// Switch on the match, it will return the integer you passed in previously
switch (mUriMatcher.match(uri)) {
case ORDERS:
count = database.getWritableDatabase().delete("orders", where, whereArgs);
getContext().getContentResolver().notifyChange(uri, null);
case ITEMS:
count = database.getWritableDatabase().delete("items", where, whereArgs);
getContext().getContentResolver().notifyChange(uri, null);
}
return count;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
String defaultOrder = DatabaseHelper.DEFAULT_SORT_ORDER; // "id"
switch (uriMatcher.match(uri)) {
case ORDERS:
case ORDERS_ID:
qb.setTables("orders");
defaultOrder = DatabaseHelper.DEFAULT_SORT_ORDER_ORDERS; // "date DESC"
break;
case ITEMS:
case ITEMS_ID:
qb.setTables("items");
break;
}
String orderBy;
if (TextUtils.isEmpty(sortOrder)) {
orderBy = defaultOrder;
} else {
orderBy = sortOrder;
}
Cursor cursor = qb.query(database.getReadableDatabase(), projection,
selection, selectionArgs, null, null, orderBy);
cursor.setNotificationUri(getContext().getContentResolver(), uri);
return cursor;
}
}
Posted on 15 Mar 2013
I started on a new Android project that pulls JSON form a web service. One of the end points returns and array of objects and I wanted to parse them into Java objects with Jackson. It wasn’t very obvious and I didn’t see this listed anywhere so I figured I’d share it.
Replace MyClass
with the class you want to deserialize to.
ObjectMapper mapper = new ObjectMapper();
mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
TypeFactory typeFactory = TypeFactory.defaultInstance();
List<MyClass> my_classes = mapper.readValue(responseJson, typeFactory
.constructCollectionType(ArrayList.class, MyClass.class));
Posted on 13 Feb 2013
I started up on android again and started using the SQLite database for the first time. Coming from rails I really wanted to have some kind of migrations for the database. I googled around and didn’t really see anything available so I made up a simple class that solves my problem.
Note that this hasn’t been used outside of my test app. I also have only created one migration with it so far, but I like how it went. An abstract class might also not be the best way to go, but I haven’t used it since college and wanted to try it out again.
src/org/oestrich/myapp/migrations/Migration.java
package org.oestrich.myapp.migrations;
import android.database.sqlite.SQLiteDatabase;
public abstract class Migration {
private SQLiteDatabase mDatabase;
public Migration(SQLiteDatabase database) {
mDatabase = database;
}
public abstract void up();
public abstract void down();
public SQLiteDatabase getDatabase() {
return mDatabase;
}
}
src/org/oestrich/myapp/migrations/InitialDatabase.java
package org.oestrich.myapp.migrations;
import android.database.sqlite.SQLiteDatabase;
public class InitialDatabase extends Migration {
public InitialDatabase(SQLiteDatabase database) {
super(database);
}
@Override
public void up() {
getDatabase().execSQL(
"CREATE TABLE my_model (_id INTEGER PRIMARY KEY AUTOINCREMENT);");
}
@Override
public void down() {
getDatabase().execSQL("DROP TABLE my_model;");
}
}
src/org/oestrich/myapp/database_helper.rb
package org.oestrich.myapp;
public class DatabaseHelper extends SQLiteOpenHelper {
// ...
@Override
public void onCreate(SQLiteDatabase db) {
try {
db.beginTransaction();
new InitialDatabase(db).up();
// Add more migrations here
db.setTransactionSuccessful();
} finally {
db.endTransaction();
}
}
// ...
}
Image Source
Posted on 09 Feb 2013
This post was originally published on the
SmartLogic Blog.
When you need to connect to multiple different APIs, it can take a long time to manage your OAuth workflow for each third-party app. On a recent app development project, I was getting really agitated using cURL for every step in the process while working on pulling in data from multiple apps. So I decided to do something about it. I’m a programmer, damn it.
While I don’t have a magic solution, I created a Sinatra OAuth proxy app that works with Harvest. This sped up development for connecting with Harvest, and with small changes, the same code can also work for other applications. For example, I tested it out on Foursquare and the same code mostly worked.
This is the code I used to speed up OAuth and inspect the third party app’s API.
gist
server.rb
require 'sinatra'
require 'json'
require 'faraday'
require 'faraday_middleware'
enable :sessions
IDENTIFIER = "YOUR_IDENTIFIER"
SECRET = "YOUR_SECRET"
REDIRECT_URI = "http://localhost:3000/auth"
AUTH_URL = "https://api.harvestapp.com/oauth2/authorize"
TOKEN_URL = "https://api.harvestapp.com/oauth2/token"
BASE_API_URL = "https://api.harvestapp.com/"
# Middlware to insert "Accept: application/json" header
class JsonMiddleware < Faraday::Middleware
def call(env)
env[:request_headers]["Accept"] = "application/json"
@app.call(env)
end
end
# Redirect to the API to start the OAuth handshake
# http://www.getharvest.com/api/authentication-oauth2
# http://tools.ietf.org/html/draft-ietf-oauth-v2-22#section-4.1
get "/" do
query_string = Rack::Utils.build_query({
:client_id => IDENTIFIER,
:redirect_uri => REDIRECT_URI,
:state => "optional-csrf-token",
:response_type => "code"
})
redirect "#{AUTH_URL}?#{query_string}"
end
# Harvest will redirect back here with the OAuth code you
# use to get the access token.
get "/auth" do
query_string = Rack::Utils.build_query({
:code => params[:code],
:client_id => IDENTIFIER,
:client_secret => SECRET,
:redirect_uri => REDIRECT_URI,
:grant_type => "authorization_code"
})
response = Faraday.post("#{TOKEN_URL}?#{query_string}")
session[:token] = JSON.parse(response.body)["access_token"]
redirect "/token"
end
# Removes favicon warnings
get "/favicon.ico" do
end
# Display your access token
get "/token" do
session[:token]
end
# Proxy everything after / to Harvest
#
# http://localhost:3000/projects/1/entries?from=2013-01-10&to=2013-01-14
# => https://api.harvest.com/projects/1/entries?from=2013-01-10&to=2013-01-14
get "/*" do
headers "Content-Type" => "text/plain"
params.delete("captures")
url = "/#{params.delete("splat").join}?"
url += Rack::Utils.build_query(params)
client = Faraday.new(:url => BASE_API_URL) do |faraday|
faraday.request :url_encoded
faraday.request :oauth2, session[:token]
faraday.use JsonMiddleware
faraday.adapter Faraday.default_adapter
end
response_body = client.get(url).body
JSON.pretty_generate(JSON.parse(response_body))
end
How do you handle OAuth without cURLin’ all day long? Comment and let us know.
For more like this, follow @SmartLogic and @ericoestrich on Twitter.
Image Source
Posted on 01 Feb 2013
My co-worker, Sam Goldman, a while back showed me this useful little IRB trick in order to get out how long a method takes. I used it pretty heavily recently with doing a call that hits the network.
It’s really easy to set up, just add the following to your .irbrc
file.
~/.irbrc
def tic
@tic = Time.now
end
def toc
"#{Time.now - @tic} seconds"
end
Once that’s set up you can call it surrouding the method you want to time.
irb(main):003:0> tic; puts "Hello"; toc
Hello
#=> "3.0686e-05 seconds"
irb(main):004:0> tic; sleep 2; toc
#=> "2.000082375 seconds"
It’s also in my dotfiles repo on github.