본문 바로가기

Android Project

[Android/Kotlin] 커뮤니티앱(4) - 꿀팁 페이지 만들기

# fragment_tip.xml 디자인 

먼저 꿀팁부분 레이아웃을 디자인해줄것이다

맨 마지막줄 한개는 비어있게 해줄것이기 때문에 영역은 그대로 유지해주되, 이미지만 지워준다

<?xml version="1.0" encoding="utf-8"?>
<layout>
    <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        tools:context=".fragments.TipFragment">

        <androidx.constraintlayout.widget.ConstraintLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent">

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_marginBottom="70dp"
                android:orientation="vertical">

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="150dp">

                <ImageView
                    android:id="@+id/category1"
                    android:src="@drawable/main_icon_all"
                    android:layout_weight="1"
                    android:layout_width="120dp"
                    android:layout_height="120dp"/>

                <ImageView
                    android:id="@+id/category2"
                    android:src="@drawable/main_icon_cook"
                    android:layout_weight="1"
                    android:layout_width="120dp"
                    android:layout_height="120dp"/>

                <ImageView
                    android:src="@drawable/main_icon_economy"
                    android:layout_weight="1"
                    android:layout_width="120dp"
                    android:layout_height="120dp"/>

            </LinearLayout>

                <LinearLayout
                    android:layout_width="match_parent"
                    android:layout_height="150dp">

                    <ImageView
                        android:src="@drawable/main_icon_else"
                        android:layout_weight="1"
                        android:layout_width="120dp"
                        android:layout_height="120dp"/>

                    <ImageView
                        android:src="@drawable/main_icon_hobby"
                        android:layout_weight="1"
                        android:layout_width="120dp"
                        android:layout_height="120dp"/>

                    <ImageView
                        android:src="@drawable/main_icon_interior"
                        android:layout_weight="1"
                        android:layout_width="120dp"
                        android:layout_height="120dp"/>

                </LinearLayout>


                <LinearLayout
                    android:layout_width="match_parent"
                    android:layout_height="150dp">

                    <ImageView
                        android:src="@drawable/main_icon_life"
                        android:layout_weight="1"
                        android:layout_width="120dp"
                        android:layout_height="120dp"/>

                    <ImageView
                        android:src="@drawable/main_icon_oneroom"
                        android:layout_weight="1"
                        android:layout_width="120dp"
                        android:layout_height="120dp"/>

                    <ImageView
                        android:layout_weight="1"
                        android:layout_width="120dp"
                        android:layout_height="120dp"/>

                </LinearLayout>







            </LinearLayout>


            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="3dp"
                app:layout_constraintBottom_toTopOf="@+id/linearLayout">

                <LinearLayout
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:layout_weight="1" />

                <LinearLayout
                    android:layout_width="match_parent"
                    android:layout_weight="1"
                    android:layout_height="match_parent"
                    android:background="@color/mainColor"/>

                <LinearLayout
                    android:layout_width="match_parent"
                    android:layout_weight="1"
                    android:layout_height="match_parent"/>

                <LinearLayout
                    android:layout_width="match_parent"
                    android:layout_weight="1"
                    android:layout_height="match_parent"/>

                <LinearLayout
                    android:layout_width="match_parent"
                    android:layout_weight="1"
                    android:layout_height="match_parent"/>

            </LinearLayout>

            <LinearLayout
                android:id="@+id/linearLayout"
                android:layout_width="match_parent"
                android:layout_height="60dp"
                android:background="@color/white"
                android:weightSum="5"
                app:layout_constraintBottom_toBottomOf="parent">

                <ImageView
                    android:id="@+id/homeTap"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_weight="1"
                    android:src="@drawable/bottom_hometap" />

                <ImageView
                    android:id="@+id/tipTap"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_weight="1"
                    android:src="@drawable/bottom_goodtip" />

                <ImageView
                    android:id="@+id/talkTap"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_weight="1"
                    android:src="@drawable/bottom_talk" />

                <ImageView
                    android:id="@+id/bookmarkTap"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_weight="1"
                    android:src="@drawable/bottom_bookmark" />

                <ImageView
                    android:id="@+id/storeTap"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_weight="1"
                    android:src="@drawable/bottom_store" />

            </LinearLayout>



        </androidx.constraintlayout.widget.ConstraintLayout>

    </FrameLayout>

</layout>

fragment_tip.xml

 

fragment_tip.xml

 

 

# 해당 이미지 누르면 컨텐츠 리스트들이 뜨도록 

# 리사이클러뷰 만들기

-> 레이아웃에 리사이클러뷰 추가 (activity_content_list.xml 에 리사이클러뷰 추가)

-> 아이템뷰 생성 (content_rv_item.xml 생성)

-> 리사이클러뷰와 연결해줄 어뎁터 생성 (ContentRVAdapter.kt 생성)

 

그리고 이제 이 해당 이미지를 누르면 이에 해당되는 컨텐츠들이 나오도록 리사이클러뷰를 활용해서 리스트를 만들어주는 작업을 해줄것이다

 

일단 ContentListActivity와 activity_content_list.xml 파일들을 생성해준뒤, 리사이클러뷰를 만들어줄것이다

 

activity_content_list.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="match_parent"
    tools:context=".contentsList.ContentListActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        android:text="카테고리 영역 텍스트"
        android:textSize="20dp"
        android:textStyle="bold"
        android:textColor="@color/black"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/rv"
        android:layout_marginTop="80dp"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</androidx.constraintlayout.widget.ConstraintLayout>

activity_content_list.xml

 

activity_content_list.xml

 

 

그리고 각각의 데이터들이 들어갈 레이아웃인 아이템뷰 레이아웃을 생성해준다 (content_rv_item.xml 생성) 

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="200dp"
    android:orientation="vertical">

    <ImageView
        android:id="@+id/imageArea"
        android:src="@drawable/main_icon_oneroom"
        android:layout_width="match_parent"
        android:layout_height="100dp"/>

    <TextView
        android:id="@+id/textArea"
        android:text="Text Area"
        android:textSize="15sp"
        android:textStyle="bold"
        android:layout_width="match_parent"
        android:gravity="center"
        android:layout_height="wrap_content"/>

    <ImageView
        android:id="@+id/bookmarkArea"
        android:src="@drawable/bookmark_white"
        android:layout_marginTop="10dp"
        android:layout_gravity="center"
        android:layout_width="30dp"
        android:layout_height="30dp"/>

</LinearLayout>

content_rv_item.xml 

 

content_rv_item.xml

 

 

이렇게 해주었으면 이제 리사이클러뷰와 연결해줄 어뎁터를 생성해준다 (ContentRVAdapter.kt 생성)

방금만든 그 아이템을 어뎁터에 연결해주도록한다

일단 어뎁터의 틀을 먼저 만들어줄것이다

package com.example.mysololife.contentsList

import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView

class ContentRVAdapter(val item : ArrayList<String>) : RecyclerView.Adapter<ContentRVAdapter.ViewHolder>(){
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ContentRVAdapter.ViewHolder {
       
    }

    override fun onBindViewHolder(holder: ContentRVAdapter.ViewHolder, position: Int) {
       
    }

    override fun getItemCount(): Int {
        
    }

    inner class ViewHolder(itemView : View) : RecyclerView.ViewHolder(itemView) {

        fun bindItems(item : String){

        }
    }
}

ContentRVAdapter.kt (어뎁터 기본틀)

 

OnCreateViewHolder = 화면 연결

OnBindViewHolder = 데이터 연결

getItemCount = 값 개수 리턴

 

 

이렇게 틀을 먼저 만들어놓고 이어서 작성해보겠다

package com.example.mysololife.contentsList

import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.example.mysololife.R

class ContentRVAdapter(val items : ArrayList<String>) : RecyclerView.Adapter<ContentRVAdapter.ViewHolder>(){
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ContentRVAdapter.ViewHolder {
        // 아이템 레이아웃 연결
        val v = LayoutInflater.from(parent.context).inflate(R.layout.content_rv_item, parent,false)
        return ViewHolder(v)
    }

    override fun onBindViewHolder(holder: ContentRVAdapter.ViewHolder, position: Int) {
        holder.bindItems(items[position])
    }

    override fun getItemCount(): Int {
        return items.size
    }

    inner class ViewHolder(itemView : View) : RecyclerView.ViewHolder(itemView) {

        fun bindItems(item : String){

        }
    }
}

ContentRVAdapter.kt

 

이렇게 작성해준뒤 ContentListActivity에서 방금만든 어뎁터와 리사이클러뷰를 연결해준다

package com.example.mysololife.contentsList

class ContentListActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {

        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_content_list)

        //리사이클러뷰 연결
        val rv : RecyclerView = findViewById(R.id.rv)

        val items = ArrayList<String>()
        items.add("a")
        items.add("b")
        items.add("c")

        val rvAdapter = ContentRVAdapter(items)
        rv.adapter = rvAdapter

        rv.layoutManager = GridLayoutManager(this, 2)   // 한줄에 2줄씩

    }
}

ContentListActivity.kt

 

여기에 리스트에 3개의 아이템을 넣어주었기 때문에 3개의 아이템들이 나오는것을 확인할수있다 

 

 

TipFragment에서 첫번째 카테고리 눌렀을때 ContentListActivity로 이동하도록 안해줬기때문에 해당 코드도 추가해준다

// category1 눌렀을때 ContentListActivity로 이동
binding.category1.setOnClickListener {

    val intent = Intent(context, ContentListActivity::class.java)
    startActivity(intent)
}

TipFragment.kt

 

 

리사이클러뷰 도식화

 

 

 

여기까지하면 이렇게 나오는것을 확인할수있다

 

 

이제는 리스트에 a,b,c라는 값을 넣는게 아니라, 데이터 모델들을 넘겨줄것이다

데이터모델의 이미지와 제목들을 넘겨줄것이다 

 

 

그래서 데이터모델을 만들어서 데이터모델에 title과 imageUrl의 값을 넣어준다

package com.example.mysololife.contentsList

data class ContentModel (
    val title : String = "",
    val imageUrl : String = ""
)

ContentModel.kt

 

이제 ContentListActivity로 가서 아까 String으로 넘겨줬던 값을 삭제하고 방금 만든 ContentModel을 넣어주도록 한다

package com.example.mysololife.contentsList

class ContentListActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {

        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_content_list)

        //리사이클러뷰 연결
        val rv : RecyclerView = findViewById(R.id.rv)

        val items = ArrayList<ContentModel>()
        items.add(ContentModel("title1","imageurl1"))
        items.add(ContentModel("title2","imageurl2"))
        items.add(ContentModel("title3","imageurl3"))

        ...
    }
}

ContentListActivity.kt

 

ContentRVAdapter에도 CotentModel데이터를 넘겨준다

package com.example.mysololife.contentsList


class ContentRVAdapter(val items : ArrayList<ContentModel>) : RecyclerView.Adapter<ContentRVAdapter.ViewHolder>(){
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ContentRVAdapter.ViewHolder {
        // 아이템 레이아웃 연결
        val v = LayoutInflater.from(parent.context).inflate(R.layout.content_rv_item, parent,false)
        return ViewHolder(v)
    }

    override fun onBindViewHolder(holder: ContentRVAdapter.ViewHolder, position: Int) {
        holder.bindItems(items[position])
    }
   

    override fun getItemCount(): Int {
        return items.size
    }

    inner class ViewHolder(itemView : View) : RecyclerView.ViewHolder(itemView) {

        fun bindItems(item : ContentModel){

        }
    }
}

ContentRVAdapter.kt

 

 

이제 넘어온 데이터들을 실제로 하나하나 넣어주도록 하겠다

먼저 타이틀값부터 넣어주도록 할것이기 때문에, 어뎁터의 bindItems에 해당 코드를 추가해줘서 ContentListActivity에서 넣어놓은 데이터들이 나오도록한다.

inner class ViewHolder(itemView : View) : RecyclerView.ViewHolder(itemView) {

    fun bindItems(item : ContentModel){

        // content_rv_item에서 텍스트를 찾아옴
        val contentTitle = itemView.findViewById<TextView>(R.id.textArea)
        // ContentModel에서 받아온 하나하나의 아이템들을 가져와서 title을 넣어주겠다
        contentTitle.text = item.title


    }
}

ContentRVAdapter.kt

 

 

 

 

여기까지 해주면 이렇게 내가 추가해놓았던 title이 반영되는것을 볼수있다

 

 

 

 

이제는 이미지가 나오게 해볼것인데 웹에 있는 이미지들을 가져오도록 할것이다

웹사이트에 들어가서 이미지주소 복사를 누른다음 imageUrl쪽에 붙여넣어준다

package com.example.mysololife.contentsList

class ContentListActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {

        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_content_list)

        //리사이클러뷰 연결
        val rv : RecyclerView = findViewById(R.id.rv)

        val items = ArrayList<ContentModel>()
        items.add(ContentModel("title1","https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FblYPPY%2Fbtq66v0S4wu%2FRmuhpkXUO4FOcrlOmVG4G1%2Fimg.png"))
        items.add(ContentModel("title2","https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FznKK4%2Fbtq665AUWem%2FRUawPn5Wwb4cQ8BetEwN40%2Fimg.png"))
        items.add(ContentModel("title3","https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbtig9C%2Fbtq65UGxyWI%2FPRBIGUKJ4rjMkI7KTGrxtK%2Fimg.png"))

        // ContentRVAdapter를 rvAdapter에 연결
        val rvAdapter = ContentRVAdapter(baseContext, items)
        rv.adapter = rvAdapter

        rv.layoutManager = GridLayoutManager(this, 2)   // 한줄에 2줄로

    }
}

ContentListActivity.kt

 

 

그리고 이제는 Glide를 사용해서 아이템에 있는 이미지뷰에 이미지를 넣어줄것이다

Glide를 사용하기위해서 build.gradle(app)에 아래 코드를 추가해준다 

implementation ("com.github.bumptech.glide:glide:4.16.0")

 build.gradle(app)

 

Manifest에도 아래 코드를 추가해준다

<uses-permission android:name="android.permission.INTERNET"/>

AndroidManifest.xml

 

 

이제 context를 받아와서 ContentListActivity와 ContentRVAdapter에도 추가해준다

그리고 Glide를 사용해서 아이템 레이아웃에 있는 이미지뷰 부분에 이미지를 넣어준다

package com.example.mysololife.contentsList

class ContentRVAdapter(val context : Context, val items : ArrayList<ContentModel>) : RecyclerView.Adapter<ContentRVAdapter.ViewHolder>(){
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ContentRVAdapter.ViewHolder {
        // 아이템 레이아웃 연결
        val v = LayoutInflater.from(parent.context).inflate(R.layout.content_rv_item, parent,false)
        return ViewHolder(v)
    }

    override fun onBindViewHolder(holder: ContentRVAdapter.ViewHolder, position: Int) {
        holder.bindItems(items[position])
    }

    override fun getItemCount(): Int {
        return items.size
    }

    inner class ViewHolder(itemView : View) : RecyclerView.ViewHolder(itemView) {

        fun bindItems(item : ContentModel){

            // content_rv_item에서 텍스트, 이미지를 찾아옴
            val contentTitle = itemView.findViewById<TextView>(R.id.textArea)
            val imageViewArea = itemView.findViewById<ImageView>(R.id.imageArea)

            // ContentModel에서 받아온 하나하나의 아이템들을 가져와서 title을 넣어주겠다
            contentTitle.text = item.title

            // 이미지 불러오기
            Glide.with(context)
                .load(item.imageUrl)
                .into(imageViewArea)    // imageUrl을 imageViewArea변수에 집어넣겠다


        }
    }
}

ContentRVAdapter.kt

 

 

 

 

 

'

 

이렇게 Glide를 사용해서 이미지를 받아오면 이미지가 잘 불러와지는것을 볼수있다

 

일단 총 15개의 title과 url을 더 만들어준다

val items = ArrayList<ContentModel>()
items.add(ContentModel("title1","https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FblYPPY%2Fbtq66v0S4wu%2FRmuhpkXUO4FOcrlOmVG4G1%2Fimg.png"))
items.add(ContentModel("title2","https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FznKK4%2Fbtq665AUWem%2FRUawPn5Wwb4cQ8BetEwN40%2Fimg.png"))
items.add(ContentModel("title3","https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbtig9C%2Fbtq65UGxyWI%2FPRBIGUKJ4rjMkI7KTGrxtK%2Fimg.png"))
items.add(ContentModel("title4","https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcOYyBM%2Fbtq67Or43WW%2F17lZ3tKajnNwGPSCLtfnE1%2Fimg.png"))
items.add(ContentModel("title5","https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fekn5wI%2Fbtq66UlN4bC%2F8NEzlyot7HT4PcjbdYAINk%2Fimg.png"))
items.add(ContentModel("title6","https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F123LP%2Fbtq65qy4hAd%2F6dgpC13wgrdsnHigepoVT1%2Fimg.png"))
items.add(ContentModel("title7","https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fl2KC3%2Fbtq64lkUJIN%2FeSwUPyQOddzcj6OAkPKZuk%2Fimg.png"))
items.add(ContentModel("title8","https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmBh5u%2Fbtq651yYxop%2FX3idRXeJ0VQEoT1d6Hln30%2Fimg.png"))
items.add(ContentModel("title9","https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlOnja%2Fbtq69Tmp7X4%2FoUvdIEteFbq4Z0ZtgCd4p0%2Fimg.png"))
items.add(ContentModel("title10","https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FNNrYR%2Fbtq64wsW5VN%2FqIaAsfmFtcvh4Bketug9m0%2Fimg.png"))
items.add(ContentModel("title11","https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FK917N%2Fbtq64SP5gxj%2FNzsfNAykamW7qv1hdusp1K%2Fimg.png"))
items.add(ContentModel("title12","https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FeEO4sy%2Fbtq69SgK8L3%2FttCUxYHx9aPNebNwkPcI21%2Fimg.png"))
items.add(ContentModel("title13","https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbdIKDG%2Fbtq64M96JFa%2FKcJiYgKuwKuP3fIyviXm90%2Fimg.png"))
items.add(ContentModel("title14","https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFtY3t%2Fbtq65q6P4Zr%2FWe64GM8KzHAlGE3xQ2nDjk%2Fimg.png"))
items.add(ContentModel("title15","https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOtaMq%2Fbtq67OMpk4W%2FH1cd0mda3n2wNWgVL9Dqy0%2Fimg.png"))

ContentListActivity.kt

 

 

 

이제 webview를 사용해서, 저 불러온 이미지를 클릭하면 url로 이동하도록해볼것이다

그러면 이동할 url이 필요할것이므로 데이터모델에 가서 이동할 url 데이터를 추가해준다

package com.example.mysololife.contentsList

data class ContentModel (
    var title : String = "",
    var imageUrl : String = "",
    var webUrl : String = ""
)

ContentModel.kt

 

 

데이터 모델에 webUrl을 추가했으니깐 ContentListActivity에도 Url데이터를 추가해줘야한다 

val items = ArrayList<ContentModel>()
items.add(ContentModel("title1", "https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FblYPPY%2Fbtq66v0S4wu%2FRmuhpkXUO4FOcrlOmVG4G1%2Fimg.png", "https://philosopher-chan.tistory.com/1235?category=941578"))
items.add(ContentModel("title2", "https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FznKK4%2Fbtq665AUWem%2FRUawPn5Wwb4cQ8BetEwN40%2Fimg.png", "https://philosopher-chan.tistory.com/1236?category=941578"))
items.add(ContentModel("title3", "https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbtig9C%2Fbtq65UGxyWI%2FPRBIGUKJ4rjMkI7KTGrxtK%2Fimg.png", "https://philosopher-chan.tistory.com/1237?category=941578"))
items.add(ContentModel("title4", "https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcOYyBM%2Fbtq67Or43WW%2F17lZ3tKajnNwGPSCLtfnE1%2Fimg.png", "https://philosopher-chan.tistory.com/1238?category=941578"))
items.add(ContentModel("title5", "https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fekn5wI%2Fbtq66UlN4bC%2F8NEzlyot7HT4PcjbdYAINk%2Fimg.png", "https://philosopher-chan.tistory.com/1239?category=941578"))
items.add(ContentModel("title6", "https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F123LP%2Fbtq65qy4hAd%2F6dgpC13wgrdsnHigepoVT1%2Fimg.png", "https://philosopher-chan.tistory.com/1240?category=941578"))
items.add(ContentModel("title7", "https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fl2KC3%2Fbtq64lkUJIN%2FeSwUPyQOddzcj6OAkPKZuk%2Fimg.png","https://philosopher-chan.tistory.com/1241?category=941578"))
items.add(ContentModel("title8", "https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmBh5u%2Fbtq651yYxop%2FX3idRXeJ0VQEoT1d6Hln30%2Fimg.png", "https://philosopher-chan.tistory.com/1242?category=941578"))
items.add(ContentModel("title9", "https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlOnja%2Fbtq69Tmp7X4%2FoUvdIEteFbq4Z0ZtgCd4p0%2Fimg.png", "https://philosopher-chan.tistory.com/1243?category=941578"))
items.add(ContentModel("title10", "https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FNNrYR%2Fbtq64wsW5VN%2FqIaAsfmFtcvh4Bketug9m0%2Fimg.png", "https://philosopher-chan.tistory.com/1244?category=941578"))
items.add(ContentModel("title11", "https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FK917N%2Fbtq64SP5gxj%2FNzsfNAykamW7qv1hdusp1K%2Fimg.png", "https://philosopher-chan.tistory.com/1245?category=941578"))
items.add(ContentModel("title12", "https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FeEO4sy%2Fbtq69SgK8L3%2FttCUxYHx9aPNebNwkPcI21%2Fimg.png", "https://philosopher-chan.tistory.com/1246?category=941578"))
items.add(ContentModel("title13", "https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbdIKDG%2Fbtq64M96JFa%2FKcJiYgKuwKuP3fIyviXm90%2Fimg.png", "https://philosopher-chan.tistory.com/1247?category=941578"))
items.add(ContentModel("title14", "https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFtY3t%2Fbtq65q6P4Zr%2FWe64GM8KzHAlGE3xQ2nDjk%2Fimg.png", "https://philosopher-chan.tistory.com/1248?category=941578"))
items.add(ContentModel("title15", "https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOtaMq%2Fbtq67OMpk4W%2FH1cd0mda3n2wNWgVL9Dqy0%2Fimg.png", "https://philosopher-chan.tistory.com/1249?category=941578"))

ContentListActivity.kt

 

 

불러온 아이템들 하나하나씩 클릭하면 webview(url)로 이동하도록해볼것이다

그래서 리사이클러뷰에 있는 아이템을 클릭하면 이동하도록 하는 이벤트 처리를 해줘야한다

ContentRVAdapter로 가서 리사이클러뷰 클릭을 처리하는 코드를 추가해준다 

package com.example.mysololife.contentsList


class ContentRVAdapter(val context : Context, val items : ArrayList<ContentModel>) : RecyclerView.Adapter<ContentRVAdapter.ViewHolder>(){
    
    interface ItemClick{
        fun onClick(view : View, position: Int)
    }

    var itemClick : ItemClick? = null



    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ContentRVAdapter.ViewHolder {
        ...
    }

    override fun onBindViewHolder(holder: ContentRVAdapter.ViewHolder, position: Int) {

        // 리사이클러뷰에 있는 아이템을 클릭하면 이동하도록 하는 이벤트 처리
        if(itemClick != null){
            holder.itemView.setOnClickListener {v ->
                itemClick?.onClick(v, position)

            }
        }

        holder.bindItems(items[position])
    }

    override fun getItemCount(): Int {
        return items.size
    }

    inner class ViewHolder(itemView : View) : RecyclerView.ViewHolder(itemView) {
        ...
    }
}

ContentRVAdapter.kt

 

이렇게 작성해주면 리사이클러뷰 아이템 클릭이 가능해진다

 

진짜 클릭이되는지 토스트메시지를 띄워서 확인해보겠다

ContenListActivity에 아래와같은 코드를 작성해준다 

rvAdapter.itemClick = object  : ContentRVAdapter.ItemClick {
    override fun onClick(view: View, position: Int) {

        Toast.makeText(baseContext, items[position].title, Toast.LENGTH_SHORT).show()
    }
}

ContenListActivity.kt

 

이렇게 다 써주면 아이템 리스트를 눌렀을때 해당하는 텍스트가 토스트메세지로 뜨게된다

 

이제 webview를 구현해주기위해서 ContentShowActivity.kt 파일과 이에 해당하는 xml파일을 생성해준다

activity_content_show.xml에 webview코드를 추가해준다

<?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="match_parent"
    tools:context=".ContentShowActivity">

    <WebView
        android:id="@+id/webView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</androidx.constraintlayout.widget.ConstraintLayout>

activity_content_show.xml

 

ContentListActivity로 가서 리사이클러뷰 아이템을 클릭하면 ContentShowActivity로 이동하는 코드를 작성해주겠다 

rvAdapter.itemClick = object  : ContentRVAdapter.ItemClick {
    override fun onClick(view: View, position: Int) {

        Toast.makeText(baseContext, items[position].title, Toast.LENGTH_SHORT).show()

        val intent = Intent(this@ContentListActivity, ContentShowActivity::class.java)
        startActivity(intent)
    }
}

ContentListActivity.kt

 

근데 여기까지 하고 실행시켜보면, 아이템을 클릭했을때 페이지는 넘어가는데 웹뷰로 이동하지는 않고 빈화면이 나오는것을 확인할수있을것이다

 

ContentShowActivity로 데이터가 넘어가야한다

ContentListActivity에서 클릭한 데이터의 url이 넘어가야한다 

 

그래서 puteExtra를 사용해서 url이라는 이름 안에 items에 있는 클릭된값의 webUel을 넘긴다 

rvAdapter.itemClick = object  : ContentRVAdapter.ItemClick {
    override fun onClick(view: View, position: Int) {

        Toast.makeText(baseContext, items[position].title, Toast.LENGTH_SHORT).show()

        val intent = Intent(this@ContentListActivity, ContentShowActivity::class.java)
        intent.putExtra("url",items[position].webUrl)
        startActivity(intent)
    }
}

ContentListActivity.kt

 

이제 넘긴데이터를 getExtra를 사용해서 ContentShowActivity에서 받아준다

이렇게하면 url데이터가 잘 넘어간것을 확인할수있다

잘 넘어왔으니깐 이 url을 webview에 넣어주는 작업을해줄것이다

loadUrl을 사용해서 getExtra로 받아온 url데이터를 불러와서 webview에 넣어준다

package com.example.mysololife.contentsList

class ContentShowActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_content_show)

        val getUrl = intent.getStringExtra("url")

        val webView : WebView = findViewById(R.id.webView)
        webView.loadUrl(getUrl.toString())
    }
}

ContentShowActivity.kt

 

이렇게 코드를 써주면 리사이클러뷰 아이템을 클릭했을때 해당 웹뷰로 이동하는 것을 확인해볼수있다 

 

 

지금까지는 데이터들을 직접 하나하나 코드로 짜줘서 데이터를 받아와줬는데, 이 데이터들을 서버에서 받아와줘야할것이다. 따라서 파이어베이스를 이용해서 데이터들을 받아와주도록 해볼것이다 

 

파이어베이스 리얼타임베이스로 들어가서 활성화를 시켜준뒤, 인증된 사용자(로그인한 모든 사용자)가 쓸수있도록 실시간 데이터베이스 규칙을 아래와같이 수정해준다

{
    "rules": {
    ".read": "auth.uid !== null",
    ".write": "auth.uid !== null"
  }
}

 

안드로이드 스튜디오 build.gradle(app)으로 돌아와서 아래코드를 추가시켜준뒤 동기화를 시켜준다

implementation("com.google.firebase:firebase-database-ktx")

 build.gradle(app)

 

 

파이어베이스 공식문서를 참고하여 ContentListActivity에 아래와같은 코드를 추가해보도록하겠다 

package com.example.mysololife.contentsList


class ContentListActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {

        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_content_list)

        // Write a message to the database
        val database = Firebase.database
        val myRef = database.getReference("message")
        
        myRef.setValue("Hello, World!")
        
        ...

ContentListActivity.kt

 

이렇게하고 앱을 실행시켜서 리스트를 클릭한뒤 파이어베이스를 보면 아래처럼 실시간 데이터베이스가 추가된것을 확인할수있다 

여기에 message라는게 생긴것을 확인할수있는데 아까 위에 코드에서 적어준 getReference의 이름이다

이제 getReference의 이름을 contents로 바꿔보도록 하겠다

 

이제 이 contents밑에 아이템?들이 딸려나오도록 할건데 child를 사용해서 해줄것이다

myRef.child("test").setValue("Hello, World!")

이렇게 이줄만 수정해주면 contents안에 test가 딸려 나오는것을 볼수있다 

 

 

 

그다음에 push를 사용해서 코드를 작성한뒤 다시 앱을 실행하여 파이어베이스를 보면 test 밑에 임의의값이 생기고 "Hello World"라는 데이터가 들어간것을 볼수있다 

myRef.child("test").push().setValue("Hello, World!")

 

 

이제 우리는 "Hello World"라는 값을 집어넣을것이 아니라 여기에 데이터모델을 집어넣어서 우리가 원하는 값이 나오게 할것이다

그래서 setValue부분에 ContentModel을 사용해서 우리가 작성했던 데이터를 넣어줄것이다

myRef.child("test").push()
    .setValue(ContentModel("title1", "https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FblYPPY%2Fbtq66v0S4wu%2FRmuhpkXUO4FOcrlOmVG4G1%2Fimg.png", "https://philosopher-chan.tistory.com/1235?category=941578"))

일단 값을 하나만 넣어서 파이어베이스를 보면 test밑에 임의의값 밑에 우리가 넣은 데이터모델들이 잘 들어가있는것을 볼수있다

 

 

 

 

사실상 test부분은 필요없는것같아서 child부분은 지워주고 나머지 데이터들도 추가해보겠다 (일단 4개추가)

myRef.push()
    .setValue(ContentModel("title1", "https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FblYPPY%2Fbtq66v0S4wu%2FRmuhpkXUO4FOcrlOmVG4G1%2Fimg.png", "https://philosopher-chan.tistory.com/1235?category=941578"))

myRef.push()
    .setValue(ContentModel("title2", "https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FznKK4%2Fbtq665AUWem%2FRUawPn5Wwb4cQ8BetEwN40%2Fimg.png", "https://philosopher-chan.tistory.com/1236?category=941578"))

myRef.push()
    .setValue(ContentModel("title3", "https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbtig9C%2Fbtq65UGxyWI%2FPRBIGUKJ4rjMkI7KTGrxtK%2Fimg.png", "https://philosopher-chan.tistory.com/1237?category=941578"))

myRef.push()
    .setValue(ContentModel("title4", "https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcOYyBM%2Fbtq67Or43WW%2F17lZ3tKajnNwGPSCLtfnE1%2Fimg.png", "https://philosopher-chan.tistory.com/1238?category=941578"))

 

이렇게 하고 앱을 실행시킨뒤 파이어베이스를 확인해보면 contents밑에 4개의 값들이 잘 생기는것을 확인할수있다

 

 

이렇게하면 데이터를 넣는 작업은 완료가 됐다

 

 

근데 이제 이 데이터들을 다 주석처리를 시켜줘서 쓰지 않도록할것이다

데이터들이 이미 파이어베이스 데이터베이스에 들어가있으니깐, 그 데이터베이스에 있는 값들을 가져와서 어뎁터에 넣어주도록 할예정이다. 즉, 파이어베이스에 4개의 값을 집어넣어줬으므로 이 데이터들을 불러오도록 해줄것이다

 

데이터베이스 공식문서를 참고해서 ContentListActivity에 아래와같이 써주고 로그를 사용해서 datasnapshot이 어떻게 찍히는지 확인해본다. 로그를 찍어봤더니 contents안에 value들이 쭉 나와있는걸 확인할수있는데, 데이터들이 한덩어리들로 나오고있는걸 하나하나씩 빼와야되기때문에 그 작업을 해볼것이다

package com.example.mysololife.contentsList

class ContentListActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {

        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_content_list)

        // Write a message to the database
        val database = Firebase.database
        val myRef = database.getReference("contents")

        val postListener = object : ValueEventListener {
            override fun onDataChange(dataSnapshot: DataSnapshot) {

                Log.d("ContentListActivity", dataSnapshot.toString())

            }

            override fun onCancelled(databaseError: DatabaseError) {
                // Getting Post failed, log a message
                Log.w("ContentListActivity", "loadPost:onCancelled", databaseError.toException())
            }
        }
        myRef.addValueEventListener(postListener)

ContentListActivity.kt

 

 

반복문을 사용해서 데이터들을 하나하나씩 빼올수있다

dataModel을 만들어서 dataSnapshot에 있는애들을 가져오는 코드를 짜준뒤, dataModel에 어떤값이 들어있는지 Log를 사용해서 확인해보겠다. 로그를 확인해보면 우리가 원했던대로 데이터들이 하나하나씩 잘 나오는것을 볼수있다

이제 getValue()를 사용해서 우리가 만들었던 데이터모델인 ContentModel형태로 받아온다

그리고 items안에 item변수를 집어넣어준다. 로그를 찍어서 items안에 데이터들이 잘 들어갔는지 확인해보면 잘 들어간것을 볼수있다 

package com.example.mysololife.contentsList


class ContentListActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {

        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_content_list)

        val items = ArrayList<ContentModel>()

        // Write a message to the database
        val database = Firebase.database
        val myRef = database.getReference("contents")

        val postListener = object : ValueEventListener {
            override fun onDataChange(dataSnapshot: DataSnapshot) {

                for (dataModel in dataSnapshot.children){
                    Log.d("ContentListActivity",dataModel.toString())

                    val item = dataModel.getValue(ContentModel::class.java)
                    items.add(item!!)

                }
                Log.d("ContentListActivity",items.toString())

            }

            override fun onCancelled(databaseError: DatabaseError) {
                // Getting Post failed, log a message
                Log.w("ContentListActivity", "loadPost:onCancelled", databaseError.toException())
            }
        }
        myRef.addValueEventListener(postListener)

ContentListActivity.kt

 

이제 items들이 ContentRVAdapter로 들어가서 데이터가 잘 나와야되는데, 데이터들이 잘 넣어졌는데도 데이터들이 잘 출력이 되지 않고있다. 비동기형태로 받아오기때문에 데이터들이 잘 나오지 않는것이다 

따라서 notifyDataSetChanged()를 사용해서 어뎁터를 새로고침해주면 데이터들이 잘 나오는것을 확인할수있다 

package com.example.mysololife.contentsList


class ContentListActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {

        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_content_list)

        val items = ArrayList<ContentModel>()
        val rvAdapter = ContentRVAdapter(baseContext, items)

        // Write a message to the database
        val database = Firebase.database
        val myRef = database.getReference("contents")

        val postListener = object : ValueEventListener {
            override fun onDataChange(dataSnapshot: DataSnapshot) {

                for (dataModel in dataSnapshot.children){
                    Log.d("ContentListActivity",dataModel.toString())

                    val item = dataModel.getValue(ContentModel::class.java)
                    items.add(item!!)

                }
                rvAdapter.notifyDataSetChanged()
                Log.d("ContentListActivity",items.toString())

            }

            override fun onCancelled(databaseError: DatabaseError) {
                // Getting Post failed, log a message
                Log.w("ContentListActivity", "loadPost:onCancelled", databaseError.toException())
            }
        }
        myRef.addValueEventListener(postListener)



        //리사이클러뷰 연결
        val rv : RecyclerView = findViewById(R.id.rv)



        // ContentRVAdapter를 rvAdapter에 연결

        rv.adapter = rvAdapter

        rv.layoutManager = GridLayoutManager(this, 2)   // 한줄에 2줄로


        // 리사이클러뷰 아이템 클릭시
        rvAdapter.itemClick = object  : ContentRVAdapter.ItemClick {
            override fun onClick(view: View, position: Int) {

                Toast.makeText(baseContext, items[position].title, Toast.LENGTH_SHORT).show()

                val intent = Intent(this@ContentListActivity, ContentShowActivity::class.java)
                intent.putExtra("url",items[position].webUrl)
                startActivity(intent)
            }
        }


    }
}

ContentListActivity.kt

 

지금은 카테고리 하나만 만들어서 카테고리 클릭이 하나만되는데 이제 두번째 카테고리도 클릭하면 데이터가 받아지도록 코드를 짜볼것이다 

TipFragment로 가서 category2를 클릭했을때 ContentListActivity로 이동하도록 코드를 작성해주고, 

putExtra를 통해서 category1을 클릭했을때 category정보도 같이 넘겨주도록 한다 

// category1 눌렀을때 ContentListActivity로 이동
binding.category1.setOnClickListener {

    val intent = Intent(context, ContentListActivity::class.java)
    // category1 눌렀을때 category정보도 같이 넘겨줌
    intent.putExtra("category","category1")
    startActivity(intent)
}

// category2 눌렀을때 ContentListActivity로 이동
binding.category2.setOnClickListener {

    val intent = Intent(context, ContentListActivity::class.java)
    // category1 눌렀을때 category정보도 같이 넘겨줌
    intent.putExtra("category","category2")
    startActivity(intent)
}

TipFragment.kt

 

방금 넘겨줬던 데이터들을 ContentListAcitivty에서 받아온다 

그러면 이제 category안에 category1, category2 가 들어가있을것이다

if문을 사용해서 category1일때는 contents를 넣고, category2일때는 contents2를 넣도록한다

category1일때는 myRef에서 contents부분에 있는 데이터들을 가져오고, category2일때는 myRef에서 contents2부분에 있는 데이터들을 가져온다.

package com.example.mysololife.contentsList


class ContentListActivity : AppCompatActivity() {

    lateinit var myRef : DatabaseReference

    override fun onCreate(savedInstanceState: Bundle?) {

        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_content_list)

        val items = ArrayList<ContentModel>()
        val rvAdapter = ContentRVAdapter(baseContext, items)

        // Write a message to the database
        val database = Firebase.database

        // TipFragment에서 넘겨준 데이터 받아옴
        val category = intent.getStringExtra("category")



        if (category == "category1"){

            myRef = database.getReference("contents")

//            코드가 겹쳐서 삭제
//            val postListener = object : ValueEventListener {
//                override fun onDataChange(dataSnapshot: DataSnapshot) {
//
//                    for (dataModel in dataSnapshot.children){
//                        Log.d("ContentListActivity",dataModel.toString())
//
//                        val item = dataModel.getValue(ContentModel::class.java)
//                        items.add(item!!)
//
//                    }
//                    rvAdapter.notifyDataSetChanged()
//                    Log.d("ContentListActivity",items.toString())
//
//                }
//
//                override fun onCancelled(databaseError: DatabaseError) {
//                    // Getting Post failed, log a message
//                    Log.w("ContentListActivity", "loadPost:onCancelled", databaseError.toException())
//                }
//            }
//            myRef.addValueEventListener(postListener)



        }else if(category == "category2"){

            myRef = database.getReference("contents2")

        }

        val postListener = object : ValueEventListener {
            override fun onDataChange(dataSnapshot: DataSnapshot) {

                for (dataModel in dataSnapshot.children){
                    Log.d("ContentListActivity",dataModel.toString())

                    val item = dataModel.getValue(ContentModel::class.java)
                    items.add(item!!)

                }
                rvAdapter.notifyDataSetChanged()
                Log.d("ContentListActivity",items.toString())

            }

            override fun onCancelled(databaseError: DatabaseError) {
                // Getting Post failed, log a message
                Log.w("ContentListActivity", "loadPost:onCancelled", databaseError.toException())
            }
        }
        myRef.addValueEventListener(postListener)




        //리사이클러뷰 연결
        val rv : RecyclerView = findViewById(R.id.rv)



        // ContentRVAdapter를 rvAdapter에 연결

        rv.adapter = rvAdapter

        rv.layoutManager = GridLayoutManager(this, 2)   // 한줄에 2개씩


        rvAdapter.itemClick = object  : ContentRVAdapter.ItemClick {
            override fun onClick(view: View, position: Int) {

                Toast.makeText(baseContext, items[position].title, Toast.LENGTH_SHORT).show()

                val intent = Intent(this@ContentListActivity, ContentShowActivity::class.java)
                intent.putExtra("url",items[position].webUrl)
                startActivity(intent)
            }
        }



//        val myRef2 = database.getReference("contents2")
//        myRef2.push()
//            .setValue(ContentModel("title5", "https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FblYPPY%2Fbtq66v0S4wu%2FRmuhpkXUO4FOcrlOmVG4G1%2Fimg.png", "https://philosopher-chan.tistory.com/1235?category=941578"))
//
//        myRef2.push()
//            .setValue(ContentModel("title6", "https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FznKK4%2Fbtq665AUWem%2FRUawPn5Wwb4cQ8BetEwN40%2Fimg.png", "https://philosopher-chan.tistory.com/1236?category=941578"))
//
//        myRef2.push()
//            .setValue(ContentModel("title7", "https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbtig9C%2Fbtq65UGxyWI%2FPRBIGUKJ4rjMkI7KTGrxtK%2Fimg.png", "https://philosopher-chan.tistory.com/1237?category=941578"))
//
//        myRef2.push()
//            .setValue(ContentModel("title8", "https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcOYyBM%2Fbtq67Or43WW%2F17lZ3tKajnNwGPSCLtfnE1%2Fimg.png", "https://philosopher-chan.tistory.com/1238?category=941578"))


//        items.add(ContentModel("title1", "https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FblYPPY%2Fbtq66v0S4wu%2FRmuhpkXUO4FOcrlOmVG4G1%2Fimg.png", "https://philosopher-chan.tistory.com/1235?category=941578"))
//        items.add(ContentModel("title2", "https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FznKK4%2Fbtq665AUWem%2FRUawPn5Wwb4cQ8BetEwN40%2Fimg.png", "https://philosopher-chan.tistory.com/1236?category=941578"))
//        items.add(ContentModel("title3", "https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbtig9C%2Fbtq65UGxyWI%2FPRBIGUKJ4rjMkI7KTGrxtK%2Fimg.png", "https://philosopher-chan.tistory.com/1237?category=941578"))
//        items.add(ContentModel("title4", "https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcOYyBM%2Fbtq67Or43WW%2F17lZ3tKajnNwGPSCLtfnE1%2Fimg.png", "https://philosopher-chan.tistory.com/1238?category=941578"))
//        items.add(ContentModel("title5", "https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fekn5wI%2Fbtq66UlN4bC%2F8NEzlyot7HT4PcjbdYAINk%2Fimg.png", "https://philosopher-chan.tistory.com/1239?category=941578"))
//        items.add(ContentModel("title6", "https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F123LP%2Fbtq65qy4hAd%2F6dgpC13wgrdsnHigepoVT1%2Fimg.png", "https://philosopher-chan.tistory.com/1240?category=941578"))
//        items.add(ContentModel("title7", "https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fl2KC3%2Fbtq64lkUJIN%2FeSwUPyQOddzcj6OAkPKZuk%2Fimg.png","https://philosopher-chan.tistory.com/1241?category=941578"))
//        items.add(ContentModel("title8", "https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmBh5u%2Fbtq651yYxop%2FX3idRXeJ0VQEoT1d6Hln30%2Fimg.png", "https://philosopher-chan.tistory.com/1242?category=941578"))
//        items.add(ContentModel("title9", "https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlOnja%2Fbtq69Tmp7X4%2FoUvdIEteFbq4Z0ZtgCd4p0%2Fimg.png", "https://philosopher-chan.tistory.com/1243?category=941578"))
//        items.add(ContentModel("title10", "https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FNNrYR%2Fbtq64wsW5VN%2FqIaAsfmFtcvh4Bketug9m0%2Fimg.png", "https://philosopher-chan.tistory.com/1244?category=941578"))
//        items.add(ContentModel("title11", "https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FK917N%2Fbtq64SP5gxj%2FNzsfNAykamW7qv1hdusp1K%2Fimg.png", "https://philosopher-chan.tistory.com/1245?category=941578"))
//        items.add(ContentModel("title12", "https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FeEO4sy%2Fbtq69SgK8L3%2FttCUxYHx9aPNebNwkPcI21%2Fimg.png", "https://philosopher-chan.tistory.com/1246?category=941578"))
//        items.add(ContentModel("title13", "https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbdIKDG%2Fbtq64M96JFa%2FKcJiYgKuwKuP3fIyviXm90%2Fimg.png", "https://philosopher-chan.tistory.com/1247?category=941578"))
//        items.add(ContentModel("title14", "https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFtY3t%2Fbtq65q6P4Zr%2FWe64GM8KzHAlGE3xQ2nDjk%2Fimg.png", "https://philosopher-chan.tistory.com/1248?category=941578"))
//        items.add(ContentModel("title15", "https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOtaMq%2Fbtq67OMpk4W%2FH1cd0mda3n2wNWgVL9Dqy0%2Fimg.png", "https://philosopher-chan.tistory.com/1249?category=941578"))




    }
}

ContentListActivity.kt

 

이렇게 하면 파이어베이스에 데이터가 잘 들어가져서,

두번째 카테고리를 클릭했을때 해당하는 데이터가 나오는것을 확인할수가있다 

처음에 주석처리 해준것은 코드가 겹치기 때문에 삭제를 시켜준것이다.

 

 

 

 

근데 내가 앱을 실행시켰었는데 두번째 카테고리를 클릭했을때 아무 데이터도 나오지 않는 불상사가 발생했었다...

데이터를 넣어줄때 앱을 실행시켜서 파이어베이스에 contents2라는 데이터를 집어넣어야지 앱에 출력이 되는데 파이어베이스에 데이터를 넣어놓지 않아서 발생하는 문제였다..! 

 

파이어베이스에 데이터를 넣어주지 않아서 발생한 오류라는 것을 알고 위와같이 contens2데이터를 넣어주었다! 

이런식으로 나머지 카테고리에도 전부 데이터를 넣어서 적용되도록 해준다!

 

 

8번째 카테고리까지 전부 적용되도록 수정한 전체코드다

package com.example.mysololife.contentsList


class ContentListActivity : AppCompatActivity() {

    lateinit var myRef : DatabaseReference

    override fun onCreate(savedInstanceState: Bundle?) {

        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_content_list)

        val items = ArrayList<ContentModel>()
        val rvAdapter = ContentRVAdapter(baseContext, items)

        // Write a message to the database
        val database = Firebase.database

        // TipFragment에서 넘겨준 데이터 받아옴
        val category = intent.getStringExtra("category")


        if (category == "category1"){
            myRef = database.getReference("contents")

        }else if(category == "category2"){
            myRef = database.getReference("contents2")

        }else if(category == "category3"){
            myRef = database.getReference("contents3")

        }else if(category == "category4"){
            myRef = database.getReference("contents4")

        }else if (category == "category5"){
            myRef = database.getReference("contents5")

        }else if (category == "category6"){
            myRef = database.getReference("contents6")

        }else if (category == "category7"){
            myRef = database.getReference("contents7")

        }else if (category == "category8") {
            myRef = database.getReference("contents8")
        }



        val postListener = object : ValueEventListener {
            override fun onDataChange(dataSnapshot: DataSnapshot) {

                for (dataModel in dataSnapshot.children){
                    Log.d("ContentListActivity",dataModel.toString())

                    val item = dataModel.getValue(ContentModel::class.java)
                    items.add(item!!)

                }
                rvAdapter.notifyDataSetChanged()
                Log.d("ContentListActivity",items.toString())

            }

            override fun onCancelled(databaseError: DatabaseError) {
                // Getting Post failed, log a message
                Log.w("ContentListActivity", "loadPost:onCancelled", databaseError.toException())
            }
        }
        myRef.addValueEventListener(postListener)


        //리사이클러뷰 연결
        val rv : RecyclerView = findViewById(R.id.rv)



        // ContentRVAdapter를 rvAdapter에 연결

        rv.adapter = rvAdapter

        rv.layoutManager = GridLayoutManager(this, 2)   // 한줄에 2개씩


        rvAdapter.itemClick = object  : ContentRVAdapter.ItemClick {
            override fun onClick(view: View, position: Int) {

                Toast.makeText(baseContext, items[position].title, Toast.LENGTH_SHORT).show()

                val intent = Intent(this@ContentListActivity, ContentShowActivity::class.java)
                intent.putExtra("url",items[position].webUrl)
                startActivity(intent)
            }
        }



//        val myRef8 = database.getReference("contents8")
//        myRef8.push()
//            .setValue(ContentModel("title33", "https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbdIKDG%2Fbtq64M96JFa%2FKcJiYgKuwKuP3fIyviXm90%2Fimg.png", "https://philosopher-chan.tistory.com/1247?category=941578"))
//
//        myRef8.push()
//            .setValue(ContentModel("title34", "https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFtY3t%2Fbtq65q6P4Zr%2FWe64GM8KzHAlGE3xQ2nDjk%2Fimg.png", "https://philosopher-chan.tistory.com/1248?category=941578"))
//
//        myRef8.push()
//            .setValue(ContentModel("title35", "https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOtaMq%2Fbtq67OMpk4W%2FH1cd0mda3n2wNWgVL9Dqy0%2Fimg.png", "https://philosopher-chan.tistory.com/1249?category=941578"))
//
//        myRef8.push()
//            .setValue(ContentModel("title36", "https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FeEO4sy%2Fbtq69SgK8L3%2FttCUxYHx9aPNebNwkPcI21%2Fimg.png", "https://philosopher-chan.tistory.com/1246?category=941578"))


//        items.add(ContentModel("title1", "https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FblYPPY%2Fbtq66v0S4wu%2FRmuhpkXUO4FOcrlOmVG4G1%2Fimg.png", "https://philosopher-chan.tistory.com/1235?category=941578"))
//        items.add(ContentModel("title2", "https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FznKK4%2Fbtq665AUWem%2FRUawPn5Wwb4cQ8BetEwN40%2Fimg.png", "https://philosopher-chan.tistory.com/1236?category=941578"))
//        items.add(ContentModel("title3", "https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbtig9C%2Fbtq65UGxyWI%2FPRBIGUKJ4rjMkI7KTGrxtK%2Fimg.png", "https://philosopher-chan.tistory.com/1237?category=941578"))
//        items.add(ContentModel("title4", "https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcOYyBM%2Fbtq67Or43WW%2F17lZ3tKajnNwGPSCLtfnE1%2Fimg.png", "https://philosopher-chan.tistory.com/1238?category=941578"))
//        items.add(ContentModel("title5", "https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fekn5wI%2Fbtq66UlN4bC%2F8NEzlyot7HT4PcjbdYAINk%2Fimg.png", "https://philosopher-chan.tistory.com/1239?category=941578"))
//        items.add(ContentModel("title6", "https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F123LP%2Fbtq65qy4hAd%2F6dgpC13wgrdsnHigepoVT1%2Fimg.png", "https://philosopher-chan.tistory.com/1240?category=941578"))
//        items.add(ContentModel("title7", "https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fl2KC3%2Fbtq64lkUJIN%2FeSwUPyQOddzcj6OAkPKZuk%2Fimg.png","https://philosopher-chan.tistory.com/1241?category=941578"))
//        items.add(ContentModel("title8", "https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmBh5u%2Fbtq651yYxop%2FX3idRXeJ0VQEoT1d6Hln30%2Fimg.png", "https://philosopher-chan.tistory.com/1242?category=941578"))
//        items.add(ContentModel("title9", "https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlOnja%2Fbtq69Tmp7X4%2FoUvdIEteFbq4Z0ZtgCd4p0%2Fimg.png", "https://philosopher-chan.tistory.com/1243?category=941578"))
//        items.add(ContentModel("title10", "https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FNNrYR%2Fbtq64wsW5VN%2FqIaAsfmFtcvh4Bketug9m0%2Fimg.png", "https://philosopher-chan.tistory.com/1244?category=941578"))
//        items.add(ContentModel("title11", "https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FK917N%2Fbtq64SP5gxj%2FNzsfNAykamW7qv1hdusp1K%2Fimg.png", "https://philosopher-chan.tistory.com/1245?category=941578"))
//        items.add(ContentModel("title12", "https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FeEO4sy%2Fbtq69SgK8L3%2FttCUxYHx9aPNebNwkPcI21%2Fimg.png", "https://philosopher-chan.tistory.com/1246?category=941578"))
//        items.add(ContentModel("title13", "https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbdIKDG%2Fbtq64M96JFa%2FKcJiYgKuwKuP3fIyviXm90%2Fimg.png", "https://philosopher-chan.tistory.com/1247?category=941578"))
//        items.add(ContentModel("title14", "https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFtY3t%2Fbtq65q6P4Zr%2FWe64GM8KzHAlGE3xQ2nDjk%2Fimg.png", "https://philosopher-chan.tistory.com/1248?category=941578"))
//        items.add(ContentModel("title15", "https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOtaMq%2Fbtq67OMpk4W%2FH1cd0mda3n2wNWgVL9Dqy0%2Fimg.png", "https://philosopher-chan.tistory.com/1249?category=941578"))




    }
}

ContentListActivity.kt

 

package com.example.mysololife.fragments


class TipFragment : Fragment() {

    private lateinit var binding : FragmentTipBinding


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

    }

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
       binding = DataBindingUtil.inflate(inflater,R.layout.fragment_tip,container,false)


        // category1 눌렀을때 ContentListActivity로 이동
        binding.category1.setOnClickListener {

            val intent = Intent(context, ContentListActivity::class.java)
            // category1 눌렀을때 category정보도 같이 넘겨줌
            intent.putExtra("category","category1")
            startActivity(intent)
        }

        // category2 눌렀을때 ContentListActivity로 이동
        binding.category2.setOnClickListener {

            val intent = Intent(context, ContentListActivity::class.java)
            // category1 눌렀을때 category정보도 같이 넘겨줌
            intent.putExtra("category","category2")
            startActivity(intent)
        }

        // category3 눌렀을때 ContentListActivity로 이동
        binding.category3.setOnClickListener {

            val intent = Intent(context, ContentListActivity::class.java)
            // category1 눌렀을때 category정보도 같이 넘겨줌
            intent.putExtra("category","category3")
            startActivity(intent)
        }

        // category4 눌렀을때 ContentListActivity로 이동
        binding.category4.setOnClickListener {

            val intent = Intent(context, ContentListActivity::class.java)
            // category1 눌렀을때 category정보도 같이 넘겨줌
            intent.putExtra("category","category4")
            startActivity(intent)
        }

        // category5 눌렀을때 ContentListActivity로 이동
        binding.category5.setOnClickListener {

            val intent = Intent(context, ContentListActivity::class.java)
            // category1 눌렀을때 category정보도 같이 넘겨줌
            intent.putExtra("category","category5")
            startActivity(intent)
        }

        // category6 눌렀을때 ContentListActivity로 이동
        binding.category6.setOnClickListener {

            val intent = Intent(context, ContentListActivity::class.java)
            // category1 눌렀을때 category정보도 같이 넘겨줌
            intent.putExtra("category","category6")
            startActivity(intent)
        }

        // category7 눌렀을때 ContentListActivity로 이동
        binding.category7.setOnClickListener {

            val intent = Intent(context, ContentListActivity::class.java)
            // category1 눌렀을때 category정보도 같이 넘겨줌
            intent.putExtra("category","category7")
            startActivity(intent)
        }

        // category8 눌렀을때 ContentListActivity로 이동
        binding.category8.setOnClickListener {

            val intent = Intent(context, ContentListActivity::class.java)
            // category1 눌렀을때 category정보도 같이 넘겨줌
            intent.putExtra("category","category8")
            startActivity(intent)
        }


        //하단 네비게이션바
        binding.homeTap.setOnClickListener {
            it.findNavController().navigate(R.id.action_tipFragment_to_homeFragment)
        }

        binding.talkTap.setOnClickListener {
            it.findNavController().navigate(R.id.action_tipFragment_to_talkFragment)

        }

        binding.bookmarkTap.setOnClickListener {
            it.findNavController().navigate(R.id.action_tipFragment_to_bookmarkFragment)

        }

        binding.storeTap.setOnClickListener {
            it.findNavController().navigate(R.id.action_tipFragment_to_storeFragment)

        }

        return binding.root
    }


}

TipFragment.kt

 

 

파이어베이스에도 이렇게 8개의 contents 데이터들이 잘 들어간것을 볼수있다 

 

 

꿀팁페이지 완성화면이다

 

 

이미지들이랑 웹페이지 사이트는 전부 다 바꾸지는 않아서 겹치는게 많다ㅎㅎ