Class ‘Task’ is not abstract and does not implement abstract member public abstract fun writeToParcel(p0: Parcel!, p1: Int): Unit defined in android.os.Parcelable

AndroidのParcelのことでつまづています。

Parcelという仕組みは、例えばIntentからIntentへ何か値を渡すときに、String(文字列)とかInt(整数)とかだと簡単に渡せるんですが、自分で作った自作クラスのオブジェクトを渡すための仕組みです。(かなりはしょっていますが)

Parcelについて(Android公式 英語)

で、Javaでやってた時はかなりごちゃごちゃ書かないと、 自分で作った独自クラス にParcelというのを実装できませんでした。

Kotlinでも、少し古いのを読むと、の独自クラスに実装するのに、やはりかなりわかりにくい処理を書かねばいけませんでした。

しかし、なんと!!

Android StudioのKotlinのプラグインの1.3.60 以降では、下記のように

@Parcelize
class Task(val _id: String, val _name: String):Parcelab

これだけでOKになりました!

@Parcelize

アノテーションと、Parcelableを継承するだけで完結!

になったらしいです。

A study of the Parcelize feature from Kotlin Android Extensions
https://medium.com/@BladeCoder/a-study-of-the-parcelize-feature-from-kotlin-android-extensions-59a5adcd5909

しゅごいー

と思って早速実装したところ、タイトル通り、ビルドできませんでした。

下記のStack Overflowさんにも、1.3.60以降はこのエラー出ないヨ!って書いてあるんですけどね…。

https://stackoverflow.com/questions/56018761/class-x-is-not-abstract-and-does-not-implement-fun-writetoparcel-defined-in-an

仕方なく

androidExtensions {
experimental = true
}

をアプリケーションのbuild.gradleに書いたらビルドできるようになりました。

build.gradleの全部をサンプルで載せておきます。

apply plugin: 'com.android.application'

apply plugin: 'kotlin-android'

apply plugin: 'kotlin-android-extensions'

android {
    compileSdkVersion 28
    defaultConfig {
        applicationId "hogehoge.myapplication"
        minSdkVersion 14
        targetSdkVersion 28
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    sourceSets {
        main.java.srcDirs += 'src/main/kotlin'

        androidTest.java.srcDirs += 'src/androidTest/kotlin'
    }
}

androidExtensions {
    experimental = true
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
    implementation 'com.android.support:appcompat-v7:28.0.0'
    implementation 'com.android.support.constraint:constraint-layout:1.1.3'
    implementation 'com.android.support:design:28.0.0'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'com.android.support.test:runner:1.0.2'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
}

Kotlin のコードをバイトコードにしてからJavaにデコンパイルする

Android Studio内(現時点で3.4.1)で 実に簡単にできます。(´ω`)

①対象のKotlinのファイルを開いておく

②Tools→Kotlin→Show Kotlin Bytecode

で、右のベイン(私の環境では)に、バイトコードが出ます。

おおー。

で、上にある「Decompile」というボタンを押します。

そうすると、左側のソースコードのところに、例えば

「Task.kt」

というファイルを変換した時は

「Task.decompiled.java」

というファイルができます。

途中、バイトコードにしてくれるのはIntelliJのやさしさなんですかね?

「ちゃんとやってますよー」

みたいな。

なんでこんなことやってみたかというと、下記のMediumの記事を見て、とても勉強になったからです。(オール英語でかなりつらい)

良記事なので、また違うところで紹介できるといいなと思います。

https://medium.com/@BladeCoder/a-study-of-the-parcelize-feature-from-kotlin-android-extensions-59a5adcd5909



2次元のNumpyの行列で、行と列に1個ずつしか1が存在しないかどうか確かめるサンプルコード

あんまり大した話じゃないんですけど(大したことを書いたことがないですが(^_^;))

次のような、2次元のNumpyの配列(ndarray)があった時に

pieces = np.array([
        [1, 0, 0],
        [0, 1, 0],
        [0, 0, 1]
        ])

行、列のどちらにも一個しか1が存在しないのが正しい状態で、2個以上の場合は、エラーを出す、という必要がありました。

import numpy as np

pieces = np.array([
        [1, 0, 0],
        [0, 1, 0],
        [0, 0, 1]
        ])

list1 = np.count_nonzero(pieces, axis=0)
print(list1)

list2 = np.count_nonzero(pieces, axis=1)
print(list2)

morethan_one_column = [i for i in list1 if i > 1 ]
print(morethan_one_column)

if morethan_one_column:
        print("あかーん")

morethan_one_row = [i for i in list2 if i > 1 ]
print(morethan_one_row)

if morethan_one_row:
        print("あかーん")

one hotなどで、行の方向に1個だけしか存在してほしくない、という状況はえてしてあると思います。

私の場合は、列の方向にも1個だけしか存在してほしくない、という状況ですけど、行の場合だけなら上記の

np.count_nonzero(pieces, axis=1)

だけでコト足りてます。

axisという引数は、軸ですが、軸の数え方、いつも間違いそうになりますけど、この2次元配列の場合、縦に並んでいるのが0軸です!!

下記にも count_nonzero は紹介してまして、実際のところ、下記の記事みてやり方思い出したって次第です。


NumPy 0じゃない要素をカウントする

Python

PHPで複数のコンストラクタを設定する

PHPでは複数のコンストラクタを、例えば引数の数に応じて使い分けるということができません。(´ω`)

下記みたいにやりたいじゃないですか。

<?php
class A
{
   function __construct()
    {
    }
   
    function __construct($a1)
    {
        echo('引数が1個のコンストラクタ');
    }
   
    function __construct($a1,$a2)
    {
        echo('引数が2個のコンストラクタ');
    }
   
}


でもできません。(´ω`)

「そんなの不便じゃーん」

もちろんそうですが、ググっても「できません」とかあまりいいやり方出てこなかったので、下記のPHP本家サイトに載っているコードですが、再掲させて頂きます。

https://www.php.net/manual/ja/language.oop5.decon.php

みんな!PHPの本家マニュアルサイトで大事なのは、下の方にある、

User Contributed Notes

だよ!ここ読むと、いいこと書いてあるので読み得です。
英語なのが玉にキズ。(´ω`)

<?php
class A
{
  //要はコンストラクタを使って、引数の数でメソッド振り分けしている
    function __construct()
    {
        $a = func_get_args();
        $i = func_num_args();
        if (method_exists($this,$f='__construct'.$i)) {
            call_user_func_array(array($this,$f),$a);
        }
    }
   
    function __construct1($a1)
    {
        echo('__construct with 1 param called: '.$a1.PHP_EOL);
    }
   
    function __construct2($a1,$a2)
    {
        echo('__construct with 2 params called: '.$a1.','.$a2.PHP_EOL);
    }
   
    function __construct3($a1,$a2,$a3)
    {
        echo('__construct with 3 params called: '.$a1.','.$a2.','.$a3.PHP_EOL);
    }
}
$o = new A('sheep');
$o = new A('sheep','cat');
$o = new A('sheep','cat','dog');

// results:
// __construct with 1 param called: sheep
// __construct with 2 params called: sheep,cat
// __construct with 3 params called: sheep,cat,dog
?>

Java 桁の大きいLongがマイナスの数字になってしまう

しょぼい失敗ではありますが。(´・ω・`)

例えば、31日間のミリセカンドを取得すべく下記のように定義したとします。

public static final long THIRTY_ONE_DAYS_MILL_SEC = 31 * 24 * 60 * 60 * 1000;

この数字は、2,678,400,000です。
26億7840万ミリ秒ですね。

ですが、これを実行すると、実際には、THIRTY_ONE_DAYS_MILL_SEC

-1616567296 

という数字が入っています。マイナスの数字になってしまってるんですよー。

なんで?というと、次のようなことが起きているらしい。

①右辺で計算する時はintで計算されている

②intの最大値が int32ビット-2,147,483,648 〜 2,147,483,64

③桁あふれでマイナス値になってしまっている

なので、右辺で計算するときにlongであると宣言してあげないと、 2,678,400,000 にならないらしいのです…。

末尾にLをつけるだけ。

正しくは、下記の通り。


public static final long THIRTY_ONE_DAYS_MILL_SEC = 31 * 24 * 60 * 60 * 1000L;