Android Studio.App
をクリックする
[File]-[New]-[New Project...]
Application name: SalesRanking
Company domain: example.com
Project location: /Users/(ユーザー名)
以下のディレクトリを指定する
include Kotlin supportにチェックする
プロジェクトディレクトリにリポジトリを作成し、バージョン管理を開始する
作成したプロジェクトをコミットする
git init
git add -A
git commit -m " initial commit"
[Tools]-[AVD Manager]
Created Virtual Device...
Nexus
やPixel
を選択する
app/res/values/strings.xml
のapp_name
をセールスランキング
にする
[Run]-[Debug 'app']
app/res/layout/activity_main.xml
のTextView
のandroid:text
をハローワールド!
にする
[Run]-[Debug 'app']
app/res/layout/activity_main.xml
RecyclerView
のダウンロード
TextView
を削除する
RecyclerView
をドラッグ&ドロップする
android:id
を@+id/recyclerView
にする
<android .support.v7.widget.RecyclerView
android : id =" @+id/recyclerView"
android : layout_width =" match_parent"
android : layout_height =" match_parent" />
implementation ' com.android.support:recyclerview-v7:27.1.0'
import android.support.v7.widget.LinearLayoutManager
import kotlinx.android.synthetic.main.activity_main.*
recyclerView.layoutManager = LinearLayoutManager (this )
[File]-[New]-[XML]-[Layout XML File]
row.xml
という名前で新規作成する
ImageView
をドラッグ&ドロップする
TextView
をドラッグ&ドロップする
layout_height
を60dp
にする
<?xml version =" 1.0" encoding =" utf-8" ?>
<LinearLayout xmlns : android =" http://schemas.android.com/apk/res/android"
xmlns : app =" http://schemas.android.com/apk/res-auto"
android : layout_width =" match_parent"
android : layout_height =" match_parent" >
<ImageView
android : id =" @+id/imageView"
android : layout_width =" wrap_content"
android : layout_height =" wrap_content"
android : layout_weight =" 1"
app : srcCompat =" @mipmap/ic_launcher" />
<TextView
android : id =" @+id/textView"
android : layout_width =" wrap_content"
android : layout_height =" wrap_content"
android : layout_weight =" 1"
android : text =" TextView" />
</LinearLayout >
[File]-[New]-[Kotlin File/Class]
MainAdapter
という名前で新規作成する
MainAdapter.MainHolder
を追加
RecyclerView.Adapter
のメンバーを実装する(implement members
を活用する)
import android.support.v7.widget.RecyclerView
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import kotlinx.android.synthetic.main.row.view.*
class MainAdapter (): RecyclerView.Adapter<MainAdapter.MainHolder>() {
override fun onCreateViewHolder (parent : ViewGroup , viewType : Int ): MainHolder {
return MainHolder (LayoutInflater .from(parent.context).inflate(R .layout.row, parent, false ))
}
override fun getItemCount (): Int {
return 30
}
override fun onBindViewHolder (holder : MainHolder , position : Int ) {
holder.itemView.textView.text = " モンスターストライク"
}
class MainHolder (view : View ): RecyclerView.ViewHolder(view)
}
recyclerView.adapter = MainAdapter ()
[Run]-[Debug 'app']
リストにデータが30行表示されていることを確認する
App StoreのRSSフィードで得られる構造化データをプログラムで表現する
{
" feed" : {
" title" : ...,
" id" : ...,
...
" results" : [
{ " name" : " xxx" , " artworkUrl100" : " yyy" , ... },
{ " name" : " xxx" , " artworkUrl100" : " yyy" , ... },
{ " name" : " xxx" , " artworkUrl100" : " yyy" , ... },
...
]
}
}
[File]-[New]-[Kotlin File/Class]
MainItem
という名前で新規作成する
package com.example.saleranking
data class Item (val feed : Feed )
data class Feed (val results : Array <Result >)
data class Result (val name : String , val artworkUrl100 : String )
class MainAdapter (private val results : Array <Result >): RecyclerView.Adapter<MainAdapter.MainHolder>() {
override fun getItemCount (): Int {
return results.size
}
override fun onBindViewHolder (holder : MainHolder , position : Int ) {
holder.itemView.textView.text = results[position].name
}
val results = arrayOf(
Result (" モンスターストライク" , " " ),
Result (" パズル&ドラゴンズ" ," " )
)
recyclerView.layoutManager = LinearLayoutManager (this )
recyclerView.adapter = MainAdapter (results)
[Run]-[Debug 'app']
渡したデータが表示されていることを確認する
implementation ' com.github.bumptech.glide:glide:4.6.1'
annotationProcessor ' com.github.bumptech.glide:compiler:4.6.1'
Result (" モンスターストライク" , " https://is3-ssl.mzstatic.com/image/thumb/Purple128/v4/d7/3a/ae/d73aae7d-b2c0-998f-c7a1-a2f60215b880/AppIcon-1x_U007emarketing-85-220-7.png/200x200bb.png" ),
Result (" パズル&ドラゴンズ" ," https://is1-ssl.mzstatic.com/image/thumb/Purple118/v4/c3/97/35/c397356b-bf5f-cae6-724f-5dc638a17f6c/AppIcon-1x_U007emarketing-0-85-220-0-9.png/200x200bb.png" )
import com.bumptech.glide.Glide
.. .
Glide .with (holder.itemView).load(results[position].artworkUrl100).into(holder.itemView.imageView)
app/manifests/AndroidManifest.xml
<uses-permission android : name =" android.permission.INTERNET" />
[Run]-[Debug 'app']
画像が取得できていることを確認する
RSS取得
implementation ' com.squareup.okhttp3:okhttp:3.10.0'
import android.util.Log
import okhttp3.*
import java.io.IOException
val request = Request .Builder ()
.url(" https://rss.itunes.apple.com/api/v1/jp/ios-apps/top-grossing/all/30/non-explicit.json" )
.build()
OkHttpClient ()
.newCall(request)
.enqueue(object : Callback {
override fun onResponse (call : Call ? , response : Response ? ) {
Log .d(" test" , response?.body()?.string())
}
override fun onFailure (call : Call ? , e : IOException ? ) {
}
})
メソッドonResponse
にブレークポイントをおく
[Run]-[Debug 'app']
Variable
にresponse.body().string()
を追加して、データが取得できていることを確認する
implementation ' com.squareup.moshi:moshi-kotlin:1.5.0'
Log.d("test", response?.body()?.string())
の行は削除する
import com.squareup.moshi.KotlinJsonAdapterFactory
import com.squareup.moshi.Moshi
.. .
val responseJson = response?.body()?.string() ? : return
Log .d(" responseJson:" , responseJson)
val item = Moshi .Builder ()
.add(KotlinJsonAdapterFactory ())
.build()
.adapter(Item ::class .java)
.fromJson(responseJson)
メソッドonResponse
にブレークポイントをおく
[Run]-[Debug 'app']
変数item
にデータが入っていることを確認する
recyclerView.adapter = MainAdapter(results)
の行を削除する
import android.os.Handler
import android.os.Looper
.. .
Handler (Looper .getMainLooper()).post {
recyclerView.adapter = MainAdapter (item!! .feed.results)
}
[Run]-[Debug 'app']
RSSから取得したデータが画面に反映されていることを確認する
<?xml version =" 1.0" encoding =" utf-8" ?>
<android .support.constraint.ConstraintLayout xmlns : android =" http://schemas.android.com/apk/res/android"
xmlns : app =" http://schemas.android.com/apk/res-auto"
android : layout_width =" match_parent"
android : layout_height =" wrap_content" >
<ImageView
android : id =" @+id/imageView"
android : layout_width =" 60dp"
android : layout_height =" 60dp"
android : layout_weight =" 1"
app : layout_constraintStart_toStartOf =" parent"
app : layout_constraintTop_toTopOf =" parent"
app : srcCompat =" @mipmap/ic_launcher" />
<TextView
android : id =" @+id/textView"
android : layout_width =" 0dp"
android : layout_height =" 60dp"
android : gravity =" center_vertical|start"
android : padding =" 8dp"
android : text =" TextView"
app : layout_constraintEnd_toEndOf =" parent"
app : layout_constraintStart_toEndOf =" @+id/imageView" />
</android .support.constraint.ConstraintLayout>
[Run]-[Debug 'app']
レイアウトが崩れないことを確認する
app/res/layout/activity_main.xml
<ProgressBar
android : id =" @+id/progressBar"
style =" ?android:attr/progressBarStyleLarge"
android : layout_width =" wrap_content"
android : layout_height =" wrap_content"
android : translationZ =" 2dp"
app : layout_constraintBottom_toBottomOf =" parent"
app : layout_constraintEnd_toEndOf =" parent"
app : layout_constraintStart_toStartOf =" parent"
app : layout_constraintTop_toTopOf =" parent" />
progressBar.visibility = View .GONE