Giter VIP home page Giter VIP logo

winas-lesson-android-exam's Introduction

Day1

(1)モバイルアプリを開発する上で、設計上留意すべき点はどこになるか、サーバサイドやフロントエンドとの違いの観点から説明してください。

(2)Activityへの過度な依存や類似/同一コードの重複を避けるため、コード設計上どのような対策をとることが望ましいか、プレゼンテーション層(View)と処理・ビジネスロジック(Controller)それぞれの観点から説明してください。

Day2

(3)以下のそれぞれのレイアウトを実現するレイアウトXMLを書いてください。

① 横一列に3つのViewを並べるレイアウト。その際、3つのViewの幅(width)の比率が、3:2:1になるようにすること。また、それぞれ左右に10dpずつマージンを取り、高さはすべて100dpとすること。

② 画面いっぱい(上下左右に10dpずつマージン)にViewを置き、それに重ねる形で、width 100dp、height 100dpのViewを縦横**にそろえたレイアウト。色はそれぞれ変えること。

③ 親ビューの下部に横幅100%、高さは可変サイズのTextViewを配置し、その上部にwidth 100dp、height 100dpのViewを左右の**にそろえたレイアウト。

(4)以下のコードのTODO箇所を埋める形で、ActivityのContentViewの各Viewコンポーネントをプロパティアクセスで参照するコードを、①findViewByIdを使う方法、②ViewBindingを使う方法それぞれで書いてください。 その際、下記の要件に従うこと。

  • レイアウトファイルの名前は、main_activity.xmlとする
class MainActivity : Activity() {
    private val findViewByIdView: View?
        get() = // TODO: ①findViewByIdからViewを取得
    private val viewBindingView: View?
        get() = // TODO: ②ViewBindingからViewを取得

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // TODO: ここでContentViewを設定すること。①②それぞれでコードを書くこと
    }
}
interface ViewBindable {
    var binding: ViewBinding
}

Day3

(5)以下のコードのTODO箇所を埋める形で、①Activityが新しい別のActivityを呼び出した際にデータ(Contentデータ)を渡し、②呼び出されたActivityが閉じられる際に古いActivityにデータ(Int型の数値)を渡すコードを書いてください。なお、コード中に使われるIDは、コード内にあるenumを使用すること。

data class Content(
    var id: Int = 0,
    var name: String = ""
) : Parcelable {
    override fun writeToParcel(parcel: Parcel, flags: Int) {
        parcel.writeInt(id)
        parcel.writeString(name)
    }
    override fun describeContents(): Int {
        return 0
    }
    constructor(parcel: Parcel) : this(
        parcel.readInt() ?: 0,
        parcel.readString() ?: "")
    companion object CREATOR : Parcelable.Creator<Content> {
        override fun createFromParcel(parcel: Parcel): Content {
            return Content(parcel)
        }
        override fun newArray(size: Int): Array<Content?> {
            return arrayOfNulls(size)
        }
    }
}
enum class ActivityRequestCode(val code: Int) {
    TARGET(11111);
}
enum class ActivityResultCode(val code: Int) {
    TARGET(1111);
}
enum class ActivityExtraData(val key: String) {
    NUMBER("number"), CONTENT("content");
}
class MainActivity : Activity() {
    private val button: Button?
        get() = findViewById<Button>(R.id.button) as? Button
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        button?.setOnClickListener {
            // TODO: Contentデータを設定してTargetActivity呼び出し
        }
    }
    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        // TODO: TargetActivityから返されたデータをデバッグ
    }
}
class TargetActivity : Activity() {
    private val closeButton: Button?
        get() = findViewById<Button>(R.id.button) as? Button
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_target)
        // TODO: MainActivityから渡されたデータを復元
        
        closeButton?.setOnClickListener {
            // TODO: MainActivityに返す任意のデータ(Int)を設定してください
            finish()
        }
    }
}

(6)以下のコードのTODO箇所を埋めて、Activity(呼び出し側)とカスタムビューとの間での処理のやりとりを実現するコードを書いてください。その際、下記の条件を満たすこと。

  • SampleViewlistenerを設定して、ボタンがタップされた際にActivity側でイベントを受け取るようにすること
  • SampleViewにデータ(Content)を設定したら、textViewにデータのtextを表示させること
  • SampleViewupdate()関数を呼び出したら、textViewに表示される情報を更新すること
data class Content(
    var id: Int = 0,
    var text: String = ""
)
class MainActivity : Activity() {
    private val view: SampleView?
        get() = findViewById<SampleView>(R.id.sample_view) as? SampleView
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val content = Content(id = 1234, text = "test content")
        // TODO
    }
}
class SampleView : FrameLayout {
    private val textView: TextView?
        get() = findViewById<TextView>(R.id.text_view) as? TextView
    private val button: Button?
        get() = findViewById<TextView>(R.id.text_view) as? TextView
    constructor(context: Context) : super(context) {
        // TODO
    }
    // TODO
}

(7)以下のコードのTODO箇所を埋めて、コード中の各ImageViewに、指定された方法で画像を表示させるコードを書いてください。その際、下記の条件を満たすこと。

  • imageView1にresourceのdrawableから "icon" を設定すること
  • imageView2にassetから画像ファイル "icon2.png" を読み込み、Bitmapとして設定すること
  • imageView3にenumBrandIconを使ってアイコンフォントの画像を設定すること
  • imageView4にOSSPicassoを使って、画像URL "https://sample.com/sample.jpg" を読み込むこと
class MainActivity : Activity() {
    private val imageView1: ImageView?
        get() = findViewById<ImageView>(R.id.image_view_1) as? ImageView
    private val imageView2: ImageView?
        get() = findViewById<ImageView>(R.id.image_view_2) as? ImageView
    private val imageView3: ImageView?
        get() = findViewById<ImageView>(R.id.image_view_3) as? ImageView
    private val imageView4: ImageView?
        get() = findViewById<ImageView>(R.id.image_view_4) as? ImageView

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        // TODO
    }
}
enum class BrandIcon(val key: Int) {
    TWITTER(1);
    val resourceId: Int
        get() {
            return when (this) {
                TWITTER -> R.string.icon_brand_twitter
            }
        }
    val color: Int
        get() {
            return when (this) {
                TWITTER -> Color.parseColor("#55acee")
            }
        }
}
abstract class FontIconDrawable: Drawable() {
    protected var text: String = ""
    protected val context: Context = App.context
    protected val textPaint: TextPaint = TextPaint()
    protected abstract val typeface: Typeface?
    protected var size: Int = 20
    protected var _alpha: Int = 255
    override fun isStateful(): Boolean {
        return true
    }
    override fun setState(stateSet: IntArray): Boolean {
        val oldValue = textPaint.alpha
        val newValue = if (isEnabled(stateSet)) _alpha else _alpha / 2
        textPaint.alpha = newValue
        return oldValue != newValue
    }
    fun isEnabled(stateSet: IntArray): Boolean {
        for (state in stateSet)
            if (state == android.R.attr.state_enabled)
                return true
        return false
    }
    fun alpha(alpha: Int): FontIconDrawable {
        setAlpha(alpha)
        invalidateSelf()
        return this
    }
    override fun draw(canvas: Canvas) {
        textPaint.textSize = bounds.height().toFloat()
        val textBounds = Rect()
        val textValue = text
        textPaint.getTextBounds(textValue, 0, 1, textBounds)
        val textBottom = (bounds.height() - textBounds.height()) / 2f + textBounds.height() - textBounds.bottom
        canvas.drawText(textValue, bounds.width() / 2f, textBottom, textPaint)
    }
    override fun setAlpha(p0: Int) {
        _alpha = p0
        textPaint.alpha = p0
    }
    override fun getOpacity(): Int {
        return PixelFormat.OPAQUE
    }
    override fun setColorFilter(p0: ColorFilter?) {
        textPaint.colorFilter = p0
    }
    override fun getIntrinsicHeight(): Int {
        return size
    }
    override fun getIntrinsicWidth(): Int {
        return size
    }
    protected fun update() {
        textPaint.typeface = typeface
        textPaint.textSize = size.toFloat()
        textPaint.style = Paint.Style.FILL_AND_STROKE
        textPaint.textAlign = Paint.Align.CENTER
        textPaint.isUnderlineText = false
        textPaint.isAntiAlias = true
        setBounds(0, 0, size, size)
        invalidateSelf()
    }
}
class BrandIconDrawable: FontIconDrawable() {
    override val typeface: Typeface? = CachedTypeFaces.get(context, "fa-brands-400.ttf")
    companion object {
        fun create(context: Context, brand: BrandIcon, size: Int): BrandIconDrawable {
            val drawable = BrandIconDrawable()
            drawable.text = context.getString(brand.resourceId)
            drawable.size = size
            drawable.update()
            drawable.textPaint.color = brand.color
            return drawable
        }
    }
}
object CachedTypeFaces {
    private val cache = HashMap<String, Typeface>()
    fun get(context: Context, assetPath: String): Typeface? {
        synchronized(cache) {
            try {
                if (!cache.containsKey(assetPath)) {
                    val typeface = Typeface.createFromAsset(context.assets, assetPath)
                    cache[assetPath] = typeface
                    return typeface
                }
            } catch (e: Exception) {
                return null
            }
            return cache[assetPath]
        }
    }
}

Day4

(8)下記の各データを保存するとき、どのような手法を用いて要件を満たせば良いか、その理由も含めて説明してください。

① アプリのインストール後チュートリアルの閲覧が完了したかどうかのフラグ

② マスターデータ

③ ユーザーまたはアプリ運営者が継続的に投稿しているコンテンツ

④ ③のコンテンツのキャッシュ

(9)以下の要件を満たすデータ群を、enumを用いて実際のコードで書いてください。

  • 名前はGenderとすること
  • 「ID」はenumを定義した時点でプロパティアクセスできるようにすること
  • nameプロパティを呼ぶことで「名前」を呼び出せること
  • convert()関数を呼ぶことで、「男性」の場合は「女性」、「女性」の場合は「男性」、「不明」の場合は「不明」のenum変数を返すようにすること
  • 値の仕様は以下のテーブルの通り
男性 女性 不明
ID 1 2 0
名前 男性 女性 不明
// TODO : ここにコードを記述してください

(10)以下のURLのJSONをdata classに直したコードを書いてください。data classが複数ある際、それぞれの役割について簡単な説明をコメントで入れてください。

http://cs367.xbit.jp/~w065038/app/winas/list-with-error-code.json

// TODO : ここにコードを記述してください

(11)データの取得と加工を、それが必要とする箇所(Activity側など)ではなく、仲介クラスやメソッド(講座ではRepositoryという名前をつけたクラスを使った)を使って行ったほうが良い理由をわかりやすく説明してください。

(12)以下の要件を満たすデータをAndroidXのRoomでローカル保存するために必要なコードを「すべて」書いてください。

  • データ名 Content、パラメータは以下を持つものとする
  • データの保存と取得のためのコードも書くこと(呼び出すだけで処理できるように)
パラメータ名 Roomのカラム名
id Int id
name String name
genderId Int gender_id
// TODO : ここにコードを記述してください

(13)サーバAPIからJSONデータを取得して、モデルクラスの形で呼び出し元まで返す過程を、準備のための実装フローも含めて、箇条書きでできるだけ詳しく、ロジックフローで説明してください。なお、ライブラリはRetrofit, OkHttp, Moshiを使うものとします。

例: Step1: XXクラスをXXライブラリの仕様に沿うよう、XXする。
   Step2: XXデータをXXライブラリのXXメソッドを使ってXXする。

Day5

(14)複数の異なる型を持つデータ群を1つの配列で持ちたいとする。それらのデータをサーバAPIから取得した場合、どのように実装をすればいいのか、MoshiのPolymorphicJsonAdapterFactoryを使って、以下のコードのTODO箇所を埋める形でコードを書いてください。

  • APIのURLはこちらから http://cs367.xbit.jp/~w065038/app/winas/day5/list-adr.json
val apiInterface = Retrofit
    .Builder()
    .addConverterFactory(
        MoshiConverterFactory.create(
            Moshi.Builder()
                // TODO
                .add(KotlinJsonAdapterFactory())
                .build()
        )
    )
    .addCallAdapterFactory(CoroutineCallAdapterFactory())
    .client(createOkHttpClient())
    .baseUrl("http://cs367.xbit.jp/~w065038/app/winas/day5/")
    .build()
    .create(SampleApiService::class.java)
data class Restaurant(
    var id: Int = 0,
    var name: String = ""): Feedable {}
data class Hospital (
    var id: Int = 0,
    var name: String = ""): Feedable {}
enum class FeedContentType(val index: String) {
    Hospital("hospital"), Restraunt("restaurant")
}
interface Feedable {
    val feedContentType: FeedContentType
}
interface SampleApiService {
    // TODO: 任意のサンプル用APIを定義すること
}
fun getList(
    completion: (contents: List</* TODO */>) -> Unit,
    failure: () -> Unit
    ) {
    // TODO: ここで実際にAPIを呼んでデータに変換する
}
getList(
    completion = { contents ->
        // TODO: ここで結果が返るようにする
    }, failure = {
        // do nothing
    }
)

(15)あるカスタムビュークラスが、プロパティのデータの型によって異なる表示を行うものとします。その際、ジェネリクスを使った場合の実装、使わない場合の実装のコード例を、以下のコードを埋める形でそれぞれ書いてください。

data class Dog(
    override var id: Int = 0,
    override var name: String = "いぬ🐶"): Animal {}
data class Cat(
    override var id: Int = 0,
    override var name: String = "ねこ🐱"): Animal {}
interface Animal {
    val id: Int
    val name: String
}
class SampleCustomView: FrameLayout {
    var data: ??? // TODO: 型名、textViewに`name`を表示させること
    private val textView: TextView?
        get() = findViewById<TextView>(R.id.text_view) as? TextView
}

(16)あるActivityが、プロパティに指定されたモデルデータに基づいてUIを構築・表示する役割を持っていた場合について考えます。

① その「モデルデータ」がnullになるケースとしてどのようなケースが考えられるか。わかりやすく説明してください。

② モデルデータがnullであった場合、どのようにして代替処理を行うか、以下のコードのTODO箇所を埋める形でコードを書いてください。

data class Content(
    var id: Int = 0,
    var text: String = ""
)
class ContentActivity : Activity() {
    companion object {
        private const val EXTRA_CONTENT = "EXTRA_CONTENT"
        private const val EXTRA_CONTENT_ID = "EXTRA_CONTENT_ID"
    }
    private var content: Content by Delegates.observable(Content()) { _, _, _ ->
        updateView()
    }
    
    private val textView: TextView?
        get() = findViewById<TextView>(R.id.text_view) as? TextView
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_content)
        // TODO : contentを取得してnullの場合の代替処理
    }
    // TODO : contentが設定されない場合の代替処理
}
class ContentRepository {
    fun getContent(
        contentId: Int,
        completion: (content: Content) -> Unit,
        failure: () -> Unit
    ) {
        // API通信でのデータ取得処理は省略
        let content = Content()
        content.id = contentId
        content.name = "テストコンテンツ"
        completion(content)
    }
}

Day6

(17)Activityが破棄されてから復元された際に、プロパティ「counter」のデータも復元されるよう、以下のコードに追記する形で実装してください。

class SampleActivity : Activity() {
    private var counter: Int = 0
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
    }
}

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.