Android
${Harvey}
2022. 11. 28. 09:32
2022. 11. 28. 09:32
plugins {
id 'kotlin-kapt'
}
// ROOM
def roomVersion = "2.4.0"
implementation("androidx.room:room-runtime:$roomVersion")
annotationProcessor("androidx.room:room-compiler:$roomVersion")
// To use Kotlin annotation processing tool (kapt)
kapt("androidx.room:room-compiler:$roomVersion")
// Coroutine
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.0")
// ViewModelScope
implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.1")
}
class Repository(context: Context) {
val db = TextDataBase.getDatabase(context)
fun getTextList() = db.textDao().getAllData()
fun getWordList() = db.wordDao().getAllData()
fun insertTextData(text: String) = db.textDao().insert(TextEntity(0, text))
fun insertWordData(text: String) = db.wordDao().insert(WordEntity(0, text))
fun deleteTextData() = db.textDao().deleteAllData()
fun deleteWordData() = db.wordDao().deleteAllData()
}
class MainViewModel(application: Application) : AndroidViewModel(application) {
val context = getApplication<Application>().applicationContext
val db = TextDataBase.getDatabase(context)
private var _textList = MutableLiveData<List<TextEntity>>()
val textList : LiveData<List<TextEntity>>
get() = _textList
private var _wordList = MutableLiveData<List<WordEntity>>()
val wordList : LiveData<List<WordEntity>>
get() = _wordList
val repository = Repository(context)
fun getData() = viewModelScope.launch(Dispatchers.IO) {
Log.d("MainViewModel",db.textDao().getAllData().toString())
Log.d("MainViewModel",db.wordDao().getAllData().toString())
_textList.postValue(repository.getTextList())
_wordList.postValue(repository.getWordList())
}
fun insertData(text : String) = viewModelScope.launch(Dispatchers.IO) {
repository.insertTextData(text)
repository.insertWordData(text)
}
fun removeData() = viewModelScope.launch (Dispatchers.IO){
repository.deleteTextData()
repository.deleteWordData()
}
}
Dispatcher.IO에서 사용하기위해 postValue를 사용해주어야함.
MainActivity.kt
// ROOM
// https://developer.android.com/training/data-storage/room?hl=ko
// https://developer.android.com/codelabs/android-room-with-a-view-kotlin?hl=ko#5
// https://developer.android.com/kotlin/coroutines/coroutines-adv?hl=ko
class MainActivity : AppCompatActivity() {
lateinit var viewModel : MainViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
viewModel = ViewModelProvider(this).get(MainViewModel::class.java)
viewModel.getData()
val db = TextDataBase.getDatabase(this)
val inputArea = findViewById<EditText>(R.id.textInputArea)
val insertBtn = findViewById<Button>(R.id.insert)
val getAllBtn = findViewById<Button>(R.id.getData)
val deleteBtn = findViewById<Button>(R.id.delete)
insertBtn.setOnClickListener {
viewModel.insertData(inputArea.text.toString())
inputArea.setText("")
}
val rv = findViewById<RecyclerView>(R.id.rv)
viewModel.textList.observe(this, Observer {
val customAdapter = CustomAdapter(it)
rv.adapter = customAdapter
rv.layoutManager = LinearLayoutManager(this)
})
getAllBtn.setOnClickListener {
viewModel.getData()
}
deleteBtn.setOnClickListener {
viewModel.removeData()
}
}
}
class CustomAdapter(private val dataSet : List<TextEntity>) : RecyclerView.Adapter<CustomAdapter.ViewHolder>(){
class ViewHolder(view: View) : RecyclerView.ViewHolder(view){
val textView : TextView = view.findViewById(R.id.textView)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CustomAdapter.ViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.text_row_item,parent,false)
return ViewHolder(view)
}
override fun onBindViewHolder(holder: CustomAdapter.ViewHolder, position: Int) {
holder.textView.text = dataSet[position].text
}
override fun getItemCount(): Int {
return dataSet.size
}
}
@Entity(tableName = "text_table")
data class TextEntity (
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = "id")
var id : Int,
@ColumnInfo(name = "text")
var text: String
)
@Entity(tableName = "word_table")
data class WordEntity (
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = "id")
var id : Int,
@ColumnInfo(name = "text")
var text: String
)
@Database(entities = [TextEntity::class, WordEntity::class], version = 2)
abstract class TextDataBase : RoomDatabase(){
abstract fun textDao() : TextDao
abstract fun wordDao() : WordDao
companion object {
@Volatile
private var INSTANCE : TextDataBase? = null
fun getDatabase(
context : Context
) : TextDataBase {
return INSTANCE ?: synchronized(this){
val instance = Room.databaseBuilder(
context.applicationContext,
TextDataBase::class.java,
"text_database"
)
.fallbackToDestructiveMigration()
.build()
INSTANCE = instance
instance
}
}
}
}
@Dao
interface WordDao {
@Query("SELECT * FROM text_table")
fun getAllData() : List<WordEntity>
@Insert(onConflict = OnConflictStrategy.IGNORE)
fun insert(text : WordEntity)
@Query("DELETE FROM word_table")
fun deleteAllData()
}
@Dao
interface TextDao {
@Query("SELECT * FROM text_table")
fun getAllData() : List<TextEntity>
@Insert(onConflict = OnConflictStrategy.IGNORE)
fun insert(text : TextEntity)
@Query("DELETE FROM text_table")
fun deleteAllData()
}
${Harvey}
2022. 11. 22. 18:03
2022. 11. 22. 18:03
build.gradle
plugins {
id 'kotlin-kapt'
}
// ROOM
def roomVersion = "2.4.0"
implementation("androidx.room:room-runtime:$roomVersion")
annotationProcessor("androidx.room:room-compiler:$roomVersion")
// To use Kotlin annotation processing tool (kapt)
kapt("androidx.room:room-compiler:$roomVersion")
// Coroutine
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.0")
// ViewModelScope
implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.1")
}
class MainViewModel(application: Application) : AndroidViewModel(application) {
val context = getApplication<Application>().applicationContext
val db = TextDataBase.getDatabase(context)
fun getDate() = viewModelScope.launch(Dispatchers.IO) {
Log.d("MainViewModel",db.textDao().getAllData().toString())
Log.d("MainViewModel",db.wordDao().getAllData().toString())
}
fun insertData(text : String) = viewModelScope.launch(Dispatchers.IO) {
db.textDao().insert(TextEntity(0,text))
db.wordDao().insert(WordEntity(0, text))
}
fun removeData() = viewModelScope.launch (Dispatchers.IO){
db.textDao().deleteAllData()
db.wordDao().deleteAllData()
}
}
class MainActivity : AppCompatActivity() {
lateinit var viewModel : MainViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
viewModel = ViewModelProvider(this).get(MainViewModel::class.java)
viewModel.getDate()
val db = TextDataBase.getDatabase(this)
val inputArea = findViewById<EditText>(R.id.textInputArea)
val insertBtn = findViewById<Button>(R.id.insert)
val getAllBtn = findViewById<Button>(R.id.getData)
val deleteBtn = findViewById<Button>(R.id.delete)
insertBtn.setOnClickListener {
viewModel.insertData(inputArea.text.toString())
inputArea.setText("")
}
getAllBtn.setOnClickListener {
viewModel.getDate()
}
deleteBtn.setOnClickListener {
viewModel.removeData()
}
}
}
@Entity(tableName = "text_table")
data class TextEntity (
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = "id")
var id : Int,
@ColumnInfo(name = "text")
var text: String
)
@Entity(tableName = "word_table")
data class WordEntity (
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = "id")
var id : Int,
@ColumnInfo(name = "text")
var text: String
)
@Database(entities = [TextEntity::class, WordEntity::class], version = 2)
abstract class TextDataBase : RoomDatabase(){
abstract fun textDao() : TextDao
abstract fun wordDao() : WordDao
companion object {
@Volatile
private var INSTANCE : TextDataBase? = null
fun getDatabase(
context : Context
) : TextDataBase {
return INSTANCE ?: synchronized(this){
val instance = Room.databaseBuilder(
context.applicationContext,
TextDataBase::class.java,
"text_database"
)
.fallbackToDestructiveMigration()
.build()
INSTANCE = instance
instance
}
}
}
}
@Dao
interface WordDao {
@Query("SELECT * FROM text_table")
fun getAllData() : List<WordEntity>
@Insert(onConflict = OnConflictStrategy.IGNORE)
fun insert(text : WordEntity)
@Query("DELETE FROM word_table")
fun deleteAllData()
}
@Dao
interface TextDao {
@Query("SELECT * FROM text_table")
fun getAllData() : List<TextEntity>
@Insert(onConflict = OnConflictStrategy.IGNORE)
fun insert(text : TextEntity)
@Query("DELETE FROM text_table")
fun deleteAllData()
}
${Harvey}
2022. 11. 22. 18:01
2022. 11. 22. 18:01
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val db = TextDataBase.getDatabase(this)
val inputArea = findViewById<EditText>(R.id.textInputArea)
val insertBtn = findViewById<Button>(R.id.insert)
val getAllBtn = findViewById<Button>(R.id.getData)
val deleteBtn = findViewById<Button>(R.id.delete)
insertBtn.setOnClickListener {
CoroutineScope(Dispatchers.IO).launch {
db.textDao().insert(TextEntity(0, inputArea.text.toString()))
db.wordDao().insert(WordEntity(0, inputArea.text.toString()))
inputArea.setText("")
}
}
getAllBtn.setOnClickListener {
CoroutineScope(Dispatchers.IO).launch {
Log.d("MAINACTIVITY", db.textDao().getAllData().toString())
Log.d("MAINACTIVITY", db.wordDao().getAllData().toString())
}
}
deleteBtn.setOnClickListener {
CoroutineScope(Dispatchers.IO).launch {
db.textDao().deleteAllData()
db.wordDao().deleteAllData()
}
}
}
}
@Entity(tableName = "text_table")
data class TextEntity (
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = "id")
var id : Int,
@ColumnInfo(name = "text")
var text: String
)
@Entity(tableName = "word_table")
data class WordEntity (
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = "id")
var id : Int,
@ColumnInfo(name = "text")
var text: String
)
@Database(entities = [TextEntity::class, WordEntity::class], version = 2)
abstract class TextDataBase : RoomDatabase(){
abstract fun textDao() : TextDao
abstract fun wordDao() : WordDao
companion object {
@Volatile
private var INSTANCE : TextDataBase? = null
fun getDatabase(
context : Context
) : TextDataBase {
return INSTANCE ?: synchronized(this){
val instance = Room.databaseBuilder(
context.applicationContext,
TextDataBase::class.java,
"text_database"
)
.fallbackToDestructiveMigration()
.build()
INSTANCE = instance
instance
}
}
}
}
@Dao
interface WordDao {
@Query("SELECT * FROM text_table")
fun getAllData() : List<WordEntity>
@Insert(onConflict = OnConflictStrategy.IGNORE)
fun insert(text : WordEntity)
@Query("DELETE FROM word_table")
fun deleteAllData()
}
@Dao
interface TextDao {
@Query("SELECT * FROM text_table")
fun getAllData() : List<TextEntity>
@Insert(onConflict = OnConflictStrategy.IGNORE)
fun insert(text : TextEntity)
@Query("DELETE FROM text_table")
fun deleteAllData()
}
${Harvey}
2022. 11. 22. 18:00
2022. 11. 22. 18:00
Room은 AAC(Android Architecture Components), 스마트폰 내장 DB에 데이터를 저장하기 쉽도록 해주는 라이브러리이다.(DB데이터를 Java or Kotlin 객체로 매핑 해준다.)
다양한 Annotation을 통해서 컴파일시 코드들을 자동 생성 해주고 SQLite와 달리 LiveData, RxJava와 같은 Obervation 형태를 지원 하고 MVP,MVVM과 같은 아키텍쳐 패턴에 쉽게 활용할 수 있도록 되어있다.
Room 라이브러리의 엔티티(Entity), 데이터 접근 객체(DAO),데이터 베이스(DB)의 상세 설명과 사용법은 구글 공식 문서에도 나와있지만 아래 블로그에서 많이 참고하였다.
https://velog.io/@ryalya/Android-DB-Room이란
plugins {
id 'kotlin-kapt'
}
// ROOM
def roomVersion = "2.4.0"
implementation("androidx.room:room-runtime:$roomVersion")
annotationProcessor("androidx.room:room-compiler:$roomVersion")
// To use Kotlin annotation processing tool (kapt)
kapt("androidx.room:room-compiler:$roomVersion")
// Coroutine, Room을 사용 할때 Coroutine을 사용해야함.
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.0")
// https://developer.android.com/training/data-storage/room?hl=ko
// https://developer.android.com/codelabs/android-room-with-a-view-kotlin?hl=ko#5
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val db = TextDataBase.getDatabase(this)
val inputArea = findViewById<EditText>(R.id.textInputArea)
val insertBtn = findViewById<Button>(R.id.insert)
val getAllBtn = findViewById<Button>(R.id.getData)
val deleteBtn = findViewById<Button>(R.id.delete)
insertBtn.setOnClickListener {
CoroutineScope(Dispatchers.IO).launch {
db.textDao().insert(TextEntity(0, inputArea.text.toString()))
inputArea.setText("")
}
}
getAllBtn.setOnClickListener {
CoroutineScope(Dispatchers.IO).launch {
Log.d("MAINACTIVITY", db.textDao().getAllData().toString())
}
}
deleteBtn.setOnClickListener {
CoroutineScope(Dispatchers.IO).launch {
db.textDao().deleteAllData()
}
}
}
}
@Dao
interface TextDao {
@Query("SELECT * FROM text_table")
fun getAllData() : List<TextEntity>
@Insert(onConflict = OnConflictStrategy.IGNORE)
fun insert(text : TextEntity)
@Query("DELETE FROM text_table")
fun deleteAllData()
}
@Entity(tableName = "text_table")
data class TextEntity (
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = "id")
var id : Int,
@ColumnInfo(name = "text")
var text: String
)
@Database(entities = [TextEntity::class], version = 1)
abstract class TextDataBase : RoomDatabase(){
abstract fun textDao() : TextDao
companion object {
@Volatile
private var INSTANCE : TextDataBase? = null
fun getDatabase(
context : Context
) : TextDataBase {
return INSTANCE ?: synchronized(this){
val instance = Room.databaseBuilder(
context.applicationContext,
TextDataBase::class.java,
"text_database"
)
.fallbackToDestructiveMigration()
.build()
INSTANCE = instance
instance
}
}
}
}
${Harvey}
2022. 11. 22. 17:58
2022. 11. 22. 17:58
SQLite 는 내장 DB이다. 지난 프로젝트에서 SQLite 를 사용하여 이미 익숙하지만 나중을 위해 간단하게 사용법을 남겨 놓을까 한다.
SQLiteHelper.kt
class SQLiteHelperSample(context: Context) : SQLiteOpenHelper(
context, DATABASE_NAME, null,
DATABASE_VERSION
) {
companion object {
private const val DATABASE_VERSION = 1
private const val DATABASE_NAME = "myTestDB.db"
private const val TBL_NAME = "my_table"
private const val ID = "ID"
private const val TITLE = "title"
}
override fun onCreate(db: SQLiteDatabase?) {
val SQL_CREATE_ENTRIES =
"CREATE TABLE $TBL_NAME (" +
"$ID INTEGER PRIMARY KEY," +
"$TITLE TEXT)"
db?.execSQL(SQL_CREATE_ENTRIES)
}
fun insert(str: String) {
val db = this.writableDatabase
val values = ContentValues().apply{
put(TITLE,str)
}
db.insert(TBL_NAME,null,values)
}
fun getAllData(): ArrayList<String> {
val db = this.writableDatabase
val query = "SELECT * FROM $TBL_NAME"
val cursor = db.rawQuery(query,null)
val arr = ArrayList<String>()
with(cursor){
while(moveToNext()){
arr.add(getString(1))
}
}
return arr
}
fun deleteAll(){
val db = this.writableDatabase
db?.execSQL("DROP TABLE IF EXISTS $TBL_NAME")
onCreate(db)
}
//DATABASE VERSION
override fun onUpgrade(db: SQLiteDatabase?, oldVersion: Int, newVersion: Int) {
db?.execSQL("DROP TABLE IF EXISTS $TBL_NAME")
onCreate(db)
}
}
class MainActivity : AppCompatActivity() {
lateinit var db:SQLiteHelperSample
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
db = SQLiteHelperSample(this)
val inputArea = findViewById<EditText>(R.id.inputArea)
val insertBtn = findViewById<Button>(R.id.insert)
val getAllBtn = findViewById<Button>(R.id.getAll)
val resultBtn = findViewById<Button>(R.id.resultArea)
val deleteBtn = findViewById<Button>(R.id.deleteAll)
insertBtn.setOnClickListener {
val inputText = inputArea.text.toString()
db.insert(inputText)
inputArea.setText("")
}
getAllBtn.setOnClickListener {
val arr = db.getAllData()
resultBtn.text = arr.toString()
}
deleteBtn.setOnClickListener {
db.deleteAll()
}
}
override fun onDestroy() {
super.onDestroy()
db.close()
}
}
${Harvey}
2022. 11. 22. 17:56
2022. 11. 22. 17:56
안드로이드 앱 권장 아키텍처에 따라 지난 번에 만든 코드를 수정하였다.
build.gradle
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.1")
implementation 'com.github.bumptech.glide:glide:4.13.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.13.0'
<uses-permission android:name="android.permission.INTERNET"/>
class CustomAdapter(val context :Context, val dataSet : List<Plant>) : RecyclerView.Adapter<CustomAdapter.ViewHolder>() {
class ViewHolder(view : View) : RecyclerView.ViewHolder(view) {
val textView : TextView = view.findViewById(R.id.textArea)
val imageView : ImageView = view.findViewById(R.id.imageArea)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CustomAdapter.ViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.text_row_item, parent, false)
return ViewHolder(view)
}
override fun onBindViewHolder(holder: CustomAdapter.ViewHolder, position: Int) {
holder.textView.text = dataSet[position].name
Glide.with(context)
.load(dataSet[position].imageUrl)
.into(holder.imageView)
}
override fun getItemCount(): Int {
return dataSet.size
}
}
object RetrofitInstance {
val BASE_URL = "https://raw.githubusercontent.com/"
val client = Retrofit
.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build()
fun getInstance() : Retrofit {
return client
}
}
data class Plant (
val plantId : String,
val name : String,
val description : String,
val growZoneNumber : Int,
val wateringInterval : Int,
val imageUrl : String
)
class MainViewModel : ViewModel() {
// val retrofitInstance : MyApi = RetrofitInstance.getInstance().create(MyApi::class.java)
private val repository = Repository()
private val _result = MutableLiveData<List<Plant>>()
val result : LiveData<List<Plant>>
get() = _result
fun getAllData() = viewModelScope.launch {
Log.d("MainViewModel", repository.getAllData().toString())
_result.value = repository.getAllData()
}
}
// https://raw.githubusercontent.com/googlecodelabs/kotlin-coroutines/master/advanced-coroutines-codelab/sunflower/src/main/assets/plants.json
// https://developer.android.com/training/dependency-injection/manual?hl=ko
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val viewModel = ViewModelProvider(this).get(MainViewModel::class.java)
viewModel.getAllData()
val rv = findViewById<RecyclerView>(R.id.rv)
viewModel.result.observe(this, Observer {
val customAdapter = CustomAdapter(this, it)
rv.adapter = customAdapter
rv.layoutManager = LinearLayoutManager(this)
})
}
}
interface MyApi {
@GET("googlecodelabs/kotlin-coroutines/master/advanced-coroutines-codelab/sunflower/src/main/assets/plants.json")
suspend fun getAllPlants() : List<Plant>
}
object RetrofitInstance {
val BASE_URL = "https://raw.githubusercontent.com/"
val client = Retrofit
.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build()
fun getInstance() : Retrofit {
return client
}
}
class Repository {
private val client = RetrofitInstance.getInstance().create(MyApi::class.java)
suspend fun getAllData() = client.getAllPlants()
}
${Harvey}
2022. 11. 22. 17:53
2022. 11. 22. 17:53
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.1")
implementation 'com.github.bumptech.glide:glide:4.13.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.13.0'
<uses-permission android:name="android.permission.INTERNET"/>
class CustomAdapter(val context :Context, val dataSet : List<Plant>) : RecyclerView.Adapter<CustomAdapter.ViewHolder>() {
class ViewHolder(view : View) : RecyclerView.ViewHolder(view) {
val textView : TextView = view.findViewById(R.id.textArea)
val imageView : ImageView = view.findViewById(R.id.imageArea)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CustomAdapter.ViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.text_row_item, parent, false)
return ViewHolder(view)
}
override fun onBindViewHolder(holder: CustomAdapter.ViewHolder, position: Int) {
holder.textView.text = dataSet[position].name
Glide.with(context)
.load(dataSet[position].imageUrl)
.into(holder.imageView)
}
override fun getItemCount(): Int {
return dataSet.size
}
}
interface MyApi {
@GET("googlecodelabs/kotlin-coroutines/master/advanced-coroutines-codelab/sunflower/src/main/assets/plants.json")
suspend fun getAllPlants() : List<Plant>
}
object RetrofitInstance {
val BASE_URL = "https://raw.githubusercontent.com/"
val client = Retrofit
.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build()
fun getInstance() : Retrofit {
return client
}
}
data class Plant (
val plantId : String,
val name : String,
val description : String,
val growZoneNumber : Int,
val wateringInterval : Int,
val imageUrl : String
)
// https://raw.githubusercontent.com/googlecodelabs/kotlin-coroutines/master/advanced-coroutines-codelab/sunflower/src/main/assets/plants.json
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val viewModel = ViewModelProvider(this).get(MainViewModel::class.java)
viewModel.getAllData()
val rv = findViewById<RecyclerView>(R.id.rv)
viewModel.result.observe(this, Observer {
val customAdapter = CustomAdapter(this, it)
rv.adapter = customAdapter
rv.layoutManager = LinearLayoutManager(this)
})
}
}
// https://raw.githubusercontent.com/googlecodelabs/kotlin-coroutines/master/advanced-coroutines-codelab/sunflower/src/main/assets/plants.json
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val viewModel = ViewModelProvider(this).get(MainViewModel::class.java)
viewModel.getAllData()
val rv = findViewById<RecyclerView>(R.id.rv)
viewModel.result.observe(this, Observer {
val customAdapter = CustomAdapter(this, it)
rv.adapter = customAdapter
rv.layoutManager = LinearLayoutManager(this)
})
}
}
${Harvey}
2022. 11. 22. 17:52
2022. 11. 22. 17:52
Retrofit은 서버와 클라이언트 간 http 통신을 위한 라이브러리이다.
즉, Android에서 http 통신을 할 수 있도록 해주는 친구이다.
AndroidManifest.xml
<uses-permission android:name="android.permission.INTERNET"/>
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
// Simple Retrofit Ex
// https://jsonplaceholder.typicode.com/
// https://jsonplaceholder.typicode.com/posts
// https://jsonplaceholder.typicode.com/posts/2
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val api = RetrofitInstance.getInstance().create(MyApi::class.java)
api.getPost1().enqueue(object : Callback<Post> {
override fun onResponse(call: Call<Post>, response: Response<Post>) {
Log.d("API1", response.body().toString())
}
override fun onFailure(call: Call<Post>, t: Throwable) {
Log.d("API1", "fail")
}
})
api.getPostNumber(2).enqueue(object : Callback<Post> {
override fun onResponse(call: Call<Post>, response: Response<Post>) {
Log.d("API2", response.body().toString())
}
override fun onFailure(call: Call<Post>, t: Throwable) {
Log.d("API2", "fail")
}
})
}
}
object RetrofitInstance {
val BASE_URL = "https://jsonplaceholder.typicode.com/"
val client = Retrofit
.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build()
fun getInstance() : Retrofit {
return client
}
}
data class Post (
val userId : Int,
val id : Int,
val title : String,
val body : String
)
interface MyApi {
@GET("posts/1")
fun getPost1() : Call<Post>
@GET("posts/{number}")
fun getPostNumber(
@Path("number") number : Int
) : Call<Post>
}
결과:API로 받아온 정보 두개가 로그에 찍혔다.