mgolokhov / dodroid

May the knowledge be with you!
MIT License
20 stars 12 forks source link

No global #36

Closed shiraeeshi closed 8 years ago

shiraeeshi commented 8 years ago

Selecting tags and questions by tags. In order to limit the use of global data, the code is organized as follows:

The reason for all this is to make the code more modular. It's all good, but it's very slow, so I don't know what is the best solution. Need to google it.

shiraeeshi commented 8 years ago

I've found this answer useful: http://stackoverflow.com/a/4878259 I think that a map of weak references is a good solution.

shiraeeshi commented 8 years ago

I ended up starting TopicsActivity as usual with "startActivity" to speed up getting back to MainActivity, so we got some hybrid of "with-global" and "no-global" approaches.

mgolokhov commented 8 years ago

Some thoughts without digging in the current code. My first approach was to use serialization (parcelable), but with big objects packing and upacking still can be slow, so I switched to passing the unique ID of the object that resides in a global space. The global space is a singleton pattern (reusing application singleton mechanism), because we do not need different copies of data (need access to a shared resource from multiple parts). For now it's just like a cached in memory file (and it's smaller than a good quality photo).

As for DB, I modified the table with new compound IDs. The format is topic_test.number_question.number, I was thinking about pre-cooked by python database and at start the app would copy it to the internal storage. But you was faster =)

shiraeeshi commented 8 years ago

It's the first time I hear about python database in android, it would be interesting to see how it works.

mgolokhov commented 8 years ago

By pre-cooked I mean to create binary file in res/raw (when you build project) and than copy it by the app in the internal memory (so there is no overhead at start). Python uses sqlite3 as well.

mgolokhov commented 8 years ago

I use python script to import questions from google spreadsheet. And there is a task exportQuestions in the build.gradle

shiraeeshi commented 8 years ago

I misunderstood that part (I was a little surprised about python on android, lol).

mgolokhov commented 8 years ago

doIt -> push commit button

 5494-5494/doit.study.droid E/AndroidRuntime: FATAL EXCEPTION: main
                                                                Process: doit.study.droid, PID: 5494
                                                                android.database.sqlite.SQLiteException: no such table: stats (code 1): , while compiling: UPDATE stats SET right_count = 0 WHERE question_id = 8
                                                                    at android.database.sqlite.SQLiteConnection.nativePrepareStatement(Native Method)
                                                                    at android.database.sqlite.SQLiteConnection.acquirePreparedStatement(SQLiteConnection.java:887)
                                                                    at android.database.sqlite.SQLiteConnection.prepare(SQLiteConnection.java:498)
                                                                    at android.database.sqlite.SQLiteSession.prepare(SQLiteSession.java:588)
                                                                    at android.database.sqlite.SQLiteProgram.<init>(SQLiteProgram.java:58)
                                                                    at android.database.sqlite.SQLiteStatement.<init>(SQLiteStatement.java:31)
                                                                    at android.database.sqlite.SQLiteDatabase.executeSql(SQLiteDatabase.java:1674)
                                                                    at android.database.sqlite.SQLiteDatabase.execSQL(SQLiteDatabase.java:1605)
                                                                    at doit.study.droid.sqlite.helper.DatabaseHelper.addStats(DatabaseHelper.java:370)
                                                                    at doit.study.droid.QuestionsActivity$1.onAnswer(QuestionsActivity.java:42)
                                                                    at doit.study.droid.QuestionFragment.onClick(QuestionFragment.java:246)
                                                                    at android.view.View.performClick(View.java:5198)
                                                                    at android.view.View$PerformClick.run(View.java:21147)
                                                                    at android.os.Handler.handleCallback(Handler.java:739)
                                                                    at android.os.Handler.dispatchMessage(Handler.java:95)
                                                                    at android.os.Looper.loop(Looper.java:148)
                                                                    at android.app.ActivityThread.main(ActivityThread.java:5417)
                                                                    at java.lang.reflect.Method.invoke(Native Method)
                                                                    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
                                                                    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
mgolokhov commented 8 years ago

push setTopic

12-16 22:58:05.040 8085-8085/doit.study.droid E/AndroidRuntime: FATAL EXCEPTION: main
                                                                Process: doit.study.droid, PID: 8085
                                                                java.lang.IllegalStateException: Could not execute method for android:onClick
                                                                    at android.support.v7.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:275)
                                                                    at android.view.View.performClick(View.java:5198)
                                                                    at android.view.View$PerformClick.run(View.java:21147)
                                                                    at android.os.Handler.handleCallback(Handler.java:739)
                                                                    at android.os.Handler.dispatchMessage(Handler.java:95)
                                                                    at android.os.Looper.loop(Looper.java:148)
                                                                    at android.app.ActivityThread.main(ActivityThread.java:5417)
                                                                    at java.lang.reflect.Method.invoke(Native Method)
                                                                    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
                                                                    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
                                                                 Caused by: java.lang.reflect.InvocationTargetException
                                                                    at java.lang.reflect.Method.invoke(Native Method)
                                                                    at android.support.v7.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:270)
                                                                    at android.view.View.performClick(View.java:5198) 
                                                                    at android.view.View$PerformClick.run(View.java:21147) 
                                                                    at android.os.Handler.handleCallback(Handler.java:739) 
                                                                    at android.os.Handler.dispatchMessage(Handler.java:95) 
                                                                    at android.os.Looper.loop(Looper.java:148) 
                                                                    at android.app.ActivityThread.main(ActivityThread.java:5417) 
                                                                    at java.lang.reflect.Method.invoke(Native Method) 
                                                                    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726) 
                                                                    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616) 
                                                                 Caused by: android.database.sqlite.SQLiteException: no such table: stats (code 1): , while compiling: SELECT tag_id, COUNT(*) as count, SUM(score) as learned FROM questions_tags qt JOIN (SELECT question_id,CASE WHEN right_count < 3 THEN 0 ELSE 1 END score FROM stats) s ON qt.question_id=s.question_id GROUP BY qt.tag_id
                                                                    at android.database.sqlite.SQLiteConnection.nativePrepareStatement(Native Method)
                                                                    at android.database.sqlite.SQLiteConnection.acquirePreparedStatement(SQLiteConnection.java:887)
                                                                    at android.database.sqlite.SQLiteConnection.prepare(SQLiteConnection.java:498)
                                                                    at android.database.sqlite.SQLiteSession.prepare(SQLiteSession.java:588)
                                                                    at android.database.sqlite.SQLiteProgram.<init>(SQLiteProgram.java:58)
                                                                    at android.database.sqlite.SQLiteQuery.<init>(SQLiteQuery.java:37)
                                                                    at android.database.sqlite.SQLiteDirectCursorDriver.query(SQLiteDirectCursorDriver.java:44)
                                                                    at android.database.sqlite.SQLiteDatabase.rawQueryWithFactory(SQLiteDatabase.java:1316)
                                                                    at android.database.sqlite.SQLiteDatabase.rawQuery(SQLiteDatabase.java:1255)
                                                                    at doit.study.droid.sqlite.helper.DatabaseHelper.getTagStats(DatabaseHelper.java:305)
                                                                    at doit.study.droid.QuizData.getTagStats(QuizData.java:121)
                                                                    at doit.study.droid.MainActivity.setTopicButton(MainActivity.java:39)
                                                                    at java.lang.reflect.Method.invoke(Native Method) 
                                                                    at android.support.v7.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:270) 
                                                                    at android.view.View.performClick(View.java:5198) 
                                                                    at android.view.View$PerformClick.run(View.java:21147) 
                                                                    at android.os.Handler.handleCallback(Handler.java:739) 
                                                                    at android.os.Handler.dispatchMessage(Handler.java:95) 
                                                                    at android.os.Looper.loop(Looper.java:148) 
                                                                    at android.app.ActivityThread.main(ActivityThread.java:5417) 
                                                                    at java.lang.reflect.Method.invoke(Native Method) 
                                                                    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726) 
                                                                    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616) 
shiraeeshi commented 8 years ago

The meaning of those error messages is that an app haven't created the 'stats' table. The reason is that previous schema haven't had this table. DatabaseHelper checks the existence of a file named 'imported': if this file exists, then there's no need to perform schema creation. The solution is to clear the app's data so that 'imported' file doesn't exist anymore.

shiraeeshi commented 8 years ago

Can you share your thoughts about this branch, what prevents you from accepting this pull request?

mgolokhov commented 8 years ago

You wrote lots of good code, just need some discussion and polishing. I pushed the version with pre-cooked db.

Some ideas about the app architecture (maybe I'm wrong, so need your thoughts). We need serializable compound key to identify questions and statistics. By this key we get data from global space (which query from DB and caches info, sometimes drops cache). We have a read only questions table (a good candidate to be created at the build stage) and a writable statistics table.

shiraeeshi commented 8 years ago

There is a questionId column in question table, it uniquely identifies the question, and I think we can identify statistics by this id too.

mgolokhov commented 8 years ago

There is a questionId

If we want to have predefined test sets, we need a compound primary key. My suggestion is to use topic_num_id, test_num_id, question_num_id.

shiraeeshi commented 8 years ago

Even if we have predefined test sets, questionId uniquely identifies a question. Our goal is to identify a question, right?

mgolokhov commented 8 years ago

The compound key will uniquely identifies a question and statistics, check the sketch. The goal is also to have a predefined order in test sets.

mgolokhov commented 8 years ago

I deleted data holder, don't see any use of it. All queries create data locally and return references directly to the caller. Data will be cleaned with the caller. So for now we have a copy for every query. "Truth emerges from the clash of adverse ideas". I may be wrong.