転職を繰り返したサラリーマンの多趣味ブログ

30才未経験でSEに転職した人の多趣味ブログ

アプリ開発初心者が作ったアプリは、本当に売れるのか?③_アプリを作る場合、自分ができる範囲を自覚することが重要

まさに表題の通りです。GWが終わり仕事が始まると、そもそも家で開発できる時間がなかなか確保できない。
けど、ここでやめてしまうとせっかく勉強を始めたのに勿体ないので、何とか少しずつでも開発を行っていました。
ちなみに完成したアプリは、こんな感じ。
f:id:uuc1h:20190519011200p:plain
いわゆるジャンケンゲームです。
この画面で自分のジャンケンの手を選ぶと、次画面に遷移します。
f:id:uuc1h:20190519011314p:plain
そこでジャンケンの結果が表示され、戻るボタンを押すともう一度ジャンケンができるというゲームです。
このアプリって、「はじめてのANDROIDプログラミング第4版」のサンプルアプリとほぼ一緒なんやけど、自分で工夫したのが、連勝回数をトップ画面に表示させるようにしたこと。
アプリを作る場合、「自分ができる範囲内」だけでやることが重要だと思っている。

これで、画面遷移と共有プリファレンスの使い方はなんとなくわかった気がする。

はじめてのAndroidプログラミング 第4版

はじめてのAndroidプログラミング 第4版

アプリ開発初心者が作ったアプリは、本当に売れるのか?②_さっそくアプリを1つ作り、Google Play Storeへ公開した

前回の記事がこちら。

uuc1h.hatenablog.jp

 さて、Androidを買ったし、PCはWindowsだし、Javaならちょっと分かるしということで、Android Studioアプリ開発をやっていこうと、前回のブログで決意表明しました。
そこで、さっそくAndroid開発の本を購入。それがこちら。

はじめてのAndroidプログラミング 第4版

はじめてのAndroidプログラミング 第4版

 

 サンプルとなるアプリがたくさん載っているのが、購入に至った一番の動機だ。
最初から読み進めていくと、ここである事実が一つ。

Android Studio 3.0のリリースとともに新言語Kotlinのサポートが開始されました。Googleは今後KotlinをAndroidの標準プログラミング言語にすることを明言していますので、将来的には完全に置き換わるかもしれません。

引用元:はじめてのAndroidプログラミング 第4版

 えーJavaじゃないの!!ってのが第一の感想。ただ、Javaとは100%互換性があるみたいで、Java開発経験は無駄になるわけではないとのこと。しかも、Kotlinの方がなにかと簡潔にすむらしい。
よし、では自分もKotlinで開発していこう。というか、この本がKotlinで開発しているから、Kotlinで開発するしかないのだが。。

この本は、8つのサンプルアプリが収録されている。ということで、1つのサンプルアプリをまず本の通りに作ってみて、そこで得た知識をもとに自分のアプリを作り、リリースまでやってしまおうと思う。今日はその第一弾。

得た知識

・プロジェクトの作成時、Use AndroidX artifactsにチェックを入れる。(AndroidXライブラリを使用するため)
・画像を使用する場合は、res/drawableに保存する。
Androidは画面をレイアウトする方法として、「ContraintLayout」がある。ビューに対して、制約を設定する。
・リソースの設定方法
 Resources画面を開き、Add new resources / New string valueより行う。
 または、Translations Editorから行う
・アクティビティの追加
 appを右クリックし、New / Activity / Empty Activityより追加する。ktファイルとxmlファイルが作成される。
・Intentを使った画面遷移方法
・インポートのショートカット(Alt + Enter)
インテントにデータを格納し、遷移先でデータを取得する方法
・finishメソッドを使った、前のアクティビティに戻る動作
・共有プリファレンスの使い方

成果物

f:id:uuc1h:20190506213344p:plain

f:id:uuc1h:20190506213354p:plain

Randomメソッドを使って、ただ単に「大吉」、「中吉」、「凶」のいづれかを画面上に表示するだけの単純なアプリです。

ただ、今回の一番の目的はAndroid Studioで作ったものを、リリースすること。一度Google Playにリリースしたことはあるが、そのときはUnityで作ったものだ。
Android Studioから、apkファイルの作成は以下記事の通りにやったら無事にできた。
https://akira-watson.com/android/apk.html

つづいて、Google Play Consoleからのリリースだが、以下記事を参考にした。
https://qiita.com/android_develop_hunt/items/c57319dc3012cb310c6c

 そうして、公開したアプリがこちら。
https://play.google.com/store/apps/details?id=jp.uuch1.fortune_telling

うん、このサイクルを続けていけば、いい感じになりそうな気がする。



 

アプリ開発初心者が作ったアプリは、本当に売れるのか?①

もう何度も本ブログで書いているが、自分は30歳からプログラミングを始めた。始めたきっかけは、IT会社に転職したからだ。
せっかくプログラミングを覚えたから、プライベートでも何か作ってみたいと挑戦中なのが、Unityを使ったゲーム製作だ。素人なりにいろいろ考えて、Applo Storeにも何本かリリースした。

uuc1h.hatenablog.jp

uuc1h.hatenablog.jp

uuc1h.hatenablog.jp

 ただ、ゲーム作りはプログラミングだけでなく、プログラミング以外にも色々な要素が必要になってくる。例えば絵だったり、音楽だったり、アニメーションだったりと。いや、たしかにゲーム作りは楽しいんだけど、自分はもっとサクッと作って、リリースまでしたい。
あと、iOSアプリを作っていてしんどいのが、Appleの審査。なかなか通らず、リジェクトされまくりの日々がこれまたストレスになってくる。

そこで今度はAndroidについて調べると、なんとAndroidはかなり審査がゆるいという。また、リリースも結構簡単にできるとのこと。
これはと思い、生粋のiPhoneユーザーだった自分は生まれて初めてAndroid買いました。テスト機としてね。それが、これ。

なんと、1万円ちょっとでスマホが買える。Androidやっぱりすげーっと、妙な興奮を覚えながら、さっそくリリースしたアプリがこちら。

 ちなみにこのアプリは、Unityで作りました。たしかに、developer登録からリリースまで、かなり簡単にできた。うぉーついにリリースした!って感動してたのだが、ここで問題がひとつ。
まったくダウンロードされない。
このアプリ、ブロック崩しシューティングゲームを混ぜたようなゲームで、自分の中ではかなり頑張って作った。しかし、マジで誰もダウンロードされない。ダウンロード数は、自分がテスト機にダウンロードした1回だけだ。

もちろん自分はアプリ開発で食べていこうなんて思ってないのだが、やはり何の反応もないと、モチベーションが保てない。アプリ開発レッドオーシャンと呼ばれているが、本当に初心者が個人開発したアプリなんて、まったく見向きもされないのだろうか。

と、後ろ向きになりつつあったが、冷静に考えると自分が作ったアプリのクオリティーはかなり低い。これじゃあ使ってもらえないし、またダウンロードされる工夫もしていない。まずは絶対的に、アプリを作った数が少ないと思う。

ということで、これからしばらくはAndroidアプリ開発に集中しようと思う。また、ダウンロードされることを目標にしているので、Unityを使ったゲーム開発ではなく、Android Studioでのツール系アプリ開発に挑戦していく。
100万ダウンロードくらいされないかなー。

Kotlinまとめ

変数と定数

// 変数
var a : Int = 10000

// 定数
val c : Double = 12345.6 

文字列

// 文字列比較は「==」で行う
if (str == "Kotlin")

// 文字列テンプレート
val i = 10
print("i = $i") // i = 10と出力される

// 文字列テンプレート2
val s = "Kotlin"
printl("$s length is ${s.length}) // Kotlin length is 6 と出力される。{}をつけないと、Kotlin length is Kotlin.lengthと表示される

型変換

// 文字列からInt型へ
val str = "64"
val intVal: Int = str.toInt()

// 文字列からInt型へ
val str = "Kotlin"
val intVal: Int? = str.toIntOrNull() // 変換できない場合は変数にNULLを設定

// 数値から文字列へ
val num = 128
val intStr: String = num.toString()

// 数値同士の変換
val i: Int = 100
val l: Long = i.toLong() // 明示的に変換が必要

null許容型とnull非許容型

// 以下の場合はエラーになる
var text: String = null

// 正しくは以下のような記述が必要
var text: String? = null

// null許容型の変数の場合、String型のメソッドやプロパティをそのままでは使用できないなどの制限が発生する

配列

// Arrayクラスを使い、arrayOf関数で配列の生成と初期化を実行
val arrayofInt: Array<Int> = arrayOf(1,2,3,5,8)
for (i in arrayofInt) print("$i,")

if式

val c = 10
val d = 20
if (c > d) {
    print("c")
} else {
    print("d")
}

when式

val a = 4
when(a) {
    1 -> println("a == 1")
    2,3 -> println("a == 2 or 3")
    in 10..20 -> println("a is in the range")
    !in 20..30 -> println("a is outside the range")
    else -> println("otherwise")
}

for文

for(i in 1..4)

// 配列を使う場合
val a = arrayOf(1,2,3,10,100)
for(i in a.indices) {
    print("a[$i]=${a[i]}")
}

while文

var x = 0
while(x < 10)

// do-while文
var i = 7
do {
    
}while(i > 4)

リスト

// 読み込み専用リスト
val items: List<Int> = listOf(1, 2, 3)
println(items.get(0))
println(items[1])
println(items.size)

// 変更可能なリスト
val numbers:MutableList<Int> = mutableListOf(1,2,3)
numbers.add(4) // リストの末尾に4を追加
numbers.remove(4) // 一致する要素を削除

セット

// 特徴:要素の順番をもたず、要素の重複も不可

// 読み取り専用セット
var strings:Set<String> = setOf("A", "B", "C")
println(strings)

// 変更可能セット
var strings: MutableSet<String> = mutableSetOf("x", "y", "z")
strings.add("A")
strings.remove("x")

マップ

// 読み取り専用のマップ
val fruits:Map<String, Int> = mapOf("apple" to 1, "orange" to 2, "banana" to 3)

// 変更可能なマップ
val fruits: MutableMap<String, Int> = mutableMapOf("apple" to 1, "orange" to 2, "banana" to 3)
println(fruits.get("apple"))
println(fruits["orange"])
fruits.put("melon",4) // 要素の追加
fruits.remove("banana") // 要素の削除

関数

// fun 関数名(引数:型,・・・):戻り値
fun times(a: Int, b: Int): Int {
    return a * b
}
// 関数の呼び出し
// Kotlinではクラスに属さない関数を作成できる
times(2, 5)

// 戻り値がなく、2番目の引数をデフォルト設定する場合
fun printTimes(a: Int, b:Int = 2):Unit{}
printTimes(10)

ラムダ式と関数型

ラムダ式:{引数 -> 処理}

// ラムダ式は変数に格納可能。この時の変数を関数型と呼ぶ
var minus = {x: Int, y: Int -> x - y}
minus(3, 1) // 結果は2

// 変数plusは「(Int, Int) -> Int」型
var plus:(Int, Int) -> Int = {x:Int, y:Int -> x + y}
plus(5, 2)

// 暗黙の引数it
// 引数一つの場合は、引数を省略し引数itを使用できる
// itを使用しない場合はvar double:(Int)->Int = {x:Int -> x * 2}とかく
var double: (Int)->Int = {it * 2}
double(5)

// 関数型を引数に持つ関数
fun doLambda(x: Int, y:(Int) -> Int) = y(x)
doLambda(5, {it * 2})

クラスとインターフェイス

クラスの定義:class クラス名{}
※publicがデフォルト

// インスタンス生成
class dog{}
val dog = Dog()

インターフェイスの定義:interface インターフェイス名{定義}
Kotlinのインターフェイスは、抽象メソッドだけでなく具体的な処理も記述できる

プロパティ

Javaのフィールドとセッター/ゲッターを合わせたような機能

var dog = Dog()
dog.name = "Pochi" // プロパティに値を設定
println(dog.name) // プロパティから値を取得

コンストラク

プライマリコンストラクタ:クラス宣言でクラス名の後ろにコンストラクタの引数のみを記載する。処理ブロックをもたないため、処理を行う場合はinitブロックに記載。
セカンダリコンストラクタ:処理ブロックを持つため、その他の処理も記載可能。

class Dog(val name: String) {}

イニシャライザ

class Dog(val name: String) {
    init{
        print("The dog's name is $name")
    }
val dog = Dog("Pochi") // ここでイニシャライザが呼ばれる

クラスの継承

class クラス名(プライマリコンストラクタ):親クラス名(コンストラクタ引数)

open class Person(val name: String) {} // 親クラス
class Student(name: String, var degree: String): Person(name) {} // 子クラス
val student = Student("Sato", "Bechelor") // インスタンスの取得

インターフェイスの実装

class クラス名(プライマリコンストラクタ):インターフェイス
※Kotlinのインターフェイスでは抽象メソッドだけでなく、具体的な処理を含むメソッドも定義可能。

interface Pet {
    fun eat()
    fun showName() = println("I'm Pet")
}

class Cat : Pet {
    override fun eat() = println("I'm eating")
}

型チェックとスマートキャスト

fun getLen(obj: Any) : Int? {
    // isでStringかどうかチェック
    if ( obj is String) {
        // チェック後はStringとしてふるまう
        return obj.length
    }
 return null
}

継承関係のあるオブジェクトのキャスト

// 親クラス
open class Person(val name: String) { }
// 子クラス
class Student(name: String, var degree: String): Person(name) {}
// 親クラスの変数に子クラスのインスタンスを生成
var person: Person = Student("Sato", "Bechelor")
// 子クラスへキャスト
var student: Student = person as Student

// as?の使い方
var person: Person = Student("Sato", "Bechelor")
// 例外が発生せずに、nullがセットされる
var student = person as? Int

objectキーワード

objectキーワードを使うと、クラスの宣言とそのインスタンス生成を一気に行う。
■シングルトンの実現

object MyProfile {
    処理内容
}

// objectを使用するにはオブジェクト名を使う
MyProfile.メソッド名

■コンパニオンオブジェクト

class Person(val name: String) {
    companion object {
        fun printMe() = println("Hello")
    }
}

// スタティックメソッドのように扱える
Person.printMe()

■オブジェクト式
無名インナークラスを簡単に記述するための機能

SAM変換

Javaインターフェイスで、メソッドを1つしか持たないものをSAM(Simgle Abstract Method)インターフェイスと呼ぶ。
KotlinではSAMインターフェイスを引数としたメソッドを、ラムダ式で置き換えることをSAM変換と呼ぶ。

NULL安全

var s: String? = null
// The length of null is nullと出力される
print("The length of $s is ${s?.length}")

エルビス演算子

// 変数sがNULLでなければsを返し、sがNULLならdefaultという文字列を返す
val t : String = s ?: "default"

スコープ関数

■with関数
with(対象オブジェクト){処理}

with(Dog("Pochi")) {
    age = 10     // プロパティに値を設定
    message()   // メソッドの利用
}

■apply関数
対象オブジェクト.apply{処理}

Dog("Pochi").apply{
    age = 10
}.message()

■let関数
対象オブジェクト.leg{処理}

var output = name?.let{
    var upperCase = it.toUpperCase()
    var len = it.length
    "$upperCase $len"
}
print(output)

■run関数
対象オブジェクト.run{処理}

var output = name?.run{
    "${toUpperCase()} $length"
}
print(output)

Pair

val p = Pair("apple", 1)
println("the number of ${p.first} is ${p.second} // the number of apple is 1と出力される

拡張関数

fun 型名.関数名(引数):戻り値{処理}

隻狼 SEKIRO_どんなことでも、楽しむためには成長が必要

朝食:サーモンアボカド丼、味噌汁
昼食:つけ麺
夕食:ホタルイカと春キャベツのサラダ、焼き鳥

待ち焦がれていた「SEKIRO」、発売日に買いました。

SEKIRO: SHADOWS DIE TWICE - PS4

SEKIRO: SHADOWS DIE TWICE - PS4

 

 それから、4~5時間ほどやってるけど、ホントに死んで死んで死にまくる。自分はこれまでDarkSoulsシリーズや、Bloodborneをやったことがなくて、FROMSOFTWAREの死にゲー具合が全く分からなかった。けど、これほど死にまくるとは。まさに、心折れる。。
けど、不思議なことに、こんな敵絶対倒せないと思っていながら、何回もやってるといつの間にか倒せるようになってくる。これこそ、ゲームをやって「成長」が実感できる瞬間だ。

自分はゲームに求めるものは、「成長」だ。分かりやすくいうと、RPGの「レベル」だ。何十時間とやることで、レベルがあがり、強くなるし、使える技や魔法が増える。できることが増えると、さらにゲームが楽しくなり、プレイするという具合だ。
コマンド式のRPGは、アクションゲームなどのように反射神経を駆使したテクニックなどは必要なく、誰もが平等に時間をかければ必ず強くなれるゲームだ。だから、RPGでストレスなどは感じないと思う。ここでいうストレスとは、コントローラーをぶん投げてしまうようなことだ。

だが、このSEKIROはアクションゲームである。そのため、誰もが平等に成長できるわけではない。センスのいい人、悪い人ではっきりと成長速度に差が生じてしまう。
また、コマンド式のRPGなどのように、ただ時間をかければいいというものではない。アクションをマスターするために、操作の練習が必要だ。このSEKIROでも、「弾き」「回避」「見切り」などの、敵を倒すうえで必須なアクションが様々ある。これらは、相手の攻撃に合わせ、タイミングよく操作しないと発動しないアクションなのだが、これがとても難しい。
敵によって、攻撃パターンが違えば、こちらのコマンドを押すタイミングも違ってくる。敵の攻撃パターンを把握し、それらを見て、反射的に適切なアクションのコマンド操作が必要になってくる。なお、これらのアクションが何度でも練習できるシステムがゲームに組み込まれているのだが、これはプレイヤーの努力なしでは先に進めないことを物語っているともいえる。

FROMSOFTWAREが以前インタビューで答えていたのだが、「プレイヤーにはゲームで達成感を感じてもらいたい」。この考えは、SEKIROにも十分反映されていると思う。
SEKIROはたしかに高難易度だが、絶対にクリアできないなんてことはない。プレイヤーが努力し、プレイヤー自身が「成長」すれば、必ず先に進める。そうすると、新たな技を覚えたり、武器を入手できたりして、さらに強くなる。そして、またゲームに深くのめり込んでいく。

これ、ゲームだけにとどまらず、現実世界でも同じことだと思う。何事も楽しむためには、「成長」が必要。
さて、しばらくはSEKIROで死んで死んで死にまくる生活を送ります。

MLBが開幕したから、ワールドスポーツMLBの魅力について語らせてほしい

MLB開幕

朝食:おにぎり
昼食:麦飯、レンコンのきんぴら、たまごやき、ミートボール
夕食:ほうれん草とキノコの卵とじ、春巻き

ついにMLB開幕。1年早いもんですな。
因みに自分はMLBNFLNBAと見てるもんだから、1年中スポーツまみれの幸せな1年を過ごせている。あとこれに、UFCを見てるし、最近はF1にも手を出そうとしているから、むしろ色々追い付かなくなる悲劇に見舞われている。。

と、ここで昔を振り返ると、自分が「野球」に興味を持って、まさか試合を見るようになるとは思わなかった。
野球少年以外の少年にとって、「野球」とは憎むべき対象だった場合もあると思う。そう、昔は地上波で放送していたプロ野球中継だ。
プロ野球中継で、いつもやっている番組が中止になる。また、テレビの主導権は親にあるため、チャンネルを変えられる。予約録画をしていたら、野球が延長で放送時間が伸びて、録画が失敗するなどなど。野球に興味がなかった自分にとっては、本当に迷惑でしかなかった。

では、なぜ大人になって野球に興味を持ったかというと、「ワールドスポーツMLB」の番組のおかげだ。

www4.nhk.or.jp

最初、この番組を見始めたきっかけは、NBAの情報を見るためだ。しかし、番組タイトルから分かる通り、メインで扱うスポーツはMLB。そのため、MLBの情報が嫌でも入ってくるのだが、そこで放送されるシーンの数々は、野球に興味を抱かせるには充分だった。
あと、ちょうど自分が仕事から帰宅した時間帯にやっていたのも大きい。そして決定的に野球(というか、MLB)にハマるきっかけとなったのは、シカゴ・カブス vs クリーブランド・インディアンスワールドシリーズだ。
このシリーズは、第7戦までもつれ、その第7戦の異様な盛り上がりは今思い出しても鳥肌が立つ。

また、ワールドスポーツMLBでの解説も素晴らしい。初心者にとって、そのスポーツの詳しいルールだったり、場面場面の駆け引きなどは試合を見ているだけでは分かりにくい。
「知る」ことにより「さらに好きになる」というのは、スポーツだけに留まらずどんなジャンルにも当てはまることだと言えるが、当時のワールドスポーツMLBの解説者である小宮山悟氏のコメントは、的確で分かりやすく大好きだった。そして何より、野球が大好きなのが伝わってくるのが素晴らしい。

そしてワールドスポーツMLBのもう一つの魅力として、ちゃんと野球が好きなキャスターを起用していること。中でも代表的なのが(というか、自分が好きなのが)、平原沖恵氏だ。プライベートでもプロ野球、MBL問わずの野球好きで、だからこそ番組内でのコメントにも好感しか持てない。特にこういうスポーツを扱う番組では、しっかりとそのスポーツを好きな人に担当してもらいたいのが、自分の自論だ。

だがしかし、Wikipediaを見ると今年のワールドスポーツMLBには、平原沖恵氏が出なさそうな。。というか、ワールドスポーツMLB、いつから始まるのか。

僕が筋トレする理由

f:id:uuc1h:20190317210225j:plain

2019年3月17日の所感

朝食:麦飯、味噌汁、鮭
昼食:炙り焼豚の極太つけ麺
夕食:サバ缶、豆腐、レタスのサラダ、もずく、ニンジンと柿ピーのマヨネーズ和え
体重:72.0kg

 今日は日曜日なので、ジムでトレーニング。かれこれ1年以上ジムに通っているけど、体的には全く変化なし。
まぁ、ジムに行くのは休日だけで、しかも土日のどちらか1日だけだったりする。また、毎週行っているわけでもないので、月に1回しか行かないなんてこともざらにある。こんなペースで体を変えようという方が都合が良すぎる。

けど、全く変化がないかというと実はそうでもない。
最初レッグプレスは、70kgしかあがらなかった。けど今では120kgまであがるようになった。ベンチプレスは、20kgが限界だったが、今では倍の40kgまであがるようになった。バーベルスクワットは、40kgしかあがらなかったが、60kgまであがるようになった。
というように、体の変化はなくとも、確実に成長している。成長があるからこそ、今でもジムに通い続けている。

が、ジムに行く理由はこれだけではない。自分が今行っているジムにはサウナがついているのだが、このサウナが一番のお目当てといってもいい。実際、ジムに行くというより、サウナに行っている感覚が強い。
ただ、サウナだけに入って帰ってくると、料金的に損した気分になるため、筋トレもしているといった感じだ。

けど、サウナはもともと好きではなかった。というより、温泉や銭湯といった大勢が入るお風呂が苦手なのだ。結構、潔癖なとこがあるので。。
けど、今ではサウナがない生活は考えられない。サウナのどこがそんなにいいかと言うと、やはり体の底から、リフレッシュできるとこだろう。自分はサウナ-水風呂を1セットとして、これを3セット繰り返す。
3セット目にもなると、汗の質が変わってくる。いわゆる、サラサラ汗だ。ここまで来れば、体の不純物が取り除かれた(と思っている)。そうすると、体の爽快感が凄まじい。もう、これを体験すると、サウナから離れられなくなる。
あと、もう30歳を超えてきて、加齢臭のような体臭を放つ年齢になってきたので、体の不純物を定期的に出すことは、本当に重要だと感じている。ということで、あまり人に何かを薦めるということはないのだが、体臭に悩んでいる人には、サウナを激しくオススメします。