TitlesFragment에서 표시된 ListView의 항목이 선택되었을 때, 해당 항목의 상세정보를 DetailsFragment에 어떻게 전달할 것인가?
따라서, TitlesFragment의 목록에서 선택된 내용을 DetailsFragment로 전달할 때, 프래그먼트가 서로 종속적이지 않고 독립적으로 동작하게 하기 위해서는 아래 그림과 같이, 선택된 항목번호를 MainActivity로 보내고, MainActivity에서 다시 DetailsFragment로 보내는 방법을 취해야 합니다. 이에 대한 구체적인 방법은 이어지는 절에서 자세히 설명합니다.
예제 프로젝트 소스 https://github.com/kwanulee/AndroidProgramming/tree/master/examples/TabletPhoneFragment
제목 목록을 ListView로 보여주는 TitlesFragment를 구현한다.
앞서 정의한 TitlesFragment를 MainActivity에 정적으로 추가하고, TitlesFragement 내의 ListView의 선택된 항목 번호를 MainActivity로 전달하는 방법을 구현한다.
ListView의 항목이 선택되었을 때 선택된 항목 위치를 MainActivity의 onTitleSelected()메소드를 호출하면서 파라미터로 전달
MainActivity가 이 인터페이스를 구현하도록한 후, ListView의 항목이 선택되었을 때 선택된 항목 번호를 MainActivity가 구현한 인터페이스의 onTitleSelected()메소드를 호출하면서 파라미터로 전달
장점 | 단점 | |
---|---|---|
방법1 | 간단한 구조 | 특정 Activity에 종속 |
방법2 | 정의된 인터페이스를 구현하는 모든 Activity와 통신 가능 | 다소 복잡한 구조 |
디바이스의 화면이 태블릿과 같이 큰 경우에 작은 크기의 화면과는 다른 화면 구성을 하고자 한다면, res/layout-large 폴더에 MainActivity의 레이아웃 파일과 동일한 이름의 레이아웃 파일을 정의
ListView에서 선택한 항목 번호의 상세정보를 보여주는 DetailsFragment를 구현한다.
TitlesFragment에서 리스트뷰 항목 선택 번호를 MainActivity로 전달하였으므로, MainActivity에서는 전달받은 항목 선택 번호를 다시 DetailsFragment로 넘긴다.
인자를 프래그먼트로 전달하는 일반적인 패턴은 정적 메소드인 newInstance()를 사용하는 것입니다.
newInstance(parameter) 메소드 정의
public class DetailsFragment extends Fragment {
private static final String ARG_PARAM1 = "index";
public DetailsFragment() {
// Required empty public constructor
}
/**
* Use this factory method to create a new instance of
* this fragment using the provided parameters.
*
* @param index selected position in the ListView.
* @return A new instance of fragment DetailsFragment.
*/
public static DetailsFragment newInstance(int index) {
DetailsFragment fragment = new DetailsFragment();
Bundle args = new Bundle(); // 인자 값을 저장할 번들 객체 생성
args.putInt(ARG_PARAM1, index); // 인자 값을 (키,값) 페어로 번들 객체에 설정
fragment.setArguments(args); // 인자값을 저장한 번들 객체를 프래그먼트로 전달
return fragment;
}
}
newInstance(parameter) 메소드를 통해 프래그먼트로 인자 전달
public class MainActivity extends AppCompatActivity implements TitlesFragment.OnTitleSelectedListener{
//...
public void onTitleSelected(int i) {
if (getResources().getConfiguration().orientation
== Configuration.ORIENTATION_LANDSCAPE) {
// DetailsFragment로 선택된 항목번호 i 전달
DetailsFragment detailsFragment = DetailsFragment.newInstance(i);
getSupportFragmentManager().beginTransaction().replace(R.id.details, detailsFragment).commit();
}
}
}
스마트폰의 경우에는 첫화면(MainActivity)에서 TitlesFragment만 나오고, ListView에 나열된 항목이 선택되면 해당 항목에 대한 상세정보를 표시하는 DetailsFragment를 다른 화면(DetailsActivity)으로 표시한다.
MainActivity는 DetailsActivity에게 리스트뷰의 항목 선택 번호를 인텐트의 Extra를 통해 전달한다.
onTitleSelected() 메소드 수정
public void onTitleSelected(int i) {
if (getResources().getConfiguration().isLayoutSizeAtLeast(Configuration.SCREENLAYOUT_SIZE_LARGE)) {
DetailsFragment detailsFragment = DetailsFragment.newInstance(i);
getSupportFragmentManager().beginTransaction().replace(R.id.details, detailsFragment).commit();
} else { // 화면 크기가 작은 경우
Intent intent = new Intent(this, DetailsActivity.class);
intent.putExtra("index", i);
startActivity(intent);
}
}
DetailsActivity는 MainActivity로부터 전달받은 리스트뷰의 항목 선택 번호를 새로이 생성된 DetailsFragment에 전달하고 새로이 생성된 DetailsFragment 객체를 기존 것과 교체
activity_details.xml
DetailsFragment를 포함할 컨테이너로 FrameLayout을 정의 (id는 details로 설정됨)
<?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">
<FrameLayout
android:id="@+id/details"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
DetailsActivity.java
public class DetailsActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_details);
// 액티비티로 전달된 인텐트의 Extra에서 이름이 "index"인 int형 값을 뽑아와서
// 새로이 생성된 DetailsFragment 객체에 전달
DetailsFragment details = DetailsFragment.newInstance(
getIntent().getIntExtra("index",-1));
// 새로이 생성된 DetailsFragment 객체를 기존 것과 교체
getSupportFragmentManager().beginTransaction().replace(R.id.details, details).commit();
}
}
프래그먼트의 재사용을 위해서는 프래그먼트 간에 직접 통신은 배제해야 합니다.
프래그먼트 간의 통신은 그 들의 부모 액티비티를 통해서 이루어져야 합니다.
프래그먼트와 부모 액티비티 간의 통신 방법
프래그먼트로 인자 전달하는 방법