Context

jiyoon·2023년 4월 11일
0

모바일 안드로이드

목록 보기
9/12

Context 객체란 뭘까?

안드로이드에서 Context는 애플리케이션의 실행 환경에 대한 정보를 가지고 있는 추상 클래스이다. Context 클래스를 이용하여 애플리케이션의 컴포넌트(예: 액티비티, 서비스, 브로드캐스트 수신자 등)가 애플리케이션과 상호작용할 수 있다.

주요 기능

애플리케이션 정보 접근

Context 클래스는 애플리케이션의 정보(예: 패키지명, 앱 이름, 버전 정보 등)에 접근할 수 있는 메소드를 제공한다.


  • 패키지명 가져오기
String packageName = getApplicationContext().getPackageName();

  • 앱 이름 가져오기
String appName = getPackageManager().getApplicationLabel(getApplicationInfo()).toString();

  • 앱 버전 정보 가져오기
PackageManager packageManager = getPackageManager();
PackageInfo packageInfo = packageManager.getPackageInfo(getPackageName(), 0);
String versionName = packageInfo.versionName;
int versionCode = packageInfo.versionCode;

애플리케이션 리소스 접근

Context 클래스는 애플리케이션의 리소스(예: 레이아웃, 문자열, 이미지 등)에 접근할 수 있는 메소드를 제공한다.


  • 문자열 가져오기
String helloWorld = getString(R.string.hello_world);

  • 레이아웃 가져오기
LayoutInflater layoutInflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View view = layoutInflater.inflate(R.layout.activity_main, null);

  • 이미지 가져오기
Resources resources = getResources();
Drawable drawable = resources.getDrawable(R.drawable.ic_launcher_foreground);

컴포넌트 생명주기 관리

Context 클래스는 컴포넌트의 생명주기(예: 생성, 소멸, 일시정지 등)를 관리하는 데 사용된다.


  • 액티비티 생성
Intent intent = new Intent(this, SecondActivity.class);
startActivity(intent);

  • 액티비티 종료
finish();

인텐트 발생 및 수신

Context 클래스는 인텐트(예: 액티비티 전환, 브로드캐스트 등)를 발생하고, 인텐트를 수신하는 데 사용된다.


  • 인텐트 발생
Intent intent = new Intent(this, SecondActivity.class);
startActivity(intent);

  • 인텐트 수신
Intent intent = getIntent();
String message = intent.getStringExtra("key");

AppCompatActivity를 상속받아 구현하면 자신(activity)이 Context가 됨

AppCompatActivity는 Activity를 상속하며, Activity는 Context를 상속한다. 따라서 AppCompatActivity를 상속받아 구현한 클래스는 Context를 상속받게 되며, 이 클래스의 인스턴스가 Context가 되는 것이다.

이렇게 액티비티 자체가 Context를 상속받게 되면, 액티비티 내에서 다양한 시스템 서비스에 접근하거나 리소스를 로드할 수 있다. 예를 들어, startActivity(), getSystemService(), getResources()와 같은 메서드를 액티비티 내에서 직접 호출할 수 있게된다.



액티비티의 범위

액티비티는 일반적으로 한 화면의 모든 구성요소를 담당한다. 즉, 액티비티는 해당 화면에 표시되는 모든 뷰와 그에 따른 이벤트 처리, 상태 변경 등을 담당한다. 또한, 액티비티는 다른 액티비티와의 화면 전환을 통해 다른 화면으로 이동할 수 있다.

액티비티는 기본적으로 한 화면을 담당하지만, 경우에 따라서는 여러 화면을 담당하기도 한다. 예를 들어, 탭이나 뷰페이저를 이용하여 여러 개의 화면을 구성하고, 각각의 화면을 액티비티로 구현하는 경우가 있다. 이 경우, 각각의 액티비티는 하나의 화면을 담당하며, 서로 다른 액티비티 간에 화면 전환을 이용하여 사용자와 상호작용한다.

따라서, 액티비티의 범위는 일반적으로 한 화면의 모든 구성요소를 담당하지만, 경우에 따라서는 여러 개의 화면을 담당하기도 한다.



뷰페이저

뷰페이저(ViewPager)는 안드로이드에서 많이 사용되는 UI 컴포넌트 중 하나로, 여러 개의 뷰를 페이지 단위로 스와이프하여 보여줄 수 있도록 도와주는 컨테이너입니다. 뷰페이저를 구성하고 구현하는 방법은 다음과 같습니다.


뷰페이저 라이브러리 추가

먼저, 앱 수준의 build.gradle 파일에 다음 코드를 추가하여 뷰페이저 라이브러리를 추가합니다.

dependencies {
    implementation 'androidx.viewpager:viewpager:1.0.0'
}

뷰페이저 레이아웃 추가

다음으로, 뷰페이저를 추가할 레이아웃 파일을 작성합니다. 뷰페이저는 ViewPager 위젯으로 구현되며, 이 위젯을 레이아웃 파일에 추가합니다.

<androidx.viewpager.widget.ViewPager
    android:id="@+id/viewPager"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

어댑터 클래스 작성

뷰페이저는 각 페이지에 보여줄 뷰를 어댑터(Adapter) 클래스를 통해 관리합니다. 따라서, 어댑터 클래스를 작성합니다.

public class ViewPagerAdapter extends PagerAdapter {

    private Context mContext;
    private List<View> mViewList;	// 뷰페이저에 추가할 뷰들을 저장할 리스트

    public ViewPagerAdapter(Context context, List<View> viewList) {
        mContext = context; // 컨텍스트 받아서 저장
        mViewList = viewList; // 뷰 리스트 받아서 저장
    }

    // 뷰페이저에 몇 개의 페이지가 있는지 알려줌
    @Override
    public int getCount() {
        return mViewList.size(); // 리스트의 크기를 반환
    }

    // 현재 보여지는 뷰가 인자로 전달된 오브젝트와 같은지 확인
    @Override
    public boolean isViewFromObject(View view, Object object) {
        return view == object; // 뷰랑 오브젝트가 같으면 true 반환
    }

    // 뷰페이저에 보여줄 뷰를 생성하고, 뷰 그룹에 추가
    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        View view = mViewList.get(position); // 리스트에서 뷰 꺼내옴
        container.addView(view); // 컨테이너에 뷰 추가
        return view; // 추가한 뷰 반환
    }

    // 뷰페이저에서 뷰를 제거할 때 호출
    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        View view = mViewList.get(position); // 리스트에서 뷰 꺼내옴
        container.removeView(view); // 컨테이너에서 뷰 제거
    }
}

뷰페이저에 어댑터 설정

뷰페이저를 액티비티에 추가하고, 어댑터를 설정합니다.

// 뷰페이저 객체 찾기
ViewPager viewPager = findViewById(R.id.viewPager);

// 뷰 목록 생성
List<View> viewList = new ArrayList<>();

// 레이아웃 인플레이터를 사용하여 각 페이지의 뷰를 생성하고 목록에 추가
viewList.add(getLayoutInflater().inflate(R.layout.view1, null));
viewList.add(getLayoutInflater().inflate(R.layout.view2, null));
viewList.add(getLayoutInflater().inflate(R.layout.view3, null));

// 어댑터 객체 생성하고, 현재 액티비티와 뷰 목록을 전달
ViewPagerAdapter adapter = new ViewPagerAdapter(this, viewList);

// 뷰페이저에 어댑터 설정
viewPager.setAdapter(adapter);

뷰페이저를 구성하는 방법은 위와 같다. 위 코드는 세 개의 뷰를 뷰페이저에 추가하여, 각각의 뷰를 페이지 단위로 스와이프하여 볼 수 있게 만드는 예제이다.



같은 기능을 수행하는 뷰를 여러 액티비티에서 사용하려면

사용자 정의 뷰 (Custom View) 또는 프래그먼트 (Fragment)를 사용하는 것이 좋다.

사용자 정의 뷰 (Custom View) 사용

사용자 정의 뷰는 기존의 뷰를 확장하여 원하는 기능과 디자인을 적용한 커스텀 뷰를 생성하는 방법이다. 이렇게 만든 사용자 정의 뷰는 여러 액티비티에서 재사용할 수 있다.

예를 들어, MyCustomView라는 사용자 정의 뷰를 만들고자 한다면 아래와 같이 구현할 수 있다.

public class MyCustomView extends RelativeLayout {
    public MyCustomView(Context context) {
        super(context);
        init(context);
    }

    public MyCustomView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    private void init(Context context) {
        LayoutInflater.from(context).inflate(R.layout.my_custom_view, this);
        // 뷰 초기화 및 이벤트 처리 등의 로직 작성
    }
}

그런 다음, 이 사용자 정의 뷰를 여러 액티비티에서 사용하려면 XML 레이아웃 파일에 추가하기만 하면 된다.

<com.example.myapplication.MyCustomView
    android:layout_width="match_parent"
    android:layout_height="0dp"
    android:layout_weight="1"/>

프래그먼트 (Fragment) 사용

프래그먼트는 독립된 뷰와 로직을 가진 모듈로서, 하나의 액티비티에 여러 개의 프래그먼트를 추가하거나 교체할 수 있다. 프래그먼트를 사용하면 여러 액티비티에서 동일한 기능을 수행하는 뷰를 재사용할 수 있다.

public class MyFragment extends Fragment {
    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        return inflater.inflate(R.layout.my_fragment, container, false);
    }
}

여러 액티비티에서 동일한 프래그먼트를 사용하려면 각 액티비티의 레이아웃에 프래그먼트를 추가하거나, 액티비티의 코드에서 프래그먼트를 동적으로 추가하면 된다.

사용자 정의 뷰와 프래크먼트의 차이

사용자 정의 뷰는 주로 간단한 기능을 수행하는 커스텀 뷰를 만들 때 사용한다. 프래그먼트는 더 복잡한 로직이 필요하거나, 뷰 간 상호작용이 필요한 경우에 사용한다. 각각의 특징을 고려하여 프로젝트의 요구사항에 맞는 방식을 선택하면 된다.

사용자 정의 뷰 (Custom View)

  • 기존 뷰를 확장하여 새로운 뷰를 정의
  • 주로 단순한 UI 컴포넌트를 재사용할 때 사용
  • 뷰와 관련된 로직만 포함하며, 액티비티와 독립적
  • 액티비티와의 상호작용이 제한적

프래그먼트 (Fragment)

  • 독립적인 뷰와 로직을 가진 모듈
  • 복잡한 UI 및 로직을 재사용할 때 사용
  • 뷰와 관련된 로직, 액티비티와의 상호작용 등을 포함
  • 액티비티와의 상호작용이 가능하며, 여러 프래그먼트 간의 상호작용도 가능

프레그먼트

안드로이드에서 프래그먼트를 사용하는 방법은 다양하며, 주로 독립된 UI 컴포넌트를 구현하거나, 여러 액티비티에서 재사용 가능한 모듈을 구현하는데 사용됩니다. 이제 프래그먼트를 생성하고, 액티비티에 추가하는 기본적인 방법과 주석을 달아 설명해 드리겠습니다.

프래그먼트 생성하기

우선 프래그먼트를 생성합니다. 프래그먼트는 androidx.fragment.app.Fragment를 상속받아 구현합니다.

// MyFragment.java
import androidx.fragment.app.Fragment;

public class MyFragment extends Fragment {

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        // 프래그먼트의 레이아웃을 인플레이트하여 반환
        return inflater.inflate(R.layout.fragment_my, container, false);
    }
}

액티비티에 프래그먼트 추가하기

액티비티에 프래그먼트를 추가하기 위해 액티비티의 레이아웃 파일에 FrameLayout 컨테이너를 추가합니다. 이 컨테이너는 프래그먼트를 호스트할 영역입니다.

<!-- activity_main.xml -->
<FrameLayout
    android:id="@+id/fragment_container"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

그 다음 액티비티에서 프래그먼트를 추가합니다.

// MainActivity.java
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.FragmentTransaction;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // 프래그먼트 인스턴스 생성
        MyFragment myFragment = new MyFragment();

        // 프래그먼트를 추가하기 위한 트랜잭션 시작
        FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
        // 프래그먼트 추가 (컨테이너 ID, 프래그먼트 인스턴스)
        transaction.add(R.id.fragment_container, myFragment);
        // 트랜잭션 커밋 (실제로 프래그먼트가 추가됨)
        transaction.commit();
    }
}

프래그먼트 간의 통신

프래그먼트 간의 통신을 위해서는 액티비티를 중계자로 사용합니다. 예를 들어, 프래그먼트 A에서 버튼을 클릭하면 프래그먼트 B로 데이터를 전달하는 경우입니다.

먼저, 액티비티에 인터페이스를 정의합니다.

// MainActivity.java
public class MainActivity extends AppCompatActivity {

    // 프래그먼트 A와 통신하기 위한 인터페이스 정의
    public interface FragmentAListener {
        void onButtonClickFromFragmentA(String message);
    }

    // ...

}

그 다음 프래그먼트 A에서 액티비티에 정의된 인터페이스를 구현하고, 버튼 클릭 이벤트를 처리합니다.

// FragmentA.java
public class FragmentA extends Fragment {

    private MainActivity.FragmentAListener mListener;

    @Override
    public void onAttach(@NonNull Context context) {
        super.onAttach(context);
        if (context instanceof MainActivity.FragmentAListener) {
            mListener = (MainActivity.FragmentAListener) context;
        } else {
            throw new RuntimeException(context.toString() + " must implement FragmentAListener");
        }
    }

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_a, container, false);
        Button button = view.findViewById(R.id.button_send);

        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (mListener != null) {
                    // 버튼 클릭 이벤트를 액티비티에 알림
                    mListener.onButtonClickFromFragmentA("Hello from Fragment A");
                }
            }
        });

        return view;
    }

    @Override
    public void onDetach() {
        super.onDetach();
        mListener = null;
    }
}

마지막으로 액티비티에서 인터페이스를 구현하고, 프래그먼트 B로 데이터를 전달합니다.

// MainActivity.java
public class MainActivity extends AppCompatActivity implements MainActivity.FragmentAListener {

    // ...

    @Override
    public void onButtonClickFromFragmentA(String message) {
        FragmentB fragmentB = (FragmentB) getSupportFragmentManager().findFragmentById(R.id.fragment_container_b);

        if (fragmentB != null) {
            // 프래그먼트 B로 데이터 전달
            fragmentB.updateTextView(message);
        }
    }
}

이와 같이 프래그먼트를 활용하면 여러 액티비티에서 재사용 가능한 모듈을 구현할 수 있습니다. 다양한 UI 컴포넌트를 프래그먼트로 만들어 액티비티에서 쉽게 조합할 수 있어, 유연하고 재사용 가능한 코드를 작성할 수 있습니다.

profile
주니어 개발자

0개의 댓글