제육's 휘발성 코딩
Published 2021. 10. 27. 14:06
[Android] 안드로이드 버튼 이벤트 Other
반응형

버튼 누르면 이미지 변경

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

        var rollBtn: Button = findViewById(R.id.roll)
        rollBtn.setOnClickListener{
            var myDice:Dice = Dice()
            var num = myDice.roll()
//            var textview: TextView = findViewById(R.id.number)
//            textview.text = num.toString()
            var diceImg: ImageView = findViewById(R.id.diceimg)
            when(num) {
                1 -> diceImg.setImageResource(R.drawable.dice_1)
                2 -> diceImg.setImageResource(R.drawable.dice_2)
                3 -> diceImg.setImageResource(R.drawable.dice_3)
                4 -> diceImg.setImageResource(R.drawable.dice_4)
                5 -> diceImg.setImageResource(R.drawable.dice_5)
                6 -> diceImg.setImageResource(R.drawable.dice_6)
            }
        }
    }
}

class Dice {
    fun roll():Int {
        return (1..6).random()
    }
}
  • 버튼 누를 때마다 1~6 사이의 랜덤 값을 받아와서 값에 맞게 주사위 이미지 변경하는 예제

ListView

  • 뷰 안에서 리스트로 표현하는 레이아웃
  • 만들려고하는 리스트 갯수 만큼 미리 할당 - 메모리 낭비

RecyclerView 예제

  • 롤리팝 버전부터 생성된 뷰로 ListView의 단점을 보완
  • itemview가 1000개가 있더라도 화면에 보여줄 수 있는 갯수 + 여유 몇 개만 추가적으로 할당하고 이후 사용자가 스크롤할 때 이전에 한 갯수 만큼 다시 메모리에 넣으면서 기존에 뷰 공간에 새로운 데이터를 넣어 처리한다. (뷰 공간을 재활용 하여 새로운 데이터를 넣는 레이아웃)
  • 리스트 안에 텍스트, 이미지 또는 리니어레이아웃, 그리드 등 확장하기 용이
  • 화면에 보여질 수 있는 리스트 갯수에 위에서 사라지는 리스트 갯수만큼만 할당
  • 구조
    • layout : activity_main.xml, item_list.xml (itemView 들의 집합)
    • code : MainActivity.kt - recyclerview 와 adapter를 결합
    • data 클래스 : Affirmation
    • 컴파일 한 객체(itemview)를 Adapter에서 받은 후 binding
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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=".MainActivity">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recycler_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scrollbars="vertical"
        app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"/>
</FrameLayout>
  • item을 담을 리사이클러 뷰 코드

list_item

<?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="wrap_content"
    android:orientation="vertical"
    android:padding="16dp">
    <ImageView
        android:layout_width="match_parent"
        android:layout_height="194dp"
        android:id="@+id/item_image"
        android:importantForAccessibility="no"
        android:scaleType="centerCrop" />

    <TextView
        android:id="@+id/item_title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:padding="16dp"
        android:textAppearance="@android:style/TextAppearance.Material.Subhead" />

</LinearLayout>
  • item을 담을 뷰 레이아웃
  • centerCrop : 이미지가 영역보다 클 때 방식 지정
class Affirmation(val strResource:Int, val imageResource:Int) {}
class DataSet {
    fun makeSet(): List<Affirmation> {
        return listOf<Affirmation>(
            Affirmation(R.string.affirmation1, R.drawable.image1),
            Affirmation(R.string.affirmation2, R.drawable.image2),
            Affirmation(R.string.affirmation3, R.drawable.image3),
            Affirmation(R.string.affirmation4, R.drawable.image4),
            Affirmation(R.string.affirmation5, R.drawable.image5),
            Affirmation(R.string.affirmation6, R.drawable.image6),
            Affirmation(R.string.affirmation7, R.drawable.image7),
            Affirmation(R.string.affirmation8, R.drawable.image8),
            Affirmation(R.string.affirmation9, R.drawable.image9),
            Affirmation(R.string.affirmation10, R.drawable.image10)
        )
    }
}
  • DataSet 생성 , Affirmation 클래스는 Int, Int를 매개변수로 받는 클래스

Adapter

  • 객체 안에 이미지, 텍스트 등 여러 종류의 데이터(데이터 클래스)를 넣어주는 클래스
  • Adapter와 recyclerView를 연결하는 것을 binding(결합) 한다고 한다. 이러한 결합을 MainActivity에서 동작한다.
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.example.recyclerapp_2.R
import com.example.recyclerapp_2.data.Affirmation

class ItemAdapter(private val context: Context, private val dataset: List<Affirmation>) :
    RecyclerView.Adapter<ItemAdapter.ItemViewHolder>() {
    class ItemViewHolder(private val view: View) : RecyclerView.ViewHolder(view) {
        val textview: TextView = view.findViewById(R.id.item_title)
        val imageview: ImageView = view.findViewById(R.id.item_image)
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ItemViewHolder {
        val item_layout = LayoutInflater.from(parent.context).inflate(R.layout.list_item, parent, false)
        return ItemViewHolder(item_layout)
    }

    override fun onBindViewHolder(holder: ItemViewHolder, position: Int) {
        val item = dataset[position]
        holder.textview.text = context.resources.getString(item.strResource)
        holder.imageview.setImageResource(item.imageResource)
    }

    override fun getItemCount() = dataset.size
}

Layout

  • Linear
    • 수직 : vertical, 수평 :horizontal 으로 레이아웃 지정
    • layout_weight : 가중치 설정 (남는 공간이 있으면 가중치가 있는 뷰가 가진다.)
    • gravity : 레이아웃 안 정렬, layout_gravity : 바깥 레이아웃 정렬
  • Relative
    • 기준인 뷰가 있고 그 뷰와 id를 통해 관련된 레이아웃을 생성 (상대적 배치)
  • Frame
    • 여러 개 화면이 있는 것처럼 보여주는 레이아웃
  • Grid
    • 행 또는 열을 기준으로 바둑판 모양의 배치를 정하는 레이아웃
  • Constraint
  • Coordinate
  • Motion

Activity 이동

  • A : Running(실행) , B : Paused (상태 유지)
  • Stack 처럼 액티비티 위에 쌓이고 끝나면 되돌아온다.

Life Cycle

  • start -> finish 관계가 기본
  • 액티비티 간에서도 값을 전달 및 받아올 수 있다. 이 데이터를 받는 공간을 bundle 이라고 한다.
    • 메인 액티비티는 받아온 값이 어느 레이아웃에서 온 지 알아야 한다. Req.code 라는 상수 값을 하나 정의하여 결과를 보낼 때 데이터와 Req.code를 같이 보내서 구별 한다.
    • ActivityResult Launcher를 사용하는 것이 최근 사용 방법

Manifests 설정

<activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
<activity android:name=".MenuActivity"></activity>
  • 액티비티가 여러 개이므로 manifests에 액티비티를 지정

MainActivity

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

        val button: Button = findViewById(R.id.button)
        button.setOnClickListener{
            val intent: Intent = Intent(applicationContext, MenuActivity::class.java)
            startActivity(intent)
        }
    }
}
  • Intent : 할 일 (Intent(현재 위치, 이동할 위치))

finish

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

        val button: Button = findViewById(R.id.button)
        button.setOnClickListener{
            finish()
        }
    }
}
  • finish() : 이전 위치로 되돌아 간다.

Bundle

  • 예전 방식
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val button: Button = findViewById(R.id.button)
        button.setOnClickListener{
            val intent: Intent = Intent(applicationContext, MenuActivity::class.java)
            intent.putExtra("age", 23)
            startActivityForResult(intent, REQ_CODE)
        }
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        if (requestCode == REQ_CODE && resultCode == RESULT_OK) {
            val name: TextView = findViewById(R.id.name)
            name.text = data!!.getStringExtra("name")
        }
    }

    companion object {
        const val REQ_CODE = 10
    }

}
class MenuActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_menu)

        val bundle:Bundle? = intent.extras // 데이터 받아 오기
        val age: Int? = bundle?.getInt("age") //받을 데이터의 키

        val button: Button = findViewById(R.id.button)
        button.setOnClickListener{
            val ret = Intent()
            ret.putExtra("name", "Mike : "+ age )
            setResult(RESULT_OK, ret)
            finish()
        }
    }
}

ActivityResultLauncher

class MainActivity : AppCompatActivity() {
    private lateinit var launcher: ActivityResultLauncher<Intent>
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        launcher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
            result: ActivityResult -> if (result.resultCode == RESULT_OK) {
            val name: TextView = findViewById(R.id.name)
            name.text = result.data!!.getStringExtra("name")
            }
        }


        val button: Button = findViewById(R.id.button)
        button.setOnClickListener{
            val intent: Intent = Intent(applicationContext, MenuActivity::class.java)
            intent.putExtra("age", 23)
            //startActivityForResult(intent, REQ_CODE)
            launcher.launch(intent)
        }
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)

    }

    companion object {
        const val REQ_CODE = 10
    }

}

Intent

  • 안드로이드에서 Component는 Activity, Service, BroadcastReceiver, Content Provider 로 4개라고 볼 수 있다.
  • 여러 액티비티가 있을 때 Main 은 직접 이동시키는 것이 아니라 Android 시스템에 요청을 해서 이동을 한다. 이와 같은 의사표시를 할때 사용하는 것을 Intent (할 일)라고 한다. Intent에는 명시적 인텐트 , 묵시적 인텐트가 있다.
    • 명시적 인텐트 : Intent(.Activity , Secend::class.java)
    • 묵시적 인텐트 : Intent(aoc.VIEW Browsable)

Activity Life Cycle

  • 안드로이드 시스템이 자동으로 적용해주는 시스템
  • 실행 (활성화) 메서드
    • onCreate(액티비티가 object로 생성이 될때 레이아웃과 연결)
    • onStart, onResume(다시 실행)
  • 멈춤 (액티비티의 변경)
    • onPause(일부분이 보일 때), onStop (완전히 가려서 안보일 때)
  • 소멸 (비활성화)
    • onDestroy : onStop 상태인 액티비티를 비활성화 시킬 때 사용
  • A(메인) , B, C 액티비티가 있을 때
    • A.onCreate(), A.onStart(), A.Resume()이 스택 구조로 실행
    • B 액티비티로 이동했을 때 : A.onCreate(), A.onStart(), A.onResume(), A.onPause(), B.onCreate~ B.onResume() 순으로 쌓인다. 현재 액티비티의 상해는 A: Paused, B: Resumed
    • B 액티비티에서 C로 이동했을 때 : A,B 는 Stopped, C는 Resumed 상태
    • C 액티비티를 Finish() 했을 때 : A는 Stopped, B는 Paused, C는 Resumed 상태
    • B 액티비티를 Finish() 했을 때 : A는 Resumed, B는 Paused, C는 Destroyed 상태
    • A에서 또 다른 액티비티를 눌렀을 때 : A는 Resumed, B,C는 Destroyed 상태

Broadcast Receiver

  • 방송 수신기 = 시스템 이벤트 전달
  • 사용 방법
    • Manifest 등록
    • Code 상에서 동적으로 등록 - Receiver Class 정의 또는 Receiver Object 정의
buildFeatures {
    viewBinding = true
}
  • viewBinding을 위한 build.gradle 에 객체 지정 (ActivityMainBinding 생성)
반응형
profile

제육's 휘발성 코딩

@sasca37

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요! 맞구독은 언제나 환영입니다^^