안드로이드

안드로이드 :

ChloeLee 2020. 11. 10. 22:21

Fragment 

일종의 뷰

수명주기를 가진 뷰

태블릿처럼 큰 화면을 분할 해서 디자인 하기 위해서 고안

 

뷰 -> 프래그먼트 -> 액티비티

화면에 보여지는 API

 

=> 특정 기능을 제공하는 프래그먼트 

 

1. ListFragment : ListView 형태의 프래그먼트

 

2. WebViewFragment  WebView 를 내장하고 있는 프래그먼트

 

3. Dialog 프래그먼트 : 대화 상자를 내장하고 있는 프래그먼트

 

3개의 버튼을 배치해서 각각의 버튼을 누르면 각각의 Fragment 를 출력하기

1. 프로젝트나 모듈 생성

2. 오픈 소스 라이브러리나 Support 

3. Layout 생성

 

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="16dp"
    android:orientation="vertical">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">
        <Button
            android:id="@+id/main_btn1"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="Fragment 1"/>
        <Button
            android:id="@+id/main_btn2"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="Fragment 2"/>
        <Button
            android:id="@+id/main_btn3"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="Fragment 3"/>
    </LinearLayout>
    <LinearLayout
        android:id="@+id/main_container"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">
    </LinearLayout>
</LinearLayout>

4. 3 번째 프래그먼트 화면으로 이용할 레이아웃을 생성 : fragment_three.xml

 

fragment_three.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="match_parent"
    android:orientation="vertical">
    <TextView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:text="Three Fragment!!"
        android:textStyle="bold"
        android:textSize="30dp"
        android:gravity="center"
        />
</LinearLayout>

 

OneFragment.kt

package kr.co.tjoeun.android1110

import android.os.Bundle
import android.view.View
import android.widget.ArrayAdapter
import android.widget.ListAdapter
import android.widget.ListView
import android.widget.Toast
import androidx.fragment.app.ListFragment

class OneFragment : ListFragment() {
    // 뷰가 만들어질 때 리스트 뷰 출력 설정
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        // 데이터 생성
        var datas = arrayOf("캡슐화", "상속", "다형성")
        // 어댑터 생성
        var adapter = ArrayAdapter(activity!!, android.R.layout.simple_list_item_1, datas)
        // 리스트 뷰에 어댑터 설정
        listAdapter = adapter
    }

    // 셀을 선택했을 때 선택할 셀의 문자열을 토스트로 출력
    override fun onListItemClick(l: ListView, v: View, position: Int, id: Long) {
        super.onListItemClick(l, v, position, id)
        Toast.makeText(activity!!,
            l.adapter.getItem(position) as String, Toast.LENGTH_LONG).show()
    }
}

 

TwoFragment.kt

package kr.co.tjoeun.android1110

import android.app.AlertDialog
import android.app.Dialog
import android.os.Bundle
import androidx.fragment.app.DialogFragment

class TwoFragment : DialogFragment() {
    override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
        val builder = AlertDialog.Builder(activity)
        builder.setIcon(android.R.drawable.ic_dialog_alert)
        builder.setTitle("DialogFragment")
        builder.setMessage("내용입니다")
        builder.setPositiveButton("확인", null)

        return builder.create()
        //return super.onCreateDialog(savedInstanceState)
    }
}

 

ThreeFragment.kt

package kr.co.tjoeun.android1110

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment

class ThreeFragment : Fragment(){
    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        return inflater.inflate(R.layout.fragment_three, container, false)
    }
}

 

MainActivity.kt

package kr.co.tjoeun.android1110

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.fragment.app.FragmentManager
import androidx.fragment.app.FragmentTransaction

import kotlinx.android.synthetic.main.activity_main.*

class MainActivity : AppCompatActivity() {
    // 보여주고자 하는 Fragment  변수를 선언
    var oneFragment:OneFragment? = null
    var twoFragment:TwoFragment? = null
    var threeFragment:ThreeFragment? = null

    // Fragment 관리 객체 변수 생성
    var manager:FragmentManager? = null

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

        // 변수들에 인스턴스 대입
        oneFragment = OneFragment()
        twoFragment = TwoFragment()
        threeFragment = ThreeFragment()

        manager = supportFragmentManager

        // 첫번째 Fragment 출력
        val tf:FragmentTransaction = manager!!.beginTransaction()
        tf.addToBackStack(null)
        tf.add(R.id.main_container, oneFragment!!)
        tf.commit()

        // General
        main_btn1.setOnClickListener {
            if(!oneFragment!!.isVisible) {
                val tf:FragmentTransaction = manager!!.beginTransaction()
                tf.addToBackStack(null)
                tf.replace(R.id.main_container, oneFragment!!)
                tf.commit()
            }
        }
        // Dialog
        main_btn2.setOnClickListener {
            if(!twoFragment!!.isVisible) {
                twoFragment!!.show(manager!!, null)
            }
        }
        
        main_btn3.setOnClickListener {
            if(!threeFragment!!.isVisible) {
                val tf:FragmentTransaction = manager!!.beginTransaction()
                tf.addToBackStack(null)
                tf.replace(R.id.main_container, threeFragment!!)
                tf.commit()
            }
        }
    }
}

 

 

ViewPager 

스와이프를 이용해서 화면전환을 하는 어댑터 뷰

 

1. ViewPager 를 뷰에 적당한 위치에 배치

 

2. FragmentPagerAdapter 로 부터 상속 받는 클래스를 생성

=> Fragment List 를 생성

 

1) getCount() 를 재정의 해서 몇 개의 화면을 만들 것인지 리턴을 해줍니다.

2) getItem() 을 재정의 해서 어떤 프래그먼트를 리턴 할 것인지 설정

 

3. ViewPager 에 Adapter 연결

 

RecyclerView

ListView 처럼 여러개의 데이터를 여러 항목 뷰를 이용해서 출력할 수 있는 뷰

헤더 뷰나 푸터 뷰를 만들 수 있습니다.

전체의 디자인 가능

아이템 추가하거나 삭제 및 정렬을 할 때 애니메이션을 추가하는 것도 가능

 

 

5개의 클래스

Adapter: 항목 구성

ViewHolder: 화면에 보여지는 각 항목의 구성 뷰

LayoutManager : 항목의 배치

ItemDecoration : 항목을 꾸미는 것

ItemAnimation : 항목 별 애니메이션 설정 가능

 

RecyclerView 에서 header 나 footer 를 만들고자 하는 경우에는 데이터를 1개나 2개를 더 출력을 해야합니다.

 

2. 항목 뷰, 헤더 뷰, 푸터 뷰 디자인 파일을 생성

헤더 뷰 디자인: header.xml

항목 뷰 디자인 : footer.xml

3. 출력할 뷰 홀더를 생성

헤더 뷰 홀더, 항목 뷰 홀더, 푸터 뷰 홀더를 생성

 

4. Adapter 생성

=> 데이터 개수는 헤더와 푸터의 개수를 더해야 합니다.

 

RecyclerActivity.kt

package kr.co.tjoeun.android1110

import android.graphics.BitmapFactory
import android.graphics.Canvas
import android.graphics.Rect
import android.graphics.drawable.Drawable
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import android.widget.Toast
import androidx.core.content.res.ResourcesCompat
import androidx.core.view.ViewCompat
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.LinearSmoothScroller
import androidx.recyclerview.widget.RecyclerView
import kotlinx.android.synthetic.main.activity_recycler.*

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

        val list: MutableList<String> = ArrayList()
        list.add("태연")
        list.add("제시카")
        list.add("유리")
        list.add("티파니")
        list.add("수영")
        list.add("써니")
        list.add("효연")
        list.add("윤아")
        list.add("서현")
        list.add("태연")
        list.add("제시카")
        list.add("유리")
        list.add("티파니")
        list.add("수영")
        list.add("써니")
        list.add("효연")
        list.add("윤아")
        list.add("서현")
        list.add("태연")
        list.add("제시카")
        list.add("유리")
        list.add("티파니")
        list.add("수영")
        list.add("써니")
        list.add("효연")
        list.add("윤아")
        list.add("서현")

        recycler. setLayoutManager(LinearLayoutManager(this))
        recycler.adapter = MyAdapter(list)
        recycler.addItemDecoration(MyItemDecoration())

        btn.setOnClickListener {
            val smoothScroller: RecyclerView.SmoothScroller by lazy {
                object : LinearSmoothScroller(this@RecyclerActivity) {
                    override fun getVerticalSnapPreference() = SNAP_TO_START
                }
            }
            smoothScroller.targetPosition = 0
            recycler.layoutManager?.startSmoothScroll(smoothScroller)
        }
    }


    internal class HeaderViewHolder(headerView: View?) :
        RecyclerView.ViewHolder(headerView!!)

    internal class FooterViewHolder(footerView: View?) :
        RecyclerView.ViewHolder(footerView!!)

    class MyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView), View.OnClickListener {
        var title: TextView

        init {
            title = itemView.findViewById(android.R.id.text1)
        }

        //데이터를 매핑
        fun onBind(data: String) {
            title.setText(data.toString())
            itemView.setOnClickListener(this)
        }

        // 항목을 클릭하면 호출될 메소드
        override fun onClick(v: View) {
            Toast.makeText(title.context, title.text, Toast.LENGTH_SHORT)
                .show()
        }
    }

    class MyAdapter(var list: List<String>) :
        RecyclerView.Adapter<RecyclerView.ViewHolder>() {
        override fun onCreateViewHolder(viewGroup: ViewGroup, i: Int): RecyclerView.ViewHolder {
            // 뷰 모양이 0 번 일 때 Header 출력
            if (i == 0) {
                val view =
                    LayoutInflater.from(viewGroup.context)
                        .inflate(R.layout.header, viewGroup, false)
                return HeaderViewHolder(view)
            }
            // 2번일 때는 footer 출력
            else if (i == 2) {
                val view = LayoutInflater.from(viewGroup.context)
                    .inflate(R.layout.footer, viewGroup, false);
                return FooterViewHolder(view);
            }
            // 나머지는 일반 항목 뷰 출력
            else {
                val view = LayoutInflater.from(viewGroup.context)
                    .inflate(android.R.layout.simple_list_item_1, viewGroup, false)
                return MyViewHolder(view)
            }
        }
        // 데이터의 개수를 리턴 할 때 헤더와 푸터의 개수만큼 추가해서 리컨

        override fun getItemCount(): Int {
            return list.size + 2
        }

        override fun onBindViewHolder(myViewHolder: RecyclerView.ViewHolder, i: Int) {
            if (myViewHolder is HeaderViewHolder) {
                val headerViewHolder = myViewHolder as HeaderViewHolder
            } else if (myViewHolder is FooterViewHolder) {
                val footerViewHolder = myViewHolder as FooterViewHolder
            } else {
                // Item을 하나, 하나 보여주는(bind 되는) 함수입니다.
                val itemViewHolder: MyViewHolder = myViewHolder as MyViewHolder
                itemViewHolder.onBind(list.get(i - 1))
            }
        }

        override fun getItemViewType(position: Int): Int {
            if (position == 0)
                return 0;
            else if (position == list.size + 1)
                return 2;
            else
                return 1;
        }


    }

    // 각 항목 여백 설정
    inner class MyItemDecoration : RecyclerView.ItemDecoration() {
        override fun getItemOffsets(
            outRect: Rect,
            view: View,
            parent: RecyclerView,
            state: RecyclerView.State
        ) {
            super.getItemOffsets(outRect, view, parent, state!!)
            // 각 항목 마다 여백 다르게 설정
            val index: Int = parent.getChildAdapterPosition(view) + 1
            if (index % 3 == 0) {
                outRect.set(20, 20, 20, 60)
            } else {
                outRect.set(20, 20, 20, 20)
            }
            // 배경 색과 그림자 처럼 떠있는 효과
            view.setBackgroundColor(-0x131617)
            ViewCompat.setElevation(view, 20.0f)
        }

        // 항목위에 그림그리는 메소드
        override fun onDrawOver(c: Canvas, parent: RecyclerView, state: RecyclerView.State) {
            super.onDrawOver(c, parent, state)
            val width: Int = parent.getWidth()
            val height: Int = parent.getHeight()
            val dr: Drawable? = ResourcesCompat.getDrawable(resources, R.drawable.img, null)
            val drWidth: Int = dr!!.getIntrinsicWidth()
            val drHeight: Int = dr.getIntrinsicHeight()
            val left = width / 2 - drWidth / 2
            val top = height / 2 - drHeight / 2
            c.drawBitmap(
                BitmapFactory.decodeResource(getResources(), R.drawable.img),
                left.toFloat(),
                top.toFloat(),
                null
            )
        }
    }
}

그룹화 출력

(("김태균", "권혁"), ("나성범").. ) 이런 형태는 그룹 별 출력을 못합니다.

({"title":"ㄱ", "data":("김태균","권혁")}, {"title":"ㄴ", "data":("나성범")})

 

여러개의 데이터를 그룹 별로 출력하고자 할 때는 배열의 배열을 만들지 말고 Map 을 만들어서 배열의 특징과 배열을 하나의 Map으로 만들고 Map의 배열을 생성해야합니다.

 

List<String>kia = new ArrayList< > ();

kia.add("kim");

kia.add("lee");



List<String>lg = new ArrayList< > ();

kia.add("ha");

kia.add("jin");



List<String>ob = new ArrayList< > ();

kia.add("yoo");

List<List<String>> players = new ArrayList<>();

players.add(kia);

players.add(lg);

players.add(ob);



Map<String, Object>map1 = new HashMap<>()

map1.add("team", "kia")

map1.add("team", "kia")



Map<String, Object>map2 = new HashMap<>()

map1.add("team", "lg")

map1.add("team", "lg")



Map<String, Object>map3 = new HashMap<>()

map3.add("team", "ob")

map3.add("team", "ob")



List<Map<String, Object>> players = new ArrayList<>();

players.add(map1);

players.add(map2);



for(int i =0; i<player.size(); i++){

    Map <String, Object> map = players.get(i);

   print(map.get("team"));

List<String> list = map.get("data");

}



for(int i =0; i<player.size(); int++){

    if(i==0){

        print("kia");

    } else if (i== 1){

        print("lg"); 

   }

    List<String> p = players.get(i);

}

 

그룹별 분류를 위한 데이터는 List -> Map -> List

List  -> List 구조는 이미지를 표현하거나 Machine Learning 을 할 때 주로 이용합니다.

 

안드로이드는 컴포넌트 기반 개발 방법입니다.

클래스는 개발자가 만들지만 인스턴스는 개발자가 만들지 않습니다.
인스턴스의 수명주기를 안드로이드가 관리합니다.

 

 

안드로이드의 4대 컴포넌트 

=> Activity : 화면

=> BraodCast: 알림 

=> Service: 백그라운드에서 작업 수행 - 스레드는 앱이 종료되면 더이상 작업을 못함

=> ContentProvider: 다른 앱과 데이터를 공유하기 위한 컴포넌트

 

Service 는 Broadcast 와 같이 사용

 

Broadcast Receiver 

=> 앱에게 어떤 상황이 발생한 것을 알려주는 것

=> BroadcastReceiver 로 부터 상속을 받은 후 onReceive 메소드를 재정의 해서 알림이 왔을 때 수행할 동작을 작성

 

리시버를 실행 하는 방법

1. 명시적 인텐트를 이용

val intent : Intent = Intent(Context, 리시버클래스.class)

sendBroadcast(intent)

2. 리시버를 만들고 AndroidManifest.xml 파일에 intent-filter 를 이용해서 액션 문자열을 등록해서 암시적 인텐트로 수행

예전에는 액션 문자열을 직접 정의하는 것도 가능했는데 지금은 시스템 이벤트만 가능

암시적 인텐트 형태로 실행하는 것을 금지합니다.

 

AndroidMenifest.xml

        <receiver
            android:name=".MyReceiver"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED">

                </action>
            </intent-filter>

        </receiver>

 MyReciever.kt

package kr.co.tjoeun.android1110

import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.util.Log
import android.widget.Toast

class MyReceiver : BroadcastReceiver() {

    override fun onReceive(context: Context, intent: Intent) {
        // This method is called when the BroadcastReceiver is receiving an Intent broadcast.
        Toast.makeText(context, "브로드캐스트 연습", Toast.LENGTH_LONG).show()
        Log.e("Meassage", "Respond to System Event")
    }
}

 

에뮬레이터 재부팅

AppData\Local\Android\Sdk\platform-tools

adb reboot