KotlinでDatabaseException: mypackage.Item does not define a no-argument constructor.

状況

Android Studio: 3.0.1
Kotlin: 1.2.10
firebase-database: 11.8.0

現象

Kotlinの勉強がてらFirebaseのRealTime Databaseでデータを取得しようとしたらこんなエラーが出た。

com.google.firebase.database.DatabaseException: Class my.com.package.Item does not define a no-argument constructor. If you are using ProGuard, make sure these constructors are not stripped.
    at com.google.android.gms.internal.zzelx.zze(Unknown Source)
    at com.google.android.gms.internal.zzelw.zzb(Unknown Source)
    at com.google.android.gms.internal.zzelw.zza(Unknown Source)
    at com.google.android.gms.internal.zzelw.zza(Unknown Source)
    at com.google.android.gms.internal.zzelw.zza(Unknown Source)
    at com.google.firebase.database.DataSnapshot.getValue(Unknown Source)
    at my.package.MyListFragment$fetchData$1.onDataChange(MyListFragment.kt:83)
    at com.google.android.gms.internal.zzegf.zza(Unknown Source)
    at com.google.android.gms.internal.zzeia.zzbyc(Unknown Source)
    at com.google.android.gms.internal.zzeig.run(Unknown Source)
    at android.os.Handler.handleCallback(Handler.java:751)
    at android.os.Handler.dispatchMessage(Handler.java:95)
    at android.os.Looper.loop(Looper.java:154)
    at android.app.ActivityThread.main(ActivityThread.java:6119)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)

※パッケージやクラス名は変更している

firebaseからの取得コードはこれ

    /**
     * 一覧に表示するデータを取得
     */
    private fun fetchData() {
        // Write a message to the database
        val database = FirebaseDatabase.getInstance()
        val myRef = database.getReference(mPath)

        // Read from the database
        myRef.addValueEventListener(object : ValueEventListener {
            override fun onDataChange(dataSnapshot: DataSnapshot) {
                // This method is called once with the initial value and again
                // whenever data at this location is updated.
                val items: List<Item>? = dataSnapshot.getValue(object : GenericTypeIndicator<ArrayList<Item>>() {})
                Log.d(TAG, "Value is: " + items)
                recyclerView!!.adapter = MyRecyclerViewAdapter(items!!, mListener)
            }

            override fun onCancelled(error: DatabaseError) {
                // Failed to read value
                Log.w(TAG, "Failed to read value.", error.toException())
            }
        })
    }

エラーメッセージのみ抜き出すと
Class my.com.package.Item does not define a no-argument constructor. If you are using ProGuard, make sure these constructors are not stripped.

日本語に訳すと
クラスmy.com.package.Itemは、引数のないコンストラクタを定義しません。 ProGuardを使用している場合は、これらのコンストラクタが削除されていないことを確認してください。

解決方法

引数のないコンストラクタ…
もしかしてモデルとして作ったItemクラスがおかしいのか?
と思い見てみると、ああ、Boolean型のisVideoに初期値を定義していなかった。

// 修正前
data class Item(
        val caption: String = "",
        val code: String = "",
        val data: String = "",
        val isVideo: Boolean,  // ←こいつの初期値がないのが原因
        val thumbnail: String = ""
)

とりあえずfalseでも突っ込んでおく

// 修正前
data class Item(
        val caption: String = "",
        val code: String = "",
        val data: String = "",
        val isVideo: Boolean = false,  //初期値falseを追加
        val thumbnail: String = ""
)

ビルドして動作させると...動いた!

モデルのコンストラクタに初期値を忘れるとこうなるんだな、勉強になった。

Android Studioで「Failed to resolve: com.android.support:appcompat-v7:27.+」

現象

久しぶりにAndroid Studio2.3.3を起動し、New Projectを作って初回Gradle Syncが実行されると、以下のメッセージが表示された。

Error:(26, 13) Failed to resolve: com.android.support:appcompat-v7:27.+
Install Repository and sync project
Show in File
Show in Project Structure dialog

ああ、sdkマネージャーに27が入ってないのね、と思いインストールするがエラーは直らず。

解決方法

プロジェクトルートのbuild.gradleを開いて+の行を追加する。

// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
    repositories {
        jcenter()

    }
    dependencies {
        classpath 'com.android.tools.build:gradle:2.3.3'

        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

allprojects {
    repositories {
        jcenter()
+        maven {
+            url 'https://maven.google.com/'
+            name 'Google'
+        }
    }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}

再度syncするとエラーが消えた、解決!

前からNew Projectでこんなの手で入門する必要あったっけ?

6歳にプログラミングを教えて失敗した話

microbitをなんとか有効的に使いたい & 前からプログラミング教育に興味があったので、隣家の家族に協力してもらい、男の子(6歳)にプログラミングをマンツーマンで教えてみた。

使ったもの

  • Mac Book Air
  • USBマウス
  • microbit
  • USBケーブル(タイプB)

生徒(1人)

  • 隣人の6歳男子
  • ゲーム大好き
  • プログラミングに興味があるかは不明(多分ない)
  • 母親はプログラミング教育にかなり興味あり

授業について

  • 授業会場は筆者の家のリビング
  • 授業時間は30分
  • microbitサイトのビジュアルプログラミングで動作を組み立てるやり方
  • 筆者の家なので妻と娘(1歳)がリビングで自由にしてる
  • 生徒の親は不参加

やったこと

  • プログラムとはなにか?を軽く説明
  • Microbitで起動時にLEDで好きなマークを表示
  • microbitのAボタン押下でLEDにお化けを表示(if的な処理)
  • microbitのBボタン押下でLEDにウンチを表示(if的な処理)

結果

  • 「ゲームはプログラムで作られている」と説明すると「え?ほんと?」と興味を示す
  • 最初にmicrobitでLEDを表示させた後、飽きたのか席から逃亡して娘のオモチャで遊び始める
  • なんとか席に戻してもすぐ、逃亡して授業がなかなか進まなかった
  • なんとか授業は完遂したがプログラミングとは何か的なことは10%も伝わってない
  • 俺「なんとか終わったね、お疲れ様!」 男の子「そんな事より外で遊ぼうよー」

反省点

マウスが操作できる前提だった

  • まずこれが間違い
  • マウスに慣れてない子だった
  • クリックが狙ったところにできず苦労していた
  • 今時の若い子はPCを使えると思ったが、時代はスマフォが主流らしい

microbitに興味を示さなかった

  • 6歳の男の子なら光る機械に興味を持つだろうと思ったが、これが間違い
  • LEDを1回表示させたら飽きた
  • Scratchのようにキャラクターを動かすやり方の方がいい
  • microbitを使うならもう少し年齢が上じゃないとダメ

授業机にコタツはNG

  • コタツだと簡単に立ち上がって席から離脱できてしまう
  • 机+椅子で多少逃げにくくすべき

授業部屋はテレビがON & オモチャがあってはならない

  • 娘がテレビを見ていたので男の子もついつい見てしまう
  • 娘のオモチャが気になってPC画面を見てくれない
  • むしろ授業PCよりもテレビとオモチャを多く見ていた
  • 授業するなら誘惑するモノを同じ部屋に置いてはならない(当たり前)

男の子の母には成果物としてmicrobitの完成物を見せ、「え?これを作ったんですか?」的な驚きコメントを頂いた。
が、結果としてプログラミング学習できたかは怪しく、「子供にモノを教えて静かに聞いてもらえるって難しいですね」と伝えると笑ってくれた。

今回の失敗で得たもの

環境作りは超大事!

  • 家でやるならPC以外に何もない部屋を用意しなければならない

絵で説明すること

  • 口だけで説明しても男の子は全くイメージできてなかった
  • 下手な絵でもいいから紙にでも書いて説明するべき

年齢に合わせた学習方法を選ぶこと

  • 光るデバイスに飛びつくのは少数派らしい
  • 子供が興味をもつキャラクターものにするべき

次回に盛り込みたいこと

  • 生徒数を複数にしたい(競争させて集中させよう作戦)
  • ラズパイ3でScratchでの授業を試したい
  • microbitを使うなら音を出す授業にしたい(音が出せるの?と興味を持っていた)
  • バイスを使わずCode Monkeyのようなサイトでの授業もやってみたい

The following classes could not be instantiated:- android.support.v7.widget.AppCompatTextView

現象

Android Studio 2.3.3でPreview画面に何やらerrorが出とる。

f:id:banbara:20171221185836p:plain

The following classes could not be instantiated:- android.support.v7.widget.AppCompatTextView

java.lang.NullPointerException
    at android.content.res.Resources_Delegate.getValue(Resources_Delegate.java:788)
    at android.content.res.Resources.getValue(Resources.java:1286)
    at android.support.v4.content.res.ResourcesCompat.loadFont(ResourcesCompat.java:212)
    at android.support.v4.content.res.ResourcesCompat.getFont(ResourcesCompat.java:206)
    at android.support.v7.widget.TintTypedArray.getFont(TintTypedArray.java:119)
    at android.support.v7.widget.AppCompatTextHelper.updateTypefaceAndStyle(AppCompatTextHelper.java:208)
    at android.support.v7.widget.AppCompatTextHelper.loadFromAttributes(AppCompatTextHelper.java:152)
    at android.support.v7.widget.AppCompatTextHelperV17.loadFromAttributes(AppCompatTextHelperV17.java:38)
    at android.support.v7.widget.AppCompatTextView.<init>(AppCompatTextView.java:81)
    at android.support.v7.widget.AppCompatTextView.<init>(AppCompatTextView.java:71)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
    at org.jetbrains.android.uipreview.ViewLoader.createNewInstance(ViewLoader.java:475)
    at org.jetbrains.android.uipreview.ViewLoader.loadClass(ViewLoader.java:250)
    at org.jetbrains.android.uipreview.ViewLoader.loadClass(ViewLoader.java:213)
    at com.android.tools.idea.rendering.LayoutlibCallbackImpl.loadClass(LayoutlibCallbackImpl.java:193)
    at android.view.BridgeInflater.loadCustomView(BridgeInflater.java:333)
    at android.view.BridgeInflater.onCreateView(BridgeInflater.java:152)
    at android.view.LayoutInflater.onCreateView(LayoutInflater.java:717)
    at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:785)
    at android.view.BridgeInflater.createViewFromTag(BridgeInflater.java:222)
    at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:727)
    at android.view.LayoutInflater.rInflate_Original(LayoutInflater.java:858)
    at android.view.LayoutInflater_Delegate.rInflate(LayoutInflater_Delegate.java:70)
    at android.view.LayoutInflater.rInflate(LayoutInflater.java:834)
    at android.view.LayoutInflater.inflate(LayoutInflater.java:492)
    at com.android.layoutlib.bridge.bars.CustomBar.<init>(CustomBar.java:95)
    at com.android.layoutlib.bridge.bars.StatusBar.<init>(StatusBar.java:67)
    at com.android.layoutlib.bridge.impl.Layout.createStatusBar(Layout.java:224)
    at com.android.layoutlib.bridge.impl.Layout.<init>(Layout.java:146)
    at com.android.layoutlib.bridge.impl.RenderSessionImpl.inflate(RenderSessionImpl.java:301)
    at com.android.layoutlib.bridge.Bridge.createSession(Bridge.java:429)
    at com.android.ide.common.rendering.LayoutLibrary.createSession(LayoutLibrary.java:368)
    at com.android.tools.idea.rendering.RenderTask$2.compute(RenderTask.java:567)
    at com.android.tools.idea.rendering.RenderTask$2.compute(RenderTask.java:549)
    at com.intellij.openapi.application.impl.ApplicationImpl.runReadAction(ApplicationImpl.java:863)
    at com.android.tools.idea.rendering.RenderTask.createRenderSession(RenderTask.java:549)
    at com.android.tools.idea.rendering.RenderTask.lambda$inflate$1(RenderTask.java:680)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)

一体なんだこのエラーは...

解決方法

values/styles.xmlのベーステーマのを修正する。

Theme.AppCompat.Light.DarkActionBar
から Base.Theme.AppCompat.Light.DarkActionBar
にすると直った。

 <resources>
 
     <!-- Base application theme. -->
-    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
+    <style name="AppTheme" parent="Base.Theme.AppCompat.Light.DarkActionBar">
         <!-- Customize your theme here. -->
         <item name="colorPrimary">@color/colorPrimary</item>
         <item name="colorPrimaryDark">@color/colorPrimaryDark</item>

MacOS Sierraでラズパイssh接続時にWarning: untrusted X11 forwarding setup failed: xauth key data not generated

MacSierraにアップグレードした後、ラズパイにssh -Xで接続すると以下のエラーが出ていた。

Warning: untrusted X11 forwarding setup failed: xauth key data not generated

はじめは気付かず、ssh越しにラズパイの画像をCLIで表示しようとすると動かず

$ feh Pictures/image.jpg
feh ERROR: Can't open X display. It *is* running, yeah?

一体なにがあった...

原因

エラーをググるとStackOverFlowに同様の現象を質問してる人を発見。

stackoverflow.com

MacOSSierraになってからxauthの場所が変更されたらしく、
どうやら ssh -XでXQuartzが起動してないようだ。

対処法

  1. termnalで/etc/ssh/ssh_configをひらく
sudo vi /etc/ssh/ssh_config
  1. 最後の行に以下を追加
XAuthLocation /usr/X11/bin/xauth
  1. Mac再起動

これで ssh -XでXQuartzが起動するようになった。

解決!

feh ERROR: Can't open X display [Mac]

MacからラズパイにSSHで接続して、
USBカメラで撮影した画像を feh コマンドで表示しようとするとエラーが出る。

$ feh ./image.jpg
feh ERROR: Can't open X display. It *is* running, yeah?

これ、前も見たことあるエラーだな。

ググってあれこれ探した結果、MacではXQuartzを入れれば解決する事がわかった。

解決策

  1. XQuartzをインストールする。
  2. Macを再起動する
  3. terminalからラズパイに-Xを付きでssh接続する
    ssh -X pi@raspberrypi.local
    (-X でMacのXQuartzが起動する)
  4. f:id:banbara:20170806135112p:plain
  5. fehコマンドで画像を開くと… 画像が見れた!
  6. f:id:banbara:20170806135456p:plain

参考リンク

superuser.com

やいまふにWeb版を公開

やいまふにWeb版を公開した。

八重山諸島を結ぶ離島船の運行情報を簡単にチェック。
安栄観光、八重山観光フェリー、石垣ドリーム観光に対応。
また、船の運行を左右する風や波などの天気情報も確認できる。

yaimafuni.com

開発の話をすると、
- Vuejsフレームワーク
- Materializecssでスタイルを作成
- API周りはFirebase Realtime Database
- 公開サーバーはFirebase Hosting

初めて公開できるWebサイトを作った。
初めてのデザインや慣れないJavascriptなど、学ぶべき事が多すぎて苦労したが、
どうにか公開できてホッとしている。

この達成感こそプログラマーの醍醐味だよね