clojure-android / neko

The Clojure/Android Toolkit
Other
297 stars 36 forks source link

Question: use SQLite in MyApplication.onCreate() #22

Closed sakuraiyuta closed 10 years ago

sakuraiyuta commented 10 years ago

Env:

I want to execute initialization logic in MyApplication.onCreate().

I wrote clojure.lang.Var.invoke() in onCreate() like this:

  public void onCreate() {
    Log.v(TAG,"--- onCreate() in ---");

    Symbol APPLICATION = Symbol.intern("myapp.application");
    REQUIRE.invoke(APPLICATION);

    Var ON_CREATE = RT.var("myapp.application", "app-on-create");
    ON_CREATE.invoke(MyApplication.this);
  }

and got error: java.lang.ClassCastException: clojure.lang.Var$Unbound cannot be cast to clojure.lang.Var

app-on-create calls neko.data.sqlite/get-database, and it calls neko.data.sqlite/create-helper function. But neko.context/context is unbound at that time. It causes the error.

So, I fixed app-on-create like this:

(defn app-on-create
  [this]
  (do
    (if (not (bound? #'neko.context/context))
      (alter-var-root #'neko.context/context (constantly this)))
    ; and my code...

This code works...but the solution is correct?

alexander-yakushev commented 10 years ago

Well, yes, your solution is correct. Let me tell the backstory behind initialization process.

At first there was a macro called defapplication that allowed to write there your Application logic. Then, with introduction of SplashActivity I had to give it up, because Application class gets loaded first, and defining it from Clojure side enforces to load whole Clojure runtime right away (before SplashActivity gets to be shown). This defeated the purpose of having a splash. So I had to move Neko initialization code from Application.onCreate into the first loaded Activity.onCreate. In your case, you try to use Neko facilities before this initialization code is called, which results in error.

You can leave your code as is, or you better put (neko.init/init this) call at the beginning of your app-on-create function. But then once again be aware that you won't be able to use SplashActivity if you call Clojure code in your Application.onCreate. SplashActivity will be shown, but long after all Clojure runtime is loaded. If you don't want it to be like that, then move your initialization code into :on-create of an activity that is launched right after SplashActivity.

sakuraiyuta commented 10 years ago

Thanks for details! I got a reason why defapplication was deprecated. I felt similarly that loading Clojure gets long time at 2.0.0-beta* and shows nothing, and users feel it uneasy. You fixed the problem, very good.

Unfortunately, my initialization code is used by many Activities and BroadcastReceivers, so your suggestion move initialization code into activity :on-create goes against me... However I become aware of the backstory, problem and suggestions you wrote.