2013年8月31日土曜日

あれ?すっとばした

ContentResolver resolver = this.getActivity().getContentResolver();
これやらないと始まらんよね。

ContentResolverってなんぞ?というとandroid内のプロセス間通信を制御するものらしい。
「らしい」というのはまだあんまり調べてないから(ぁ

調べます。

SDKのAPI GuidesのProcesses and Threadの章によると

Similarly, a content provider can receive data requests that originate in other processes. Although the ContentResolver and ContentProvider classes hide the details of how the interprocess communication is managed, ContentProvider methods that respond to those requests—the methods query(), insert(), delete(), update(), and getType()—are called from a pool of threads in the content provider's process, not the UI thread for the process. Because these methods might be called from any number of threads at the same time, they too must be implemented to be thread-safe.


ContentProvider methods that respond to those requests—the methods query(), insert(), delete(), update(), and getType()—are called from a pool of threads in the content provider's process, not the UI thread for the process

おおまかに訳すと
ContentProviderは呼ばれる。content provider'sのプロセスの中のスレッドプールから。UIスレッドではなく。

日本語らしく言うと、コンテンツプロバイダはUIスレッドからじゃなくてcontentのプロバイダ達がいるところのプロセスの中のスレッドプールから呼ばれてんじゃごらぁ。

まともに訳すと
コンテンツプロバイダはcontentプロバイダー達のいるプロセス中で発生しているスレッドプールで呼ばれています。

つまり、そもそも発生しているプロセス自体が違うってことですね。
だから「UIスレッド」で呼んでも問題ない。
「UIスレッド」だろうがおれおれスレッドだろうが「Appのプロセス」に結果が返される。

えーまじでー。ソースは?ってかどこで受けとってんのよその結果は。
UIスレッド上で結果を使ってあーだこーだできるじゃん。
ってことはスレッドを何らかの形で捕まえてて、そのスレッド中に投げてんじゃないのー?

スレッドを発生させているのはわかった。で、結果はどこで渡してるの?

    /**
     * After being instantiated, this is called to tell the content provider
     * about itself.
     *
     * @param context The context this provider is running in
     * @param info Registered information about this content provider
     */
    public void attachInfo(Context context, ProviderInfo info) {
        /*
         * We may be using AsyncTask from binder threads.  Make it init here
         * so its static handler is on the main thread.
         */
        AsyncTask.init();

        /*
         * Only allow it to be set once, so after the content service gives
         * this to us clients can't change it.
         */
        if (mContext == null) {
            mContext = context;
            mMyUid = Process.myUid();
            if (info != null) {
                setReadPermission(info.readPermission);
                setWritePermission(info.writePermission);
                setPathPermissions(info.pathPermissions);
                mExported = info.exported;
            }
            ContentProvider.this.onCreate();
        }
    }

sdkのソースをちらちら

ContentProviderをいれたアプリケーションで、
ふつーのUIスレッド上でContentResolver.insertとかできる。
なんだろね、これ。
予想ではUIスレッドからHandlerでLooperでも呼んでるのか?

というわけでContentResolverくんのソース。

public final Uri insert(Uri url, ContentValues values)
    {
        IContentProvider provider = acquireProvider(url);
        if (provider == null) {
            throw new IllegalArgumentException("Unknown URL " + url);
        }
        try {
            long startTime = SystemClock.uptimeMillis();
            Uri createdRow = provider.insert(url, values);
            long durationMillis = SystemClock.uptimeMillis() - startTime;
            maybeLogUpdateToEventLog(durationMillis, url, "insert", null /* where */);
            return createdRow;
        } catch (RemoteException e) {
            // Arbitrary and not worth documenting, as Activity
            // Manager will kill this process shortly anyway.
            return null;
        } finally {
            releaseProvider(provider);
        }
    }

IContentProviderというのは、調べてみるとinterfaceだった。
で、誰がインプリメンツして応答してるの?

あった。ContentProviderNativeくん。
abstract public class ContentProviderNative extends Binder implements IContentProvider
さらに中のfinalクラス
final class ContentProviderProxy implements IContentProvider

で、このNativeくんはどこで使われてるのかというと、ContentProviderクラス。
class Transport extends ContentProviderNative
この中でabstructのInsertを呼ぶようになっている。

続く
                                            かもしれない。

そういえば

初めてAndroidのSqlite触ったときにびっくりしたなぁ。

ロールバックないんすかw
外部キーないんすかw

逆の立場、sqliteから他のDBだと、
ロールバック?あぁ、キャベツで巻かれてるry
何で結合できねぇんだごらぁ。
制約とかめんどくせー
関数超便利

となるんだろうな(遠い目

googleから新しいNexus7が発売されました

というわけで、発売されましたね。

相変わらずSDカードスロットなしっすかー。

googleとしては、外部メモリを歓迎してないのかなぁ。
作成コストが削れるからなのか、システム的に歓迎していないのか気になるところ。

データを組んでて思ったこと

SQLiteを使用する場合です。
タグを入れるテーブルとコストを入れるテーブルの関係性をどうやろうか考えました。

t_cost
_id
_value
_timestamp
_tagname

m_tag
_id
_name
_timestamp
_count

DBのアップグレードでカラムを加えるような場合、
前のデータ+デフォルト値を加えた新しいカラムをテーブルにインサートという感じにしたい。
手間を考えると、copyして古いのDropして新しいのをrenameする形が良さそうだ。
この時、_idを外部キー扱いとすると、_idの値が変わったときに連鎖updateが必要になる。
SQLiteだとシステム的にそういった仕組みがないので、自前でこつこつupdateしないといけない。
これはめんどくさい(ぁ


mapタイプのデータ群でいいや。←手抜き感
アップグレード時の手間を減らしたい。←怠惰
copyして古いのDropして新しいのをrenameすればいいよねー。←簡単
だから関係性はnameでやろう。_idはがんがん変わるし。←言い訳
連鎖アップデートを手動でとかめんどくさいですしおすし。←本音
重複しないようにロジック組めばいいよね(震え声

※良い子のみんなは「_idの値を持つ_idとは別のフィールド」を外部キー扱いして関係のあるテーブルの値を更新するように。

他のDBだったら外部キー制約あるから、ルールに則って連鎖アップデートしてね。

以下蛇足。
でかい規模のサーバにアクセスするシステムってどうなってるんだろう。
例えば、戸籍とか新幹線の予約システムとか。

サーバ系は触ったことはもちろん見たこともないのでどういう処理してるのか一度見てみたい。
サーバに投げて終了の方しかやったことねーんす。今度勉強してみよう。

新幹線の予約システムはマルス(MARS)と読むらしいです。
以下、マルス(システム)より抜粋
元々は"Magnetic electronic Automatic seat Reservation System"(磁気的電気的自動座席予約装置)の略とされていたが、現在では"Multi Access seat Reservation System"(旅客販売総合システム)の略となっている。
抜粋以上。

2013年8月29日木曜日

MMD杯のマイリス投票がぼちぼち締め切りです

締め切りは9月2日(月)21時です。

テーマが8本あって、相変わらずのごった煮でございます。

大会のサブタイトルが「REBIRTH」ということもあり、
PV系に力を入れてる方が目立つなという印象です。
それなりに見たつもりですが、他の人のおすすめからマイリスしたりしてます。

どんな閉会式になるか楽しみですね。

2013年8月27日火曜日

マルチバージョニングはやっぱりおかしい

どこに違いがあるかわからない。
0..0.0刻みでもどこに違いがあるのかわからない。
対処療法が確実とは言え、
テスト状態でとりあえず出して反応を見るのがプロモーションとは言え、
やはりマルチバージョニングは危険すぎる。
surportpackageがあるとは言え、その中にも色々違いがあったりするし。
同じようには絶対に扱えない。

利用者がエラーを寛容できるのが先か、
企業がマルチバージョニングをやめるのが先か、
利用者がベータ版でのプロモーションを認めなくなるのが先か。

とは言え、どこにエラーがあるかわかりませんは口から出せない。
やってみないとわかりませんなエラーはほんと見つけるのに苦労する。

現実的な対処がUserからの
「強制終了が頻発します。最悪です。アンインストールします。」
を真摯に受け止めて、対応をできるだけ早くすることぐらいしかない。

レポート送ってください。お願いします。

googleさん、何か声明なり注意書きなり出してください(泣)