Git Product home page Git Product logo

sales-ranking-android's Introduction

sales-ranking-android

アプリ概要

  • App StoreのRSSフィードから取得したセールスランキングを表示する
  • RSS Generator

プロジェクトの新規作成

  • Android Studio.Appをクリックする
  • [File]-[New]-[New Project...]

ウィザード1

  • Application name: SalesRanking
  • Company domain: example.com
  • Project location: /Users/(ユーザー名)以下のディレクトリを指定する
  • include Kotlin supportにチェックする

ウィザード2

  • Android 5以上を選択

ウィザード3

  • Empty Activityを選択する

Git(省略可)

  • プロジェクトディレクトリにリポジトリを作成し、バージョン管理を開始する
  • 作成したプロジェクトをコミットする
git init
git add -A
git commit -m "initial commit"

エミュレータ

作成

  • [Tools]-[AVD Manager]
  • Created Virtual Device...
  • NexusPixelを選択する

実行

  • [Run]-[Debug 'app']

動きを確かめる(省略可)

アプリ名変更

  • app/res/values/strings.xmlapp_nameセールスランキングにする
  • [Run]-[Debug 'app']

テキストを変更

  • app/res/layout/activity_main.xmlTextViewandroid:textハローワールド!にする
  • [Run]-[Debug 'app']

リストの追加

app/res/layout/activity_main.xml

  • RecyclerViewのダウンロード
    • gradleファイルが変更される
  • 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" />

app/build.gradle

implementation 'com.android.support:recyclerview-v7:27.1.0'

MainActivity

  • 呼び出す側のコードを追加する
import android.support.v7.widget.LinearLayoutManager
import kotlinx.android.synthetic.main.activity_main.*

recyclerView.layoutManager = LinearLayoutManager(this)

セルの追加

app/res/layout/row.xml

  • [File]-[New]-[XML]-[Layout XML File]
  • row.xmlという名前で新規作成する
  • ImageViewをドラッグ&ドロップする
  • TextViewをドラッグ&ドロップする
  • layout_height60dpにする
<?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>

Adapterの追加

MainAdapter

  • [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)
}

MainActivity

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", ... },
            ...
        ]
    }
}

MainItem

  • [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)

リストにデータを渡す

MainAdapter

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
    }

MainActivity

val results = arrayOf(
        Result("モンスターストライク", ""),
        Result("パズル&ドラゴンズ","")
)
recyclerView.layoutManager = LinearLayoutManager(this)
recyclerView.adapter = MainAdapter(results)

実行

  • [Run]-[Debug 'app']
  • 渡したデータが表示されていることを確認する

画像の非同期取得

app/build.gradle

implementation 'com.github.bumptech.glide:glide:4.6.1'
annotationProcessor 'com.github.bumptech.glide:compiler:4.6.1'
  • Sync Nowする

MainActivity

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")

MainAdapter

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取得

app/build.gradle

implementation 'com.squareup.okhttp3:okhttp:3.10.0'

MainActivity

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']
  • Variableresponse.body().string()を追加して、データが取得できていることを確認する

JSONパース

app/build.gradle

implementation 'com.squareup.moshi:moshi-kotlin:1.5.0'

MainActivity

  • 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にデータが入っていることを確認する

ランキングを表示する

MainActivity

  • 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から取得したデータが画面に反映されていることを確認する

レイアウトを整える

app/res/layout/row.xml

  • 以下のコードに書き換える
<?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" />

MainActivity

progressBar.visibility = View.GONE

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.