android java

리사이클러뷰 및 리사이클러뷰 아답터, 뷰홀더 정리

안드로이드 샘플

 /**
 * 리스트뷰 생성을 위한 아답터 생성. 리사이클러뷰 아답터 상속 및 뷰홀더 지정.
 */
public class CustomAdapter extends RecyclerView.Adapter {

    /**로그캣 태그*/
    private static final String TAG = "CustomAdapter";
    /**데이터셋 정리*/
    private String[] mDataSet;

    // BEGIN_INCLUDE(recyclerViewSampleViewHolder)
    /**
     * 리사이클러뷰 사용할 뷰홀더 생성 및 상속
     */
    public static class ViewHolder extends RecyclerView.ViewHolder {
    /**텍스트뷰 선언*/
        private final TextView textView;
/**홀더 생성자.*/
        public ViewHolder(View v) {
            super(v);
            /**홀더 클릭리스터 등록.(리스트뷰 클릭)*/
            v.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Log.d(TAG, "Element " + getAdapterPosition() + " clicked.");
                }
            });
            textView = (TextView) v.findViewById(R.id.textView);
        }

        public TextView getTextView() {
            return textView;
        }
    }
    // END_INCLUDE(recyclerViewSampleViewHolder)


    /**
     * Initialize the dataset of the Adapter.
     *
     * @param dataSet String[] containing the data to populate views to be used by RecyclerView.
     * 아답터에 데이터 등록
     */
    public CustomAdapter(String[] dataSet) {
        mDataSet = dataSet;
    }

    // BEGIN_INCLUDE(recyclerViewOnCreateViewHolder)
    // Create new views (invoked by the layout manager)
    @Override
    public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
        // Create a new view.
/** 리스트뷰 생성을 위한 뷰 등록 */
        View v = LayoutInflater.from(viewGroup.getContext())
                .inflate(R.layout.text_row_item, viewGroup, false);

        return new ViewHolder(v);
    }
    // END_INCLUDE(recyclerViewOnCreateViewHolder)

    // BEGIN_INCLUDE(recyclerViewOnBindViewHolder)
    // Replace the contents of a view (invoked by the layout manager)
    @Override
    public void onBindViewHolder(ViewHolder viewHolder, final int position) {
        Log.d(TAG, "Element " + position + " set.");

        // Get element from your dataset at this position and replace the contents of the view
        // with that element
/**홀더로 생성된 뷰의 데이터 삽입*/
        viewHolder.getTextView().setText(mDataSet[position]);
    }
    // END_INCLUDE(recyclerViewOnBindViewHolder)

    // Return the size of your dataset (invoked by the layout manager)
    /**데이터의 크기 가져오기.*/
    @Override
    public int getItemCount() {
        return mDataSet.length;
    }
}


Activity 또는 Fragment 에서 


레이아웃 속성 정의.
정의한 데이터를 아답터 생성할때 데이터 삽입.
리사이클러뷰에 아답터 등록.





TabLayout _ 코틀린




탭레이아웃 사용하기


탭레이아웃을 사용하기 위한 디펜던시 추가.


프로젝트 생성 후 build.gradle(app) 아래 코드를 추가.


dependencies {

...

...

implementation 'com.android.support:design:x.y.z //추가.

}



3개의 프래그먼트를 뵤여주기 위해 탭 레이아웃 과 뷰페이저를 xml에 등록함.

//////////////////////////////////////////////////////////////////////////////////////////

xml 소스 구성.

activity_main.xml


상단 

//////////////////////////////////////////////////////////////////////////////////////////

<?xml version="1.0" encoding="utf-8"?>

<android.support.constraint.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=".activity.MainActivity">


    <android.support.design.widget.TabLayout


        android:id="@+id/tabLayout"

        android:layout_width="match_parent"

        android:layout_height="?android:attr/actionBarSize"

        app:layout_constraintBottom_toTopOf="@+id/viewPager"

        app:layout_constraintLeft_toLeftOf="parent"

        app:layout_constraintRight_toRightOf="parent"


        app:layout_constraintTop_toTopOf="parent"


        >


    </android.support.design.widget.TabLayout>



    <android.support.v4.view.ViewPager

        android:id="@+id/viewPager"

        android:layout_width="match_parent"

        android:layout_height="0dp"


        app:layout_constraintBottom_toBottomOf="parent"

        app:layout_constraintLeft_toLeftOf="parent"

        app:layout_constraintRight_toRightOf="parent"

        app:layout_constraintTop_toBottomOf="@+id/tabLayout">


    </android.support.v4.view.ViewPager>



</android.support.constraint.ConstraintLayout>

//////////////////////////////////////////////////////////////////////////////////////////


하단

//////////////////////////////////////////////////////////////////////////////////////////

<?xml version="1.0" encoding="utf-8"?>

<android.support.constraint.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=".MainActivity">

    

    <android.support.v4.view.ViewPager

        android:id="@+id/viewPager"

        android:layout_width="match_parent"

        android:layout_height="0dp"

        app:layout_constraintBottom_toTopOf="@+id/tabLayout"

        app:layout_constraintLeft_toLeftOf="parent"

        app:layout_constraintRight_toRightOf="parent"

        app:layout_constraintTop_toTopOf="parent">

    </android.support.v4.view.ViewPager>


    <android.support.design.widget.TabLayout

        android:id="@+id/tabLayout"

        android:layout_width="match_parent"

        android:layout_height="?android:attr/actionBarSize"

        app:layout_constraintBottom_toBottomOf="parent"

        app:layout_constraintLeft_toLeftOf="parent"

        app:layout_constraintRight_toRightOf="parent"

        app:layout_constraintTop_toBottomOf="@+id/viewPager">

    </android.support.design.widget.TabLayout>


</android.support.constraint.ConstraintLayout>

//////////////////////////////////////////////////////////////////////////////////////////


뷰 페이저 안에 탭 레이아웃 포함.(상단.)

//////////////////////////////////////////////////////////////////////////////////////////

<?xml version="1.0" encoding="utf-8"?>

<android.support.constraint.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=".activity.MainActivity">



    <android.support.v4.view.ViewPager

        android:id="@+id/viewPager"

        android:layout_width="match_parent"

        android:layout_height="match_parent"

        app:layout_constraintBottom_toBottomOf="parent"

        app:layout_constraintLeft_toLeftOf="parent"

        app:layout_constraintRight_toRightOf="parent"

        app:layout_constraintTop_toTopOf="parent">



        <android.support.design.widget.TabLayout


            android:id="@+id/tabLayout"

            android:layout_width="match_parent"

            android:layout_height="?android:attr/actionBarSize">


        </android.support.design.widget.TabLayout>



    </android.support.v4.view.ViewPager>




//////////////////////////////////////////////////////////////////////////////////////////



MainActivity.kt 소스 작성.

탭레이아웃을 구성하기 위한 ui 정의 및 프래그먼트 데이터 생성.


class MainActivity : AppCompatActivity() {


    override fun onCreate(savedInstanceState: Bundle?) {

        super.onCreate(savedInstanceState)

        setContentView(R.layout.activity_main)


        setupUI()

    }


    //UI 초기화.

    private fun setupUI() {


        setupTabLayout()

    }


    // 탭 레이아웃 설정.

    private fun setupTabLayout() {


        val pageAdapter = MainViewPagerAdapter(setFragmentList(), supportFragmentManager)

        viewPager.adapter = pageAdapter


        tabLayout.setupWithViewPager(viewPager)


    }


    // 프래그먼트 리스트 설정.

    private fun setFragmentList(): List<Pair<Fragment, String>> {

//        val pageList = listOf(

//            Pair(MainFragment_1.newInstance(), "first"),

//            Pair(MainFragment_2.newInstance(), "first"),

//            Pair(MainFragment_3.newInstance(), "first")

//        )

//        return pageList


        return listOf(

            Pair(MainFragment_1.newInstance(), "first"),

            Pair(MainFragment_2.newInstance(), "second"),

            Pair(MainFragment_3.newInstance(), "third")

        )

    }


    // 프래그먼트 리스트 설정.

    private fun setFragmentList2() = listOf(

        Pair(MainFragment_1.newInstance(), "first"),

        Pair(MainFragment_2.newInstance(), "second"),

        Pair(MainFragment_3.newInstance(), "third")

    )


}

//////////////////////////////////////////////////////////////////////////////////////////

ViewPagerAdapter 소스(FragmentPagerAdapter)


class MainViewPagerAdapter(val pageList: List<Pair<Fragment, String>>, fragmentManager: FragmentManager) :

    FragmentPagerAdapter(fragmentManager) {



    override fun getItem(position: Int): Fragment {

        return pageList[position].first

    }


    override fun getCount(): Int {

        return pageList.size

    }


    override fun getPageTitle(position: Int): CharSequence? {

//        return super.getPageTitle(position)

        return pageList[position].second

    }


}

//////////////////////////////////////////////////////////////////////////////////////////


보여줄 프래그먼트 소스.



private const val ARG_PARAM1 = "param1"

private const val ARG_PARAM2 = "param2"



class MainFragment_1 : Fragment() {


    private var param1: String? = null

    private var param2: String? = null


    override fun onCreate(savedInstanceState: Bundle?) {

        super.onCreate(savedInstanceState)

        arguments?.let {

            param1 = it.getString(ARG_PARAM1)

            param2 = it.getString(ARG_PARAM2)

        }

    }


    override fun onCreateView(

        inflater: LayoutInflater, container: ViewGroup?,

        savedInstanceState: Bundle?

    ): View? {


        return inflater.inflate(R.layout.fragment_main_fragment_1, container, false)

    }


    companion object {

        // param을 null로 처리하면 인자를 따로 추가 안해도 된다.

        // 인자값을 추가할 경우 해당 데이터가 저장된다.

        @JvmStatic

        fun newInstance(param1: String? = null, param2: String? = null) =

            MainFragment_1().apply {

                arguments = Bundle().apply {

                    putString(ARG_PARAM1, param1)

                    putString(ARG_PARAM2, param2)

                }

            }

    }

}


//////////////////////////////////////////////////////////////////////////////////////////

탭 레이아웃 기본 정리





















코디네이터레이아웃 사용해서 스크롤시 

툴바 및 리사이클러뷰 스크롤시 최상단 및 최하단 터치 감지가 불량일 때가 있다.

최상단 혹은 최하단 스크롤 후 리스트 항목을 클릭이 되지 않아 두번 클릭해야하는데 


안드로이드 sdk 28에서는 정상동작 한다.

이전 버전에서 AppBarLayout.Behavior 에 버그가 있는듯.



android coordinatorlayout recyclerview scroll click

이렇게 검색하니 스택오버플로우에 올라온 글

Click not working on RecyclerView in CoordinatorLayout when scrolling



게시글 중 해당 링크가 있고 수정된 코드 java와 kotlin이 있음.


https://gist.github.com/chrisbanes/8391b5adb9ee42180893300850ed02f2



수정된 코드소스

java

//////////////////////////////////////////////////////////////////////////////////////////

/**

 * Workaround AppBarLayout.Behavior for https://issuetracker.google.com/66996774

 *

 * See https://gist.github.com/chrisbanes/8391b5adb9ee42180893300850ed02f2 for

 * example usage.

 *

 * Change the package name as you wish.

 */

public class FixAppBarLayoutBehavior extends AppBarLayout.Behavior {


    public FixAppBarLayoutBehavior() {

        super();

    }


    public FixAppBarLayoutBehavior(Context context, AttributeSet attrs) {

        super(context, attrs);

    }


    @Override

    public void onNestedScroll(CoordinatorLayout coordinatorLayout, AppBarLayout child, View target,

            int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, int type) {

        super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed,

                dxUnconsumed, dyUnconsumed, type);

        stopNestedScrollIfNeeded(dyUnconsumed, child, target, type);

    }


    @Override

    public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, AppBarLayout child,

            View target, int dx, int dy, int[] consumed, int type) {

        super.onNestedPreScroll(coordinatorLayout, child, target, dx, dy, consumed, type);

        stopNestedScrollIfNeeded(dy, child, target, type);

    }


    private void stopNestedScrollIfNeeded(int dy, AppBarLayout child, View target, int type) {

        if (type == ViewCompat.TYPE_NON_TOUCH) {

            final int currOffset = getTopAndBottomOffset();

            if ((dy < 0 && currOffset == 0)

                    || (dy > 0 && currOffset == -child.getTotalScrollRange())) {

                ViewCompat.stopNestedScroll(target, ViewCompat.TYPE_NON_TOUCH);

            }

        }

    }

}


//////////////////////////////////////////////////////////////////////////////////////////


kotlin

//////////////////////////////////////////////////////////////////////////////////////////

/**

 * Workaround AppBarLayout.Behavior for https://issuetracker.google.com/66996774

 *

 *

 * See https://gist.github.com/chrisbanes/8391b5adb9ee42180893300850ed02f2 for

 * example usage.

 *

 * Kotlinised by Erik Huizinga (github: @erikhuizinga).

 */

class FixAppBarLayoutBehavior(context: Context?, attrs: AttributeSet?) :

AppBarLayout.Behavior(context, attrs) {


override fun onNestedScroll(coordinatorLayout: CoordinatorLayout, child: AppBarLayout,

                            target: View, dxConsumed: Int, dyConsumed: Int, dxUnconsumed: Int,

                            dyUnconsumed: Int, type: Int) {

super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed, dxUnconsumed,

dyUnconsumed, type)

stopNestedScrollIfNeeded(dyUnconsumed, child, target, type)

}


override fun onNestedPreScroll(coordinatorLayout: CoordinatorLayout, child: AppBarLayout,

                               target: View, dx: Int, dy: Int, consumed: IntArray, type: Int) {

super.onNestedPreScroll(coordinatorLayout, child, target, dx, dy, consumed, type)

stopNestedScrollIfNeeded(dy, child, target, type)

}


private fun stopNestedScrollIfNeeded(dy: Int, child: AppBarLayout, target: View, type: Int) {

if (type == ViewCompat.TYPE_NON_TOUCH) {

val currOffset = topAndBottomOffset

if (dy < 0 && currOffset == 0 || dy > 0 && currOffset == -child.totalScrollRange) {

ViewCompat.stopNestedScroll(target, ViewCompat.TYPE_NON_TOUCH)

}

}

}

}

//////////////////////////////////////////////////////////////////////////////////////////


코드 사용법 

AppBarLayout abl = findViewById(R.id.app_bar);

((CoordinatorLayout.LayoutParams) abl.getLayoutParams()).setBehavior(new FixAppBarLayoutBehavior());



xml 사용법

<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"

        xmlns:app="http://schemas.android.com/apk/res-auto"

        android:layout_width="match_parent"

        android:layout_height="match_parent">


    <android.support.design.widget.AppBarLayout

            android:id="@+id/app_bar"

            android:layout_height="..."

            android:layout_width="..."

            app:layout_behavior="your.package.FixAppBarLayoutBehavior">


    </android.support.design.widget.AppBarLayout>


    <!-- Content -->


</android.support.design.widget.CoordinatorLayout>






2-2 펴미션 구현.

상속을 통한 퍼미션 구현.


BaseActivity 소스 추가.

//////////////////////////////////////////////////////////////////////////////////////////

abstract class BaseActivity extends AppCompatActivity {


    abstract int setLayout();


    @Override

    protected void onCreate(@Nullable Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(setLayout());

    }



/**

* 아래 소스 추가 부분.

*/


    /**

     * 앱 퍼미션 권한 사용하기 위하여 상속을 이용

     * 퍼미션 체크가 끝나면 동작할 인터페이스 리스너 생성

     * 퍼미션 체크 메서드 구현.

     * onRequestPermissionsResult 를 동작하고 난뒤 액티비티로 돌아와 나머지 동작 구현 확인.

     * 리스너 등록하여 퍼미션 체크한 액티비티로 돌아가기.

     */


    /**

     * 인터페이스 등록.

     */

    public interface PermissionCheckListener {

        void permissionCheckFinish();

    }


    /**

     * 상속받은 클래스에서 사용할 인터페이스 변수.

     */

    public PermissionCheckListener permissionCheckListener;


    /**

     * 온 크레딧 바로 아래 생성 되어야 한다

     */

    public void setPermissionCheckListener(PermissionCheckListener permissionCheckListener) {

        this.permissionCheckListener = permissionCheckListener;

    }


    private final int PERMISSION_REQUEST = 1000;


    /**

     * 스트링 배열로 퍼미션 체크.

     */


    public boolean permissionCheck(String[] strings) {


        //  변수 사용시 리턴 타입 지정

        // boolean check = false;

        // 변수 사용안하면 바로 리턴 시킴.



        /**안드로이드 마시멜로 이후 퍼미션 체크.*/

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {

            for (int i = 0; i < strings.length; i++) {

                if (ContextCompat.checkSelfPermission(this, strings[i]) == PackageManager.PERMISSION_DENIED) {

                    ActivityCompat.requestPermissions(this, strings, PERMISSION_REQUEST);

                    // check = true;

                    // break;

                    return true;

                }

            }

        }

//return check;

        return false;

    }


    /**

     * 거부를 했을때 처리

     * 다시보지 않기 체크 후 거부를 하면 설정에서 권한을 허용하도록 요청.

     * 허용하지 않을 경우 앱 사용 을 못함..

     * 처리를 잘못하면 무한 반복할 경우가 생김.

     */


    @Override

    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {


        super.onRequestPermissionsResult(requestCode, permissions, grantResults);



        if (requestCode == PERMISSION_REQUEST) {

            //안드로이드 마시멜로 이후 퍼미션 체크.

            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {

                for (int i = 0; i < grantResults.length; i++) {

                    if (grantResults[i] == 0) {

                        if (grantResults.length == (i + 1)) {

                            permissionCheckListener.permissionCheckFinish();

                        }

                    } else {

                        // 거부한 이력이 있으면 true를 반환한다.

                        if (shouldShowRequestPermissionRationale(permissions[i])) {

                            ActivityCompat.requestPermissions(this, permissions, PERMISSION_REQUEST);

                            break;


                        } else {

                            new AlertDialog.Builder(this)

                                    .setTitle("다시보지않기 클릭.")

                                    .setMessage(permissions[i] + " 권한이 거부되었습니다 설정에서 직접 권한을 허용 해주세요.")

                                    .setNeutralButton("설정", new DialogInterface.OnClickListener() {


                                        @Override

                                        public void onClick(DialogInterface dialog, int which) {


                                            Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);

                                            intent.setData(Uri.parse("package:" + getPackageName()));

                                            startActivity(intent);

                                            Toast.makeText(getApplicationContext(), "권한 설정 후 다시 실행 해주세요.", Toast.LENGTH_SHORT).show();

                                            finish();

                                        }

                                    })

                                    .setPositiveButton("확인", new DialogInterface.OnClickListener() {


                                        @Override

                                        public void onClick(DialogInterface dialog, int which) {

                                            Toast.makeText(getApplicationContext(), "권한 설정을 하셔야 앱을 사용할 수 있습니다.", Toast.LENGTH_SHORT).show();

                                            finish();

                                        }

                                    })

                                    .setCancelable(false)

                                    .create().show();

                        }// shouldShowRequestPermissionRationale /else

                    } // 권한 거절

                } // for end

            }//Build.VERSION.SDK_INT  end

        }//requestCode  end

    }

}

//////////////////////////////////////////////////////////////////////////////////////////






MainActivity에서 사용 방법.


Manifest에 

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

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

퍼미션 등록 확인.

//////////////////////////////////////////////////////////////////////////////////////////

public class MainActivity extends BaseActivity {


    @Override

    int setLayout() {

        // BaseActivit에서 만들어 놓은 추상 메서그 구현.

        // setContentView(R.layout.activity_main);

        // 추상메서드로 구현.

        return R.layout.activity_main;

    }


    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);


        /**

         * 리스너 등록

         * 퍼미션 검사가 끝나고 또는 검사 체크 후 구현 될 부분

         */

        setPermissionCheckListener(new PermissionCheckListener() {

            @Override

            public void permissionCheckFinish() {


                Log.e("log", "start Activity");

            }

        });


        /**

         * Manifest 에서 uses-permission 에 등록한 퍼미션 을 배열로 전달

         * 권한 승인을 해야할려면 true 권한 승인이 모두 완료 되어 있다면 false

         * 권한 체크가 되어 있다면 지나간다.

         */

        if (permissionCheck(new String[]{Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE})) {

            return;

        }


        /**퍼미션 체크 리스너 등록*/

        permissionCheckListener.permissionCheckFinish();

    }

}

//////////////////////////////////////////////////////////////////////////////////////////



상속을 이용한 퍼미션 권한 체크 확인 완료.



'Android > source code' 카테고리의 다른 글

TabLayout 예제  (0) 2018.11.08
코디네이터레이아웃에 리사이클러뷰 스크롤시 터치 오류  (0) 2018.10.17
Android RecyclerView 예제  (0) 2018.10.15
동적 레이아웃 등록(xml)  (0) 2018.10.11
액티비티  (0) 2018.09.18

리사이클러뷰 프로젝트.


매인 액티비티(Empty Activity) 생성.

/////////////////////////////////////////////////////////////////////////////////////////

public class MainActivity extends AppCompatActivity {


    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);


    }

}

/////////////////////////////////////////////////////////////////////////////////////////


Build.gradle(Module:app)에 com.android.support:recyclerview-v7 모듈 추가

/////////////////////////////////////////////////////////////////////////////////////////

dependencies {

    implementation fileTree(include: ['*.jar'], dir: 'libs')

    implementation 'com.android.support:appcompat-v7:28.0.0'

    implementation 'com.android.support.constraint:constraint-layout:1.1.3'

    testImplementation 'junit:junit:4.12'

    androidTestImplementation 'com.android.support.test:runner:1.0.2'

    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'

    implementation 'com.github.bearkinf:AndroidLogPrintUtil_Java:1.1.1'

    //리사이클러뷰 모듈 추가.

    implementation 'com.android.support:recyclerview-v7:28.0.0'

}

/////////////////////////////////////////////////////////////////////////////////////////


리사이클러뷰에 사용할 데이터 생성.

간단한 데이터 출력 하기위한 클래스 생성.

/////////////////////////////////////////////////////////////////////////////////////////

public class People {

    private String name;

    private String age;

    private String address;

    /**

     * 기본 생성자.

     */

    public People() {

    }


    public People(String name) {

        this.name = name;

    }


    public People(String name, String age) {

        this.name = name;

        this.age = age;

    }


    public People(String name, String age, String address) {

        this.name = name;

        this.age = age;

        this.address = address;

    }


    public String getName() {

        return name;

    }


    public void setName(String name) {

        this.name = name;

    }


    public String getAge() {

        return age;

    }


    public void setAge(String age) {

        this.age = age;

    }


    public String getAddress() {

        return address;

    }


    public void setAddress(String address) {

        this.address = address;

    }



    @Override

    public String toString() {

        return "name : " + getName() + " , age : " + getAge() + " , address : " + getAddress();

    }

}

/////////////////////////////////////////////////////////////////////////////////////////



리사이클러뷰에 보여줄 row layout 생성.

간단히 name, age, address 보여줌.

test_list_row.xml

/////////////////////////////////////////////////////////////////////////////////////////

<?xml version="1.0" encoding="utf-8"?>

<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"

    xmlns:app="http://schemas.android.com/apk/res-auto"

    android:layout_width="match_parent"

    android:layout_height="wrap_content">


    <android.support.constraint.ConstraintLayout

        android:layout_width="match_parent"

        android:layout_height="wrap_content"

        android:layout_marginLeft="10dp"

        android:layout_marginTop="10dp"

        android:layout_marginRight="10dp"

        app:layout_constraintTop_toTopOf="parent">


        <TextView

            android:id="@+id/name"

            android:layout_width="match_parent"

            android:layout_height="wrap_content"

            android:text="name"

            app:layout_constraintTop_toTopOf="parent" />


        <TextView

            android:id="@+id/age"

            android:layout_width="match_parent"

            android:layout_height="wrap_content"

            android:text="age"

            app:layout_constraintTop_toBottomOf="@+id/name" />


        <TextView

            android:id="@+id/address"

            android:layout_width="match_parent"

            android:layout_height="wrap_content"

            android:text="address"

            app:layout_constraintTop_toBottomOf="@+id/age" />

    </android.support.constraint.ConstraintLayout>

</android.support.constraint.ConstraintLayout>

/////////////////////////////////////////////////////////////////////////////////////////


뷰홀더 클래스 생성. RecyclerView.ViewHolder 상속

/////////////////////////////////////////////////////////////////////////////////////////

public class TestHolder_1 extends RecyclerView.ViewHolder {


    private TextView name;

    private TextView age;

    private TextView address;

    /**

     * 팩토리 함수 생성.

     * new 하는 것을 줄여준다.

     */

    public static TestHolder_1 newInstance(ViewGroup viewGroup) {

    // 뷰 생성 후 홀더에 등록 하여 객채 생성.

        View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.test_list_row, viewGroup, false);

        return new TestHolder_1(view);

    }


    /**

     * 생성자 초기화

     */

    public TestHolder_1(View itemView) {

        super(itemView);


        name = itemView.findViewById(R.id.name);

        age = itemView.findViewById(R.id.age);

        address = itemView.findViewById(R.id.address);

    }


    public void onBindView(int position, ArrayList<People> list) {

        //화면을 그려주는 곳.

        name.setText(list.get(position).getName());

        age.setText(list.get(position).getAge());

        address.setText(list.get(position).getAddress());


    }

}

/////////////////////////////////////////////////////////////////////////////////////////


리사이클러뷰 아답터 생성.

/////////////////////////////////////////////////////////////////////////////////////////


public class TestAdapter_1 extends RecyclerView.Adapter<TestHolder_1> {

    

    private ArrayList<People> list;

    

    /**생성자 (어레이리스트를 인자로 받음.(초기화됨))*/

    public TestAdapter_1(ArrayList<People> list) {

        this.list = list;

    }


    @NonNull

    @Override

    public TestHolder_1 onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {

        //팩토리 함수를 이용한 홀더 객체 생성.

        return TestHolder_1.newInstance(viewGroup);

    }


    @Override

    public void onBindViewHolder(@NonNull TestHolder_1 testHolder_1, int i) {

        // 홀더에 정의된 함수로 뷰 그리기

        testHolder_1.onBindView(i, list);

    }


    @Override

    public int getItemCount() {

        //리스트 갯수 반환.

        return list.size();

    }

}

/////////////////////////////////////////////////////////////////////////////////////////



리사이클러뷰 레이아웃 등록.

activity_main.xml

/////////////////////////////////////////////////////////////////////////////////////////

<?xml version="1.0" encoding="utf-8"?>

<android.support.constraint.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=".MainActivity">


<!-- 레이아웃 매니저 등록, 수직으로 정렬지정-->

    <android.support.v7.widget.RecyclerView

        android:id="@+id/recyclereView"

        android:layout_width="match_parent"

        android:layout_height="match_parent"

        android:orientation="vertical"

        app:layoutManager="android.support.v7.widget.LinearLayoutManager">


    </android.support.v7.widget.RecyclerView>


</android.support.constraint.ConstraintLayout>

/////////////////////////////////////////////////////////////////////////////////////////



매인 액티비티 소스 완성 

/////////////////////////////////////////////////////////////////////////////////////////

public class MainActivity extends AppCompatActivity {


//리사이클러뷰 등록.

    private RecyclerView recyclerView;

// 아답터 등록.

    private TestAdapter_1 adapter_1;


    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);


        LogPrintUtil.setDebug(BuildConfig.DEBUG ? LogPrintUtil.All : LogPrintUtil.None);

        LogPrintUtil.setTag("bear");

        LogPrintUtil.w("start");


//레이아웃 설정.

        setupUI();


    }



    /**

     * UI 생성

     */

    private void setupUI() {

    

        recyclerView = findViewById(R.id.recyclereView);

        adapter_1 = new TestAdapter_1(makeData());

        recyclerView.setAdapter(adapter_1);

    }


    /**

     * 보여줄 데이터 생성.

     */

    private ArrayList<People> makeData() {


        ArrayList<People> list = new ArrayList<>();

        for (int i = 0; i < 40; i++) {

            People p = new People(i + "a", i + "age", i + "address");

            list.add(p);

        }

        return list;

    }

}


/////////////////////////////////////////////////////////////////////////////////////////





리사이클러뷰 기본 예제 끝.

 




안드로이드 레이아웃 동적 구성.



xml 레이아웃을 이용하여 view 등록 


    private void setupUI() {

// 임시 데이터 생성.

ArrayList<String> list = new ArrayList<>();


        for (int i = 0; i < 5; i++) {

            list.add("i data  ==" + i);

        }

        

        // 데이터 만큼 뷰 등록.        

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

        

            View view = LayoutInflater.from(this).inflate(R.layout.layout_sub, main_Layout, false);

            

            main_Layout.addView(view);


            TextView first = view.findViewById(R.id.first_textview);

            TextView second = view.findViewById(R.id.second_textview);

            TextView third = view.findViewById(R.id.third_textview);


            first.setText("list   :" + list.get(i));


            view.setTag("" + list.get(i));


            view.setOnClickListener(new View.OnClickListener() {

                @Override

                public void onClick(View v) {

                    Log.e("bear", "tag : " + v.getTag());

                }

            });

        }

    }

        

        



////////////////////////////////////////////////////////////////////////////////////////

layout_sub.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:layout_gravity="center"

    android:layout_margin="10dp"

    android:layout_weight="1"

    android:background="#ccc"

    android:gravity="center"

    android:orientation="vertical">


    <LinearLayout

        android:layout_width="match_parent"

        android:layout_height="wrap_content"

        android:orientation="horizontal">


        <TextView

            android:layout_width="wrap_content"

            android:layout_height="wrap_content"

            android:layout_marginLeft="5dp"

            android:text="1 :" />


        <TextView

            android:id="@+id/first_textview"

            android:layout_width="wrap_content"

            android:layout_height="wrap_content"

            android:layout_marginLeft="5dp"

            android:text="1" />


    </LinearLayout>


    <LinearLayout

        android:layout_width="match_parent"

        android:layout_height="wrap_content"

        android:orientation="horizontal">


        <TextView

            android:layout_width="wrap_content"

            android:layout_height="wrap_content"

            android:layout_marginLeft="5dp"

            android:text="2 : " />


        <TextView

            android:id="@+id/second_textview"

            android:layout_width="wrap_content"

            android:layout_height="wrap_content"

            android:layout_marginLeft="5dp"

            android:text="2" />


    </LinearLayout>



    <LinearLayout

        android:layout_width="match_parent"

        android:layout_height="wrap_content"

        android:orientation="horizontal">


        <TextView

            android:layout_width="wrap_content"


            android:layout_height="wrap_content"

            android:layout_marginLeft="5dp"

            android:text="3 : " />


        <TextView

            android:id="@+id/third_textview"

            android:layout_width="wrap_content"

            android:layout_height="wrap_content"

            android:layout_marginLeft="5dp"

            android:text="3" />



    </LinearLayout>

</LinearLayout>


activity_main.xml

<?xml version="1.0" encoding="utf-8"?>

<android.support.constraint.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=".MainActivity">



    <LinearLayout

        android:id="@+id/main_layout"

        android:layout_width="match_parent"

        android:layout_height="match_parent"

        android:orientation="vertical"

        app:layout_constraintBottom_toBottomOf="parent"

        app:layout_constraintLeft_toLeftOf="parent"

        app:layout_constraintRight_toRightOf="parent"

        app:layout_constraintTop_toTopOf="parent">


    </LinearLayout>


</android.support.constraint.ConstraintLayout>




안드로이드 액티비티 


상속을 이용한 베이스() 만들기.




안드로이드 스튜디오 프로젝트 생성.



퍼미션 관련 권한 자동화 시킬려니 동작이 안됨.



/////

/////java

/////

/**

 * 추상화 클래스  상속전용.

 */

abstract class BaseActivity extends AppCompatActivity {


    abstract protected int setContentViewLayout();



    @Override

    protected void onCreate(@Nullable Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(setContentViewLayout());

        Log.e("bear", "BaseActivity start");

        //무언가 하나를 불러내면 딱 하고 끝나서

        // 여러 가지 신경안써도 되는 것....어떻게 해야하지????

        // onRequestPermissionsResult 이것을 baseActivity에서 처리하고 싶다는 건데.

    }



    /**

     * 프래그먼트 add

     * backStackCheck 기본적으로 true

     * .addToBackStack(tag)

     */

    protected void addFragment(int id, Fragment fragment) {

        addFragment(id, fragment, null, true);

    }


    protected void addFragment(int id, Fragment fragment, boolean backStackCheck) {

        addFragment(id, fragment, null, backStackCheck);

    }


    protected void addFragment(int id, Fragment fragment, String tag) {

        addFragment(id, fragment, tag, true);

    }



    protected void addFragment(int id, Fragment fragment, String tag, boolean backStackCheck) {


        //프래그먼트 등록 후 back 누르면 이전 activity 또는 fragment로 이동한다.

        if (backStackCheck) {

            getSupportFragmentManager()

                    .beginTransaction()

                    .add(id, fragment, tag)

                    // 백스텍에 이름이 없거나 널이면 프래그먼트클래스 이름을 등록

                    // 아니면 백스텍 이름을 등록 삼항연산자 앞에가 true : false

                    .addToBackStack(tag)

                    .commit();

        } else {


            getSupportFragmentManager()

                    .beginTransaction()

                    .add(id, fragment, tag)

                    .commit();

        }

    }



    protected void replaceFragment(int id, Fragment fragment) {

        replaceFragment(id, fragment, null, true);

    }


      protected void replaceFragment(int id, Fragment fragment, boolean backStackCheck) {

        replaceFragment(id, fragment, null, backStackCheck);

    }

    protected void replaceFragment(int id, Fragment fragment, String tag) {

        replaceFragment(id, fragment, tag, true);

    }


    //

    protected void replaceFragment(int id, Fragment fragment, String tag, boolean backStackCheck) {


        if (backStackCheck) {

            getSupportFragmentManager()

                    .beginTransaction()

                    .replace(id, fragment, tag)

                    // 백스텍에 이름이 없거나 널이면 프래그먼트클래스 이름을 등록

                    // 아니면 백스텍 이름을 등록 삼항연산자 앞에가 true : false

                    .addToBackStack(tag)

                    .commit();

        } else {

            getSupportFragmentManager()

                    .beginTransaction()

                    .replace(id, fragment, tag)

                    .commit();

        }

    }



    @Override

    public void onBackPressed() {


        Log.w("bear", "fragment Size : " + getSupportFragmentManager().getBackStackEntryCount());

        if (getSupportFragmentManager().getBackStackEntryCount() == 0) {

            Log.w("bear", "000");

            super.onBackPressed();

        } else {

            Log.w("bear", "1111");

            super.onBackPressed();

        }

    }


    /**

     * 액티비티 전환

     */

    protected void changeActivity(Context context, Class<?> activity, boolean activityFinish) {


        Intent intent = new Intent(context, activity);


        startActivity(intent);

        if (activityFinish) {

            finish();

        }

    }



    /**

     * 퍼미션 검사 리스너.

     */

    protected interface PermissionCheckListener {

        /***/

        void permissionCheckFinish();

    }


    /**

     * 리스너 등록.

     */

    protected PermissionCheckListener permissionCheckListener;


    /**

     * 온 크레딧 바로 아래 생성 되어야 한다

     */

    public void setPermissionCheckListener(PermissionCheckListener permissionCheckListener) {

        this.permissionCheckListener = permissionCheckListener;

    }


    private final int PERMISSION_REQUEST = 1000;



    /**

     * 이게 BaseActivity 에 들어갈 필요가 있는가?????

     * 스트링 배열로 퍼미션 체크.

     * 필요할때만 if 문으로 처리.

     * true 일 경우 퍼미션 팝업.

     */

    public boolean permissionCheck(String[] strings) {

        boolean check = false;

        // //안드로이드 마시멜로 이후 퍼미션 체크.

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {

            for (int i = 0; i < strings.length; i++) {

                if (ContextCompat.checkSelfPermission(this, strings[i]) == PackageManager.PERMISSION_DENIED) {

                    ActivityCompat.requestPermissions(this, strings, PERMISSION_REQUEST);

                    check = true;

                    break;

                }

            }

        }

        return check;

    }


    /**

     * 거부를 했을때 처리

     * 다시보지 않기 체크 후 거부를 하면 설정에서 권한을 허용하도록 요청.

     * 허용하지 않을 경우 앱 사용 을 못함..

     * 처리를 잘못하면 무한 반복할 경우가 생김.

     */

    @Override

    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {


        super.onRequestPermissionsResult(requestCode, permissions, grantResults);


        if (requestCode == PERMISSION_REQUEST) {

            // //안드로이드 마시멜로 이후 퍼미션 체크.

            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {

                for (int i = 0; i < grantResults.length; i++) {


                    if (grantResults[i] == 0) {

                        if (grantResults.length == (i + 1)) {


                            // 인터페이스 콜백으로 리턴됨.

                            permissionCheckListener.permissionCheckFinish();

                        }

                    } else {


                        // 거부한 이력이 있으면 true를 반환한다.

                        if (shouldShowRequestPermissionRationale(permissions[i])) {

                            ActivityCompat.requestPermissions(this, permissions, PERMISSION_REQUEST);

                            break;


                        } else {

                            new AlertDialog.Builder(this)

                                    .setTitle("다시보지않기 클릭.")

                                    .setMessage(permissions[i] + " 권한이 거부되었습니다 설정에서 직접 권한을 허용 해주세요.")

                                    .setNeutralButton("설정", new DialogInterface.OnClickListener() {


                                        @Override

                                        public void onClick(DialogInterface dialog, int which) {

                                            Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);

                                            intent.setData(Uri.parse("package:" + getPackageName()));

                                            startActivity(intent);

                                            Toast.makeText(getApplicationContext(), "권한 설정 후 다시 실행 해주세요.", Toast.LENGTH_SHORT).show();

                                            finish();

                                        }

                                    })

                                    .setPositiveButton("확인", new DialogInterface.OnClickListener() {


                                        @Override

                                        public void onClick(DialogInterface dialog, int which) {

                                            Toast.makeText(getApplicationContext(), "권한 설정을 하셔야 앱을 사용할 수 있습니다.", Toast.LENGTH_SHORT).show();

                                            finish();

                                        }

                                    })

                                    .setCancelable(false)

                                    .create().show();


                        }// shouldShowRequestPermissionRationale /else

                    } // 권한 거절

                } // for end

            }//Build.VERSION.SDK_INT  end

        }//requestCode  end

    }



}



///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


public class MainActivity extends BaseActivity {


    @Override

    protected int setContentViewLayout() {

        return R.layout.activity_main;

    }


    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);


        setPermissionCheckListener(new PermissionCheckListener() {

            @Override

            public void permissionCheckFinish() {


                Log.w("bear", "MainActivity 여기서 시작해야 한다.");

                addFragment(R.id.layoutContainer, BlankFragment.newInstance());

                addFragment(R.id.layoutContainer, BlankFragment.newInstance("bear"));

                replaceFragment(R.id.layoutContainer, BlankFragment.newInstance("bear", "bear22  "));


            }

        });



        if (permissionCheck(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE})) {

            Log.e("bear", "퍼미션 체크를 시도.");

            return;

        }


        permissionCheckListener.permissionCheckFinish();

    }



}


public class MainActivity extends BaseActivity {


    @Override

    protected int setContentViewLayout() {

        return R.layout.activity_main;

    }


    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);


        setPermissionCheckListener(new PermissionCheckListener() {

            @Override

            public void permissionCheckFinish() {


                Log.w("bear", "MainActivity 여기서 시작해야 한다.");

                addFragment(R.id.layoutContainer, BlankFragment.newInstance());

                addFragment(R.id.layoutContainer, BlankFragment.newInstance("bear"));

                replaceFragment(R.id.layoutContainer, BlankFragment.newInstance("bear", "bear22  "));


            }

        });



        if (permissionCheck(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE})) {

            Log.e("bear", "퍼미션 체크를 시도.");

            return;

        }


        permissionCheckListener.permissionCheckFinish();

    }



}


public class MainActivity extends BaseActivity {


    @Override

    protected int setContentViewLayout() {

        return R.layout.activity_main;

    }


    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);


        setPermissionCheckListener(new PermissionCheckListener() {

            @Override

            public void permissionCheckFinish() {


                Log.w("bear", "MainActivity 여기서 시작해야 한다.");

                addFragment(R.id.layoutContainer, BlankFragment.newInstance());

                addFragment(R.id.layoutContainer, BlankFragment.newInstance("bear"));

                replaceFragment(R.id.layoutContainer, BlankFragment.newInstance("bear", "bear22  "));


            }

        });



        if (permissionCheck(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE})) {

            Log.e("bear", "퍼미션 체크를 시도.");

            return;

        }


        permissionCheckListener.permissionCheckFinish();

    }



}


///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

abstract class BaseFragment extends Fragment {


    abstract protected int setContentViewLayout();


    @Override

    public View onCreateView(LayoutInflater inflater, ViewGroup container,

                             Bundle savedInstanceState) {

        // Inflate the layout for this fragment

        Log.e("bear", "BaseFragment start");

        return inflater.inflate(setContentViewLayout(), container, false);

    }

}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


/**

 * 기본 프래그먼트 작업.

 */

public class BlankFragment extends BaseFragment {


    @Override

    protected int setContentViewLayout() {

        // onCreateView 오버라이딩 할 필요없다.

        return R.layout.fragment_blank;

    }



    private static final String ARG_PARAM1 = "param1";

    private static final String ARG_PARAM2 = "param2";


    private String mParam1;

    private String mParam2;



    public BlankFragment() {

        // Required empty public constructor

    }


    public static BlankFragment newInstance() {

        return new BlankFragment();

    }


    public static BlankFragment newInstance(String param1) {

        BlankFragment fragment = new BlankFragment();

        Bundle args = new Bundle();

        args.putString(ARG_PARAM1, param1);

        fragment.setArguments(args);

        return fragment;

    }



    public static BlankFragment newInstance(String param1, String param2) {

        BlankFragment fragment = new BlankFragment();

        Bundle args = new Bundle();

        args.putString(ARG_PARAM1, param1);

        args.putString(ARG_PARAM2, param2);

        fragment.setArguments(args);

        return fragment;

    }


    @Override

    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);


        if (getArguments() != null) {

            if (getArguments().getString(ARG_PARAM1) != null) {

                mParam1 = getArguments().getString(ARG_PARAM1);

            }


            if (getArguments().getString(ARG_PARAM2) != null) {

                mParam2 = getArguments().getString(ARG_PARAM2);

            }

        }

    }


    @Override

    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {

        super.onViewCreated(view, savedInstanceState);


        if (mParam1 != null) {


            Log.d("bear", "blankFragment mParam1 : " + mParam1);

        }

        if (mParam2 != null) {

            Log.d("bear", "blankFragment mParam2 : " + mParam2);

        }


        TextView fragment_Textview = view.findViewById(R.id.fragment_Textview);


        fragment_Textview.setText("   m    : " + mParam1 + "  ,   m " + mParam2);



    }



}








추상 클래스를 이용한 액티비티 구현 2-1.

2-2에서 퍼미션 권한 이용.



안드로이드 스튜디오 프로잭트 생성.


생성된 기본 액티비티.

MainActivity.java

//////////////////////////////////////////////////////////////////////////////////////////

public class MainActivity extends AppCompatActivity {


    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);

    }

}

//////////////////////////////////////////////////////////////////////////////////////////



추상 클래스 BaseActivity 생성.

BaseActivity.java

//////////////////////////////////////////////////////////////////////////////////////////

abstract class BaseActivity extends AppCompatActivity {


    /**상속받은 곳에서 xml 레이아웃을 받아옴.*/

    abstract int setLayout();


    @Override

    protected void onCreate(@Nullable Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(setLayout());

    }


}

//////////////////////////////////////////////////////////////////////////////////////////


생성된 BaseActivity를 MainActivity에서 상속받음.

MainActivity.java

//////////////////////////////////////////////////////////////////////////////////////////

public class MainActivity extends BaseActivity {



    @Override

    int setLayout() {

        // BaseActivit에서 만들어 놓은 추상 메서그 구현.

        // setContentView(R.layout.activity_main);

        // 추상메서드로 구현.

        return R.layout.activity_main;

    }


    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        

    }

}


//////////////////////////////////////////////////////////////////////////////////////////



이렇게 작업 한 이유는 액티비티를 상속 받은 처리 중 퍼미션 사용시 필요한 클래스 들을 정의 하여 사용하기 위함.

구현이 필요 없을 시엔 기존에 사용하던 대로 사용 가능.



'Android > source code' 카테고리의 다른 글

안드로이드 추상 클래스 이용한 퍼미션 권한 설정. 2-2  (0) 2018.10.15
Android RecyclerView 예제  (0) 2018.10.15
동적 레이아웃 등록(xml)  (0) 2018.10.11
액티비티  (0) 2018.09.18
MVP 패턴 코틀린으로 작업  (0) 2018.08.14

MVP 패턴.





MODEL : 데이터 처리.


VIEW : 뷰 


PRESENT : MODEL과 VIEW 사이의 매개체



MVP 패턴의 동작


VIEW 에서 사용자 이벤트 수신

VIEW 에서 PRESENTER 이벤트 호출

PRESENTER 에서 MODEL 데이터 요청

MODEL 에서 PRESENTER 로 데이터 전달

PRESENTER 에서 전달받은 데이털 처리 후 VIEW 업데이트 요청

VIEW 에서 화면 업데이트



구현 방법


interface Contact


inner interface View

inner interface Present 


View 에서 처리할 이벤트 선언

Present 에서 처리할 이벤트 선언



View를 상속받는 Activiry 구현

Present를 상속받는 Presenter 구현


Presenter 에서 Model로 데이터 요청.(통신을 통한 서버 데이터 요청)


Model 에서 Presenter 가 요청한 데이터를 전달 후 Presenter에서 데이터 가공 후 View에 업데이트 요청


View 로 가공된 데이터를 가지고 화면 업데이트. 




MainActivityContract


MainActivity  MainActivityContract.View 상속


MainActivityPresenter MainActivityContract.Present 상속


MainActivityDataAction Present에서 데이터 요청




코틀린으로 코드 구현.




/**

 * 액티비티 상속 클래스

 */

abstract class BaseActivity : AppCompatActivity() {


    /**레이아웃 뷰 추상화 등록*/

    protected abstract val layoutId: Int


    override fun onCreate(savedInstanceState: Bundle?) {

        super.onCreate(savedInstanceState)

        setContentView(layoutId)

    }

}




/**

 * mvp 계약자 정의

 */

interface MainActivityContract {

    /**

     * 단순 화면 처리

     * 액티비이에서 뷰 구현

     */

    interface View {


        /** 뷰에 프레젠터 등록.*/

        val presenter: Present


        fun buttonClickChangeUI(count: Int)


    }


    /**

     * 프레젠터 뷰와 모델의 데이터 처리

     * 프레젠터 클래스를 생성하여 인터페이스 구현.

     */

    interface Present {


        /**

         * 프레젠터에 뷰 등록

         *

         */

        var view: View?


        /** 전달받을 뷰를 등록함.*/

        fun attachView(view: View)


        /** 뷰 해제*/

        fun detachView()



        fun buttonClickCountUp(count: Int)

    }

}


/**

 * MainActivity

 * 

 */

class MainActivity : BaseActivity(), MainActivityContract.View {


    /**BaseActivity에서 상속받은 변수. */

    override val layoutId = R.layout.activity_main

    /**뷰에 지정한 프레젠터 등록.*/

    override val presenter: MainActivityContract.Present = MainActivityPresenter()


    override fun onCreate(savedInstanceState: Bundle?) {


        super.onCreate(savedInstanceState)

        presenter.attachView(this)

        buttonEvent()

    }



    fun buttonEvent() {


        button_Click.setOnClickListener(View.OnClickListener {

            Log.w("bear", "buttonclick")

            presenter.buttonClickCountUp(count)

        }

        )

    }


    var count = 0

    override fun buttonClickChangeUI(count: Int) {

        this.count = count

        textview.text = "${this.count}"

    }

}




/**

 * 데이터를 처리하는 프레젠터

 * 처리된 결과를 등록한 뷰에 전달.

 */

class MainActivityPresenter : MainActivityContract.Present {


    /**뷰 초기화*/

    override var view: MainActivityContract.View? = null


    /**뷰 지정.onCreate 에 등록*/

    override fun attachView(view: MainActivityContract.View) {

        this.view = view

    }


    /**뷰 해제*/

    override fun detachView() {

        this.view = null

    }


    override fun buttonClickCountUp(count: Int) {

        view?.buttonClickChangeUI(count + 1)

    }

}






이런식으로 사용이 가능하다.





+ Recent posts