[WIL] 2024๋…„ 5์›” ๋„ท์งธ์ฃผ (์‹ฌํ™” ํŒ€ํ”„๋กœ์ ํŠธ ๋งˆ๋ฌด๋ฆฌ ๋ฐ ๋ฐœํ‘œ)
๋ฐ˜์‘ํ˜•

 



 

 

๐Ÿ“… 24๋…„ 5์›” 20์ผ ~ 5์›” 26์ผ

  ์›”์š”์ผ
ํ™”์š”์ผ
์ˆ˜์š”์ผ ๋ชฉ์š”์ผ ๊ธˆ์š”์ผ ๋ฐ ์ฃผ๋ง
์‹ฌํ™” ๊ฐ•์˜ ๋ณต์Šต โ–ก ๋ฏธ์„ธ๋จผ์ง€์•ฑ        
๊ณผ์ œ ํ•ด์„ค   โ–ก ๊ณผ์ œ ํ•ด์„ค ์ˆ˜๊ฐ•      
ํŒ€ ํ”„๋กœ์ ํŠธ โ–  ์ถ”๊ฐ€ ๊ธฐ๋Šฅ ๊ตฌํ˜„
- MVC -> MVVM
- DataStore
โ–  ์ถ”๊ฐ€ ๊ธฐ๋Šฅ ๊ตฌํ˜„
   ๋ฐ ๋งˆ๋ฌด๋ฆฌ
- UI ๋งˆ๋ฌด๋ฆฌ
- ์˜ค๋ฅ˜ ์ˆ˜์ •
โ–  ์ตœ์ข… ๋จธ์ง€
โ–  ๋ฐœํ‘œ ์ค€๋น„
โ–  ๋ฐœํ‘œ ์ค€๋น„ โ–  ๋ฐœํ‘œ ๋ฐ ๋งˆ๋ฌด๋ฆฌ
๋ฒ ์ด์ง๋ฐ˜ ๊ฐ•์˜
    โ–  ์ด์ „ ๊ฐ•์˜ ์ˆ˜๊ฐ•
   (1/2/3๊ฐ•)
โ–  ๋ฒ ์ด์ง๋ฐ˜ 9ํšŒ์ฐจ
   (Retrofit)
 
Joyce ์„œ์  ๋…ํ•™   โ–ก TodoList ์ œ์ž‘
   (Room)
โ–ก ๋ฏธ์„ธ๋จผ์ง€ V1.0 โ–ก ๋ฏธ์„ธ๋จผ์ง€ V2.0 โ–ก ๋ฏธ์„ธ๋จผ์ง€ V3.0
์‹ฌํ™” ๋ชฉํ‘œ
 - KIA ๊ฐœ๋… ํ›‘๊ธฐ
 - Android Developer ์ฝ๊ธฐ
 - ๊ฐœ์ธํ”„๋กœ์ ํŠธ UI ๊ตฌํ˜„
 - ์ง€๋‚œ ํ”„๋กœ์ ํŠธ ์ฝ”๋“œ ๋œฏ์–ด๋ณด๊ธฐ
 - ๋งํฌ ์ˆ˜๊ฐ•
 - ์บ ํ”„ ๊ณต์‹ ๊ต์œก์ด ๋๋‚˜๊ณ  ๋‚˜๋ฉด, ์ฑŒ๋ฆฐ์ง€/์Šคํƒ ๋‹ค๋“œ ์ฐจ๋ก€๋กœ ์ˆ˜๊ฐ•ํ•˜๊ธฐ
 - ์ •์ฐฝ๊ฒฝ ์ •๋ฆฌ

 

 

 

 


 

 


1. ํŒ€ ํ”„๋กœ์ ํŠธ : DataStore๋กœ ์œ ์ € ์ด๋ฆ„ ์ €์žฅ ๊ตฌํ˜„ํ•˜๊ธฐ

 

 

Preferences Datastore๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ž‘์—…ํ•˜๊ธฐ  |  Android Developers

์ด Codelab์—์„œ๋Š” ์ƒ˜ํ”Œ ์•ฑ์„ ์ˆ˜์ •ํ•˜์—ฌ SharedPreferences๋ฅผ ๋Œ€์ฒดํ•˜๋Š” ์ƒˆ๋กœ์šด ํ–ฅ์ƒ๋œ ๋ฐ์ดํ„ฐ ์ €์žฅ์†Œ ์†”๋ฃจ์…˜์ธ Jetpack Preferences Datastore๋ฅผ ํ†ตํ•ฉํ•ฉ๋‹ˆ๋‹ค.

developer.android.com

  • 1. Gradle ์„ค์ •
  • 2. Datastore ์„ค์ • (UserPreferences.kt)
    DataStore๋ฅผ ์ด์šฉํ•˜์—ฌ ์‚ฌ์šฉ์ž ์ด๋ฆ„์„ ์ €์žฅํ•˜๊ณ  ๋ถˆ๋Ÿฌ์˜ฌ ์ˆ˜ ์žˆ๋„๋ก ์„ค์ •
  • 3. Fragment ์„ค์ • (MyVideoFragment.kt์—์„œ UI ๊ตฌ์„ฑ, ์ •๋ณด ์—…๋ฐ์ดํŠธ)
    ํ…์ŠคํŠธ๋ทฐ๋ฅผ ํด๋ฆญํ•˜๋ฉด ๋‹ค์ด์–ผ๋กœ๊ทธ๋ฅผ ๋„์›Œ ์‚ฌ์šฉ์ž๊ฐ€ ์ด๋ฆ„์„ ์ž…๋ ฅํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•˜๊ธฐ

 

 

(1) build.gradle ์„ค์ •

build.gradle

implementation ("androidx.datastore:datastore-preferences-android:1.1.1")

 

 

(2) Datastore ์„ค์ • (UserPreferences.kt)

UserPreferences.kt


// preferenceDataStore(name = "") ๋ฐ์ดํ„ฐ์Šคํ† ์–ด ์„ค์ • ๋ฐ ์ด๋ฆ„ ์„ค์ •
val Context.dataStore by preferencesDataStore(name = "user_prefs")

// DataStore๋ฅผ ํ†ตํ•ด ์ €์žฅ ๋ฐ ๋ถˆ๋Ÿฌ์˜ค๋Š” ๊ธฐ๋Šฅ
class UserPreferences(context: Context) {
    private val dataStore = context.dataStore // ์•ž์—์„œ ์ •์˜ํ•œ DataStore ์‚ฌ์šฉ

    companion object { // ํด๋ž˜์Šค์˜ ๋ชจ๋“  ์ธ์Šคํ„ด์Šค์—์„œ USER_NAME_KEY ๊ณตํ†ต์œผ๋กœ ์‚ฌ์šฉ๊ฐ€๋Šฅํ•˜๋„๋ก ์„ ์–ธ
        val USER_NAME_KEY = stringPreferencesKey("user_name")
    }

    val userNameFlow = dataStore.data
        .catch { exception -> // IO ์˜ˆ์™ธ ์‹œ ๋นˆ ๊ธฐ๋ณธ์„ค์ • ๋ฐ˜ํ™˜, ๊ธฐํƒ€ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ
            if (exception is IOException) {
                emit(emptyPreferences())
            } else {
                throw exception
            }
        }
        .map { preferences -> // DataStore์—์„œ ์ฝ์€ ๋ฐ์ดํ„ฐ๋ฅผ ์›ํ•˜๋Š” ํ˜•์‹์œผ๋กœ ๋ณ€ํ™˜
            preferences[USER_NAME_KEY] ?: "์•„๋ฌด๊ฐœ๋‹˜!"
        }

    suspend fun updateUserName(name: String) { // ๋น„๋™๊ธฐ ์‹คํ–‰์„ ์œ„ํ•œ suspend fun
        dataStore.edit { preferences -> // DataStore์— ๋ฐ์ดํ„ฐ ์ €์žฅ, preferences๋Š” ํ˜„์žฌ ์ €์žฅ๋œ ๋ฐ์ดํ„ฐ
            preferences[USER_NAME_KEY] = name + "๋‹˜!"
        }
    }
}

 

 

(3) Fragment ์„ค์ • (MyVideoFragment.kt์—์„œ UI ๊ตฌ์„ฑ, ์ •๋ณด ์—…๋ฐ์ดํŠธ)

class MyVideoFragment : Fragment() {
	...
    
    // userPreferences ์ดˆ๊ธฐํ™”
    private val userPreferences by lazy {
        UserPreferences(requireContext())
    }
	...

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        
        binding.myIdTv.setOnClickListener {
            showEditNameDialog()
        }
        observeUserName()
        
    }
	
    // ํ…์ŠคํŠธ ํด๋ฆญ ์‹œ ๋‚˜์˜ฌ ๋‹ค์ด์–ผ๋กœ๊ทธ ์ƒ์„ฑ
    private fun showEditNameDialog() {
        val editText = EditText(requireContext()).apply {
            hint = "์ด๋ฆ„์„ ์ž…๋ ฅํ•˜์„ธ์š”"
        }

        AlertDialog.Builder(requireContext())
            .setTitle("์ด๋ฆ„์„ ์ˆ˜์ •ํ•ด์š”")
            .setView(editText)
            .setPositiveButton("์ €์žฅํ•ด์š”") { dialog, _ ->
                val newName = editText.text.toString()
                saveUserName(newName)
                dialog.dismiss()
            }
            .setNegativeButton("์ทจ์†Œํ•ด์š”") { dialog, _ ->
                dialog.dismiss()
            }
            .show()
    }

    private fun saveUserName(newName: String) {
        lifecycleScope.launch { // ์ฝ”๋ฃจํ‹ด ๋น„๋™๊ธฐ
            userPreferences.updateUserName(newName) 
        }

    }
    
    private fun observeUserName() {
        lifecycleScope.launch { // ์ฝ”๋ฃจํ‹ด ๋น„๋™๊ธฐ
            userPreferences.userNameFlow.collect { userName -> // DataStore์—์„œ ์ด๋ฆ„์ด ๋ณ€๊ฒฝ๋  ๋•Œ๋งˆ๋‹ค ๊ฐ์ง€ํ•˜๊ณ  ๋ทฐ์— ์—…๋ฐ์ดํŠธ
                binding.myIdTv.text = userName
            }
        }
    }

...

 

 

(4) ๋‹ค์ด์–ผ๋กœ๊ทธ ์ปค์Šคํ…€

dialog_username.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginLeft="50dp"
    android:layout_marginRight="50dp"
    android:background="@drawable/bg_btn_dialog_cancel"
    android:padding="20dp">

    <TextView
        android:id="@+id/tv_username_title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="7dp"
        android:fontFamily="@font/gangwonmodubold"
        android:text="์ด๋ฆ„์„ ๋ณ€๊ฒฝํ•ด๋ณด์„ธ์š”!"
        android:textSize="25sp"
        app:layout_constraintBottom_toTopOf="@+id/et_edit_username"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <EditText
        android:id="@+id/et_edit_username"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginLeft="20dp"
        android:layout_marginTop="10dp"
        android:layout_marginRight="20dp"
        android:backgroundTint="#F3F3F3"
        android:ellipsize="end"
        android:fontFamily="@font/gangwonmodubold"
        android:singleLine="true"
        android:hint="๋ณ€๊ฒฝํ•  ์ด๋ฆ„์„ ์ž…๋ ฅํ•˜์„ธ์š”"
        android:inputType="text"
        android:textColor="@color/grey88"
        android:textSize="25sp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/tv_username_title" />

    <androidx.appcompat.widget.AppCompatButton
        android:id="@+id/btn_username_confirm"
        style="@style/Widget.AppCompat.Button.Borderless"
        android:layout_width="125dp"
        android:layout_height="46dp"
        android:layout_marginTop="20dp"
        android:layout_marginBottom="5dp"
        android:background="@drawable/bg_btn_dialog_confirm"
        android:fontFamily="@font/gangwonmodubold"
        android:text="ํ™•์ธ"
        android:textColor="@color/white"
        android:textSize="18sp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@+id/btn_username_cancel"
        app:layout_constraintTop_toBottomOf="@+id/et_edit_username" />

    <androidx.appcompat.widget.AppCompatButton
        android:id="@+id/btn_username_cancel"
        style="@style/Widget.AppCompat.Button.Borderless"
        android:layout_width="125dp"
        android:layout_height="46dp"
        android:layout_marginTop="20dp"
        android:layout_marginBottom="5dp"
        android:background="@drawable/bg_rv_searchitem"
        android:fontFamily="@font/gangwonmodubold"
        android:text="์ทจ์†Œ"
        android:textColor="@color/primary_yellow"
        android:textSize="18sp"
        app:layout_constraintEnd_toStartOf="@+id/btn_username_confirm"
        app:layout_constraintHorizontal_chainStyle="spread"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/et_edit_username" />

</androidx.constraintlayout.widget.ConstraintLayout>
showEditNameDialog ํ•จ์ˆ˜ ์ˆ˜์ •

    private fun showEditNameDialog() {
        val dialogBinding = DialogUsernameBinding.inflate(layoutInflater) // ๋ฐ”์ธ๋”ฉ์œผ๋กœ ๊ตฌํ˜„
        val dialog = AlertDialog.Builder(requireContext())
            .setView(dialogBinding.root)
            .create()

        dialog.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))

        dialogBinding.btnUsernameConfirm.setOnClickListener {
            val newName = dialogBinding.etEditUsername.text.toString()
            saveUserName(newName)
            dialog.dismiss()
        }

        dialogBinding.btnUsernameCancel.setOnClickListener {
            dialog.dismiss()
        }

        dialog.show()
    }
  • ์ปค์Šคํ…€ ๋””์ž์ธ์„ ๊ตฌํ˜„ํ•˜๊ธฐ ์œ„ํ•ด ๋‹ค์ด์–ผ๋กœ๊ทธ ๋นŒ๋” ๋ฉ”์†Œ๋“œ๋ฅผ ์ˆ˜์ •ํ•œ๋‹ค.
  • ๋ฐ”์ธ๋”ฉ์ด ํŽธํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋ฐ”์ธ๋”ฉ์„ ์—ฐ๊ฒฐํ•ด์ฃผ์–ด ์‚ฌ์šฉํ–ˆ๋‹ค.

 

 

 

 


 

2. ํŒ€ ํ”„๋กœ์ ํŠธ : ํ”„๋กœ์ ํŠธ ์ „์ฒด์ ์ธ UI ์ˆ˜์ • ์ž‘์—…

 

  • ๋ชจ๋“  ํ•„์ˆ˜ ๊ธฐ๋Šฅ ๊ตฌํ˜„์ด ๋๋‚˜๊ณ ๋‚˜์„œ, ์Šคํƒ€์ผ์ด ๋‹ค๋ฅด๊ฒŒ ๊ตฌํ˜„๋œ ์ „์ฒด์ ์ธ UI๋ฅผ ์ˆ˜์ •ํ•˜์˜€๋‹ค.
  • ์ˆ˜์ • ๋ชฉ๋ก
    - HomeFragment ๋ฐ ๋ฆฌ์‚ฌ์ดํด๋Ÿฌ๋ทฐ ์•„์ดํ…œ, ์Šคํ”ผ๋„ˆ
    - DetailFragment
    - SearchFragment ๋ฐ ๋ฆฌ์‚ฌ์ดํด๋Ÿฌ๋ทฐ ์•„์ดํ…œ
    - MyFragment ๋ฐ ๋ฆฌ์‚ฌ์ดํด๋Ÿฌ๋ทฐ ์•„์ดํ…œ

 

 

๐Ÿ”จ HomeFragment

 

์™ผ์ชฝ ๋””์ž์ธ โ–ถ ์˜ค๋ฅธ์ชฝ ๋””์ž์ธ์œผ๋กœ ์ˆ˜์ •

  • ๋‹ค์–‘ํ•œ ๋ ˆ์ด์•„์›ƒ ์ˆ˜์ •
    • LinearLayout์œผ๋กœ ์„ค์ •๋˜์–ด ์žˆ๋˜ ๊ฒƒ ๋‹ค์ˆ˜ Constraint๋กœ ๋ณ€๊ฒฝ
    • ๊ฐ ์š”์†Œ๋งˆ๋‹ค์˜ margin ๋ฐ ์—ฐ๊ฒฐ ๊ตฌ์กฐ ์žฌ์ˆ˜์ •

 

(1) ์ƒ๋‹จ ์•„์ด์ฝ˜ ๋ฒกํ„ฐ(SVG) ์ˆ˜์ •

  • png๋กœ ์ ์šฉ๋˜๋˜ ์•„์ด์ฝ˜์„ ๋ฒกํ„ฐ๋กœ ์ˆ˜์ •

 

  • ๋ฒกํ„ฐ๋กœ ๋“ฑ๋กํ•  ์ˆ˜ ์—†๋Š” ํ…์ŠคํŠธ ๋กœ๊ณ ๋Š” PNG๋กœ ๋“ฑ๋กํ•˜๋ฉด์„œ, ํ•ด์ƒ๋„ ๊นจ์ง€์ง€ ์•Š๊ฒŒ wrap_content ์ฒ˜๋ฆฌ

 

 

(2) Background.xml ์ƒ์„ฑ ๋ฐ ์ ์šฉ

 

bg_fragment_home.xml

<?xml version ="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">

    <gradient
        android:angle="270"
        android:startColor="#FFC00A"
        android:centerColor="#FFEDBA"
        android:endColor="#FFFAEB"
        android:centerX="0.1"
         />

</shape>
  • ๊ธฐ์กด์— ์ด๋ฏธ์ง€๋กœ ๋”ฐ๋กœ๋”ฐ๋กœ ์ ์šฉ๋˜๋˜ ๋ฐฐ๊ฒฝ์„ ํ•˜๋‚˜์˜ ๊ทธ๋ผ๋””์–ธํŠธ๋กœ ์„ค์ •ํ•œ background.xml ์ƒ์„ฑ
  • centerX๋กœ centerColor์˜ ์‹œ์ž‘์  ์ง€์ •

 

 

(3) Bottom Navigation ์ˆ˜์ •

  • height๊ฐ€ 70dp๋กœ ์„ค์ •๋˜์–ด ์žˆ๋˜ ๊ฒƒ(์™ผ์ชฝ)์„ wrap_content๋กœ ์ˆ˜์ •ํ•˜์—ฌ ์ •์ƒ์ ์œผ๋กœ ์ถœ๋ ฅ๋˜๋„๋ก ์ˆ˜์ •(์˜ค๋ฅธ์ชฝ)

 

  • ์™ผ์ชฝ ์‚ฌ์ง„์ฒ˜๋Ÿผ ํด๋ฆญ ์‹œ ์ƒ๊ธฐ๋˜ ํšŒ์ƒ‰ ์• ๋‹ˆ๋ฉ”์ด์…˜ ์‚ญ์ œ (ItemRippleColor๋ฅผ ํˆฌ๋ช…์œผ๋กœ ์„ค์ •)

 

 

(4) ๋ฆฌ์‚ฌ์ดํด๋Ÿฌ๋ทฐ ๊ฐ ์•„์ดํ…œ ๋งˆ๋‹ค ์„ค์ •

  • ๋‹จ์ˆœํ•˜๊ฒŒ ImageView๋กœ ํ‘œ์‹œ๋œ ๊ฒƒ๋“ค์„ ๋ชจ๋‘ ์นด๋“œ๋ทฐ ํ˜•ํƒœ๋กœ ์ˆ˜์ •
  • ๊ฐ ์•„์ดํ…œ์„ Figma ๊ธฐ๋ณธ ์„ค๊ณ„์— ๋งž๊ฒŒ ์ƒ‰์ƒ/๋งˆ์ง„/๋ ˆ์ด์•„์›ƒ/ํฐํŠธ ๋“ฑ ๋ชจ๋‘ ์ˆ˜์ •
  • maxWidth ์•„์ดํ…œ์— ๋งž๊ฒŒ ์ˆ˜์ •

 

(5) Spinner ๋””์ž์ธ ์„ค์ •

 

 

[์•ˆ๋“œ๋กœ์ด๋“œ] ์ปค์Šคํ…€ ์Šคํ”ผ๋„ˆ ๋งŒ๋“ค๊ธฐ

์œ„์™€ ๊ฐ™์€ ๊ทธ๋ฆผ์˜ ์ปค์Šคํ…€ ์Šคํ”ผ๋„ˆ๋ฅผ ๋งŒ๋“ค์–ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ํ™”์‚ดํ‘œ ๋ชจ์–‘์„ ์•„์ด์ฝ˜์œผ๋กœ ํ•˜๋Š” layer-list๋ฅผ ๋งŒ๋“ค์–ด drawble ํด๋”์— ์ถ”๊ฐ€ํ•ด์ค๋‹ˆ๋‹ค. spinner_custom.xml color, icon, margin dp๋“ฑ์„ ์ ์ ˆํžˆ ์กฐ์ ˆํ•ด ์ค๋‹ˆ๋‹ค

ddangeun.tistory.com

 

 

(6) CustomDialog

    override fun onBackPressed() {
        val dialogView = LayoutInflater.from(this).inflate(R.layout.dialog, null)
        val builder = AlertDialog.Builder(this)
        builder.setView(dialogView)
            .setCancelable(false)

        val alertDialog = builder.create()

        // ๋‹ค์ด์–ผ๋กœ๊ทธ ๋‚ด๋ถ€์˜ ๋ฒ„ํŠผ ์ดˆ๊ธฐํ™” ๋ฐ ํด๋ฆญ ์ด๋ฒคํŠธ ์„ค์ •
        dialogView.findViewById<AppCompatButton>(R.id.btn_confirm).setOnClickListener {
            alertDialog.dismiss()
            super.onBackPressed()  // ํ™•์ธ ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด ์•ฑ ์ข…๋ฃŒ
        }

        dialogView.findViewById<AppCompatButton>(R.id.btn_cancel).setOnClickListener {
            alertDialog.dismiss()  // ์ทจ์†Œ ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด ๋‹ค์ด์–ผ๋กœ๊ทธ ๋‹ซ๊ธฐ
        }

        alertDialog.show()
    }

 

 

๐Ÿ”จ DetailFragment

 

  • ํฐํŠธ ๋ณ€๊ฒฝ
  • API๋กœ ๋ถˆ๋Ÿฌ์˜ค๋Š” Thumbnail์˜ ํ•ด์ƒ๋„๊ฐ’ ๋ณ€๊ฒฝ

 

 

 

๐Ÿ”จ SearchFragment 

  • ์ €๋ฒˆ์ฃผ WIL์— ์ž‘์„ฑ ์™„๋ฃŒ

 

 

 

 

๐Ÿ”จ MyVideoFragment

 

UI ๋ณ€ํ™” ๊ณผ์ •

  • background src ์ˆ˜์ •
  • ๋ฆฌ์‚ฌ์ดํด๋Ÿฌ๋ทฐ ์•„์ดํ…œ ์ˆ˜์ •
  • ๊ฐ์ข… Margin, layout ์žฌ์„ค์ •

 

์ตœ์ข… UI

 

 

 

 

 


 

3. ํŒ€ ํ”„๋กœ์ ํŠธ : ๋„ค๋น„๊ฒŒ์ด์…˜ ์ด๋™ ์ˆ˜์ •, ๊ฐ์ข… ํŠธ๋Ÿฌ๋ธ”์ŠˆํŒ…

 

 
  • ์ด๋ฒˆ ์ฃผ ๋‚ด๋‚ด ๋‹ค์–‘ํ•œ ํ˜•ํƒœ์˜ ํŠธ๋Ÿฌ๋ธ”์„ ๊ฒช๊ณ , ๊ทธ๊ฑธ ํ•ด๊ฒฐํ•˜๋Š” ๊ณผ์ •์„ ๊ฑฐ์ณค๋‹ค.
  • ํŒ€ ๋…ธ์…˜ ๋ฐ GitHub Repository์— ์œ„ํ‚ค๋กœ ๋ชจ๋‘ ์ž‘์„ฑ๋˜์–ด ์žˆ์œผ๋ฏ€๋กœ ๋ธ”๋กœ๊ทธ์— ๋”ฐ๋กœ ์ ์ง„ ์•Š๊ฒ ๋‹ค.

 

 

 

 

 


 

4. ํŒ€ ํ”„๋กœ์ ํŠธ : ๋ฐœํ‘œ ๋ฐ ๋งˆ๋ฌด๋ฆฌ

 

 

  • ํŒ€์›๋“ค๊ณผ ํ•จ๊ป˜ ์ดˆ๊ธฐ ์™€์ด์–ดํ”„๋ ˆ์ž„ ์ˆ˜์ • ๋ฐ PPT๋ฅผ ์ œ์ž‘ํ–ˆ๋‹ค.

 

 

  • ํ”„๋กœ์ ํŠธ๊ฐ€ ์ž˜ ๋งˆ๋ฌด๋ฆฌ ๋ผ์„œ ๊ธฐ๋ถ„์ด ์ข‹๋‹ค.
  • ์ด๋ฒˆ ํŒ€์ด ์†Œํ†ต์ด ์ž˜ ๋˜๊ณ  ์„œ๋กœ์„œ๋กœ ์•Œ๋ ค์ฃผ๋ฉด์„œ ํ•ด์„œ, ์ฝ”๋“œ์— ๋Œ€ํ•œ ์ดํ•ด๋„๊ฐ€ ๋งค์šฐ ๋†’์•„์กŒ๋‹ค.

 

 

 

 

 


 

5. ๋ฒ ์ด์ง ๋งˆ์ง€๋ง‰ ๊ฐ•์˜

 

 

์•ฑ ์•„ํ‚คํ…์ฒ˜ ๊ฐ€์ด๋“œ  |  Android Developers

์ด ํŽ˜์ด์ง€๋Š” Cloud Translation API๋ฅผ ํ†ตํ•ด ๋ฒˆ์—ญ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์•ฑ ์•„ํ‚คํ…์ฒ˜ ๊ฐ€์ด๋“œ ์ปฌ๋ ‰์…˜์„ ์‚ฌ์šฉํ•ด ์ •๋ฆฌํ•˜๊ธฐ ๋‚ด ํ™˜๊ฒฝ์„ค์ •์„ ๊ธฐ์ค€์œผ๋กœ ์ฝ˜ํ…์ธ ๋ฅผ ์ €์žฅํ•˜๊ณ  ๋ถ„๋ฅ˜ํ•˜์„ธ์š”. ์ด ๊ฐ€์ด๋“œ์—๋Š” ๊ณ ํ’ˆ์งˆ์˜ ๊ฐ•๋ ฅํ•œ

developer.android.com

  • guide to app architecture ์ด๊ฑฐ ๋‹ค ์ฝ์ง€ ์•Š์œผ๋ฉด ์•ˆ๋“œ๋กœ์ด๋“œ ๊ฐœ๋ฐœ ์–ด๋””์„œ ํ•œ๋‹ค๊ณ  ๋งํ•˜๋ฉด ์•ˆ๋จ
  • ๋‹จ์ˆœํ•œ ์•ฑ ์•„ํ‚คํ…์ฒ˜๋Š” ํด๋ฆฐ์•„ํ‚คํ…์ฒ˜๊ฐ€ ์•„๋‹˜. ์˜ˆ์‹œ์— ์žˆ๋Š” ๊นƒํ—ˆ๋ธŒ ์ฝ”๋“œ๋‚˜ ์ด๋Ÿฐ ๊ฑฐ ์ฝ์–ด๋ผ
  • data (network-di,model,retrofit,source / repository)
  • domain(di, model, repository-์ธํ„ฐํŽ˜์ด์Šค๋กœ ๊ตฌํ˜„, ์‹ค์ œ ์ž‘์—…์€ data์˜ repository, usecase)
  • ๋ฌธ์„œ์— Dependency injection(์˜์กด์„ฑ ์ฃผ์ž…) ๋„ ๋‹ค ์žˆ์œผ๋‹ˆ๊นŒ ๋‹ค ์ฝ๊ธฐ.
    ์ต์ˆ™ํ•ด์ง€๊ธฐ ์œ„ํ•ด์„œ๋Š” ๋ฐ˜๋ณต ์ˆ™๋‹ฌ๋กœ ์ด๋Ÿฐ ๊ฒŒ ์žˆ๊ตฌ๋‚˜ ํ•˜๊ณ  ๊ณ„์† ์ฝ์–ด์•ผ ํ•จ
  • ์—ฐ์Šตํ•˜๊ธฐ API : CATAAS.com
  • ๋ชจ๋“  API๋Š” Docs๋ฅผ ์ฐธ์กฐํ•ด์•ผ ํ•จ

 

 

 

 

๐Ÿ’ญ Retrospect

์ด๋ฒˆ ํŒ€ํ”„๋กœ์ ํŠธ๋ฅผ ํ•˜๋ฉด์„œ ๋งŽ์€ ๋ถ€๋ถ„์—์„œ ์„ฑ์žฅํ•œ ๊ฒƒ ๊ฐ™๋‹ค. ์ €๋ฒˆ์ฃผ์— ๊ณ ๋ฏผํ–ˆ๋˜ ๋ถ€๋ถ„์€ ์ •๋ง ๋ชจ๋‘ ํ•ด๊ฒฐ๋˜์—ˆ๊ณ , ํŒ€ํ”„๋กœ์ ํŠธ์— ๋งŽ์€ ๊ธฐ์—ฌ๋ฅผ ํ•  ์ˆ˜ ์žˆ์—ˆ๊ณ , ์ดํ•ด๋„๋„ ๋งค์šฐ ๋†’์•„์กŒ๋‹ค. ์ด๋ฒˆ ํŒ€๊ณผ ํ•จ๊ป˜ํ•˜๋ฉฐ 'ํŒ€'์ด๋ž€ ๊ฑด ๊ฐœ๊ฐœ์ธ์˜ ์‹ค๋ ฅ๋ณด๋‹ค๋„ ์„œ๋กœ๊ฐ„์˜ ์†Œํ†ตํ•  ์ˆ˜ ์žˆ๋Š” ์—ญ๋Ÿ‰์ด ํ›จ์”ฌ ๋” ์ค‘์š”ํ•œ ๊ฒƒ์ด๋ผ ์ฒด๊ฐํ–ˆ๋‹ค. ๋ฐœํ‘œํ•˜์ž๋งˆ์ž ๋ฐ”๋กœ 6์ฃผ๊ฐ„์˜ ์ตœ์ข… ํ”„๋กœ์ ํŠธ๊ฐ€ ์‹œ์ž‘์ธ๋ฐ, ์ตœ์ข… ๋•Œ๋Š” ์–ผ๋งˆ๋‚˜ ์„ฑ์žฅํ•  ์ˆ˜ ์žˆ์„๊นŒ ๊ธฐ๋Œ€๋œ๋‹ค.

๋งˆ๋ฌด๋ฆฌ ๋๊นŒ์ง€ ์ž˜ํ•˜์ž!

โ€‹

 

 

 

 

๋ฐ˜์‘ํ˜•
 ๐Ÿ’ฌ C O M M E N T