开发者

ORMLite for Android: Bind DAO with Roboguice

I'm just trying to setup my Android Project with ORMLite. I'm using Roboguice for DI. Now my question is, whether anyone here can help getting those working together.

I've setup my helper class extending OrmLiteSqliteOpenHelper. Now I'm wondering how to inject the correct DAO class.

A general best practice would be fantastic. Since using OrmLiteBaseActivity shouldn't really apply, since that should be handled开发者_如何学运维 by Roboguice. The question is just: How?

I'd very much appreciate any help, your experience, best practice etc.


If you're extending from OrmLiteBaseActivity, you won't be able to extend from RoboActivity. That's fine, just call the following (assuming roboguice 1.1) to perform injection on your non-roboactivity activity:

((InjectorProvider)getApplicationContext()).getInjector().injectMembers(this)

Once you have that, you can perform injection of your dao objects.

To inject your DAOs, I suggest you follow the pattern established by SystemServiceProvider (class and bindings). So implement a DaoProvider like the following:

class DaoProvider<T> implements Provider<T> {
    protected ConnectionSource conn;
    protected Class<T> clazz;

    public DaoProvider( ConnectionSource conn, Class<T> clazz ) {
        this.conn = conn;
        this.clazz = clazz;
    }

    @Override
    public T get() {
        return DaoManager.createDao( conn, clazz  );
    }
}

Supply the bindings. You'll need to do one for each DAO type you want to inject:

bind(MyDaoObjectType.class).toProvider(
      new DaoProvider<MyDaoObjectType>(conn,MyDaoObjectType.class));

Then you can inject it into your activity or anywhere else:

@Inject MyDaoObjectType myDaoObjectType;


I had this same problem and ended up creating an OrmLiteActivityListener, to listen to my RoboActivity and handle the events it raises.

public class RoboOrmActivityBase<H extends IOrmLiteSqliteOpenHelper> extends RoboActivity {
@Inject RoboOrmLiteActivityListener<H> OrmActivityListener;

/*
 * Get a helper for this action.
 */
public H getHelper() {
    return OrmActivityListener.getHelper();
}

/**
 * Get a connection source for this action.
 */
public ConnectionSource getConnectionSource() {
    return OrmActivityListener.getHelper().getConnectionSource();
}
}

RoboOrmLiteActivityListener class was derived from the OrmLiteActivityBase class. I removed its inheritance and made it listen instead.

public class RoboOrmLiteActivityListener<H extends IOrmLiteSqliteOpenHelper> {
private volatile H helper;
private volatile boolean created = false;
private volatile boolean destroyed = false;

OrmLiteSqliteOpenHelperProvider databaseHelperProvider;

@Inject
public RoboOrmLiteActivityListener(OrmLiteSqliteOpenHelperProvider databaseHelperProvider) {
    this.databaseHelperProvider = databaseHelperProvider;
}

/**
 * Get a helper for this action.
 */
public H getHelper() {
    if (helper == null) {
        if (!created) {
            throw new IllegalStateException("A call has not been made to onCreate() yet so the helper is null");
        } else if (destroyed) {
            throw new IllegalStateException(
                    "A call to onDestroy has already been made and the helper cannot be used after that point");
        } else {
            throw new IllegalStateException("Helper is null for some unknown reason");
        }
    } else {
        return helper;
    }
}

/**
 * Get a connection source for this action.
 */
public ConnectionSource getConnectionSource() {
    return getHelper().getConnectionSource();
}

// As you might expect, some events can have parameters.  The OnCreate event
// has the savedInstanceState parameter that Android passes to onCreate(Bundle)   
public void onCreate(@Observes OnCreateEvent onCreate) {
    //Ln.d("onCreate savedInstanceState is %s", onCreate.getSavedInstanceState())
    if (helper == null) {
        helper = getHelperInternal();
        created = true;
    }
}

public void onDestroy(@Observes OnDestroyEvent onDestroy) {
    releaseHelper(helper);
    destroyed = true;
}

/**
 * This is called internally by the class to populate the helper object instance. This should not be called directly
 * by client code unless you know what you are doing. Use {@link #getHelper()} to get a helper instance. If you are
 * managing your own helper creation, override this method to supply this activity with a helper instance.
 * 
 * <p>
 * <b> NOTE: </b> If you override this method, you most likely will need to override the
 * {@link #releaseHelper(OrmLiteSqliteOpenHelper)} method as well.
 * </p>
 */
private H getHelperInternal() {
    @SuppressWarnings("unchecked")
    H newHelper = (H) databaseHelperProvider.get();
    return newHelper;
}

/**
 * Release the helper instance created in {@link #getHelperInternal(Context)}. You most likely will not need to call
 * this directly since {@link #onDestroy()} does it for you.
 * 
 * <p>
 * <b> NOTE: </b> If you override this method, you most likely will need to override the
 * {@link #getHelperInternal(Context)} method as well.
 * </p>
 */
private void releaseHelper(H helper) {
    OpenHelperManager.releaseHelper();
    helper = null;
}
}

Then I have a DatabaseHelperProvider which provides my Helper that extends from OrmLiteSqliteOpenHelper. This provider manually performs injection on my helper after retrieving it from OpenHelperManager.

public class OrmLiteSqliteOpenHelperProvider implements Provider<OrmLiteSqliteOpenHelper> {
  private final Context context;
  private final Injector injector;

  @Inject
  public OrmLiteSqliteOpenHelperProvider(Context context, Injector injector) {
      this.context=context;
      this.injector=injector;
  }
  public OrmLiteSqliteOpenHelper get() {
      //The OpenHelperManager built the DatabaseHelper, not us.  So we need to guice it up manually.  
      //Guice normally does its injections when it does its constructions. 
    OrmLiteSqliteOpenHelper dbhelp = OpenHelperManager.getHelper(context);
      injector.injectMembers(dbhelp);
    return dbhelp;
  }
}

I also have an interface called IOrmLiteSqliteOpenHelper, which contains members extracted from OrmLiteSqliteOpenHelper. Then when I build my interface (IDatabaseHelper) for my helper which derives from OrmLiteSqliteOpenHelper I can extend from IOrmLiteSqliteOpenHelper.

Then to bind in my Module I have

static {
    OpenHelperManager.setOpenHelperClass(DatabaseHelper.class);
}

and

@SuppressWarnings("unchecked")
private void bindDataHelperProvider() {
    bind(IDatabaseHelper.class)
    .toProvider((Class<? extends Provider<? extends IDatabaseHelper>>) OrmLiteSqliteOpenHelperProvider.class);
}

Then my Activity has everything for RoboGuice and Ormlite handled entirely in the baseclass and looks like this:

public class MyActivity extends RoboOrmActivityBase<IDatabaseHelper> {

    List<IMyEntity> lis;

@Override
protected void onCreate(Bundle savedInstanceState) {
    // TODO Auto-generated method stub
    super.onCreate(savedInstanceState);
    setContentView(R.layout.routine);

    try {
        Dao<IMyEntity,Integer> myDao = getHelper().getMyDao();
        lis = myDao.queryForAll();


This is not a best practice just the solution I've come up with, that works.

Please leave notes for improvements.

I'm using a UserLocation entity as an example here To bind SqliteOpenHelper and Dao as singletons, I added this to the Module configuration:

bind(new TypeLiteral<SqliteOpenHelper>(){}).toProvider(OrmLiteSqliteOpenHelperProvider.class).in(Singleton.class);
bind(new TypeLiteral<Dao<UserLocation, Integer>>(){}).toProvider(DaoUserLocationProvider.class).in(Singleton.class);

The OrmLiteSqliteOpenHelperProvider looks like this:

public class OrmLiteSqliteOpenHelperProvider implements Provider<SqliteOpenHelper>
{
    @Inject Context context;

    @Override
    public SqliteOpenHelper get() {
        return (SqliteOpenHelper) OpenHelperManager.getHelper(context);
    }
}

The DaoUserLocationProvider looks like this:

public class DaoUserLocationProvider implements Provider<Dao<UserLocation, Integer>>
{
    @Inject SqliteOpenHelper sqliteOpenHelper;

    @Override
    public Dao<UserLocation, Integer> get() {
        try {
            return sqliteOpenHelper.getUserLocationDao();
        } catch (SQLException e) {
            Ln.e(e);
        }
        return null;
    }
}

Now I can just inject the Dao liek this:

@Inject private Dao<UserLocation, Integer> userLocationDao;

That way I can keep using the roboguice activity and the SqliteOpenHelper is kept as a singleton by roboguice.

But the question on destroying / releasing remains. I'm tempted to just copy paste the contents of the OrmLiteBaseActivity and extend RoboActivity. Any opinions?


http://abdennour-insat.blogspot.com/2012/10/using-ormlite-for-sqlite-with-android.html

you can follow this tuto .

I used a specific software architecture to avoid multiple inheritance I say at beginning of tuto:

The Class which uses ormlite extends

OrmliteActivity .But when you use GreenDroid

,Activities shuld extend GDActivity .

Unfortunately, Java does not support multiple

inheritance, ie, a JAVA class can extend only one

superclass maximum.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜