마스터Q&A 안드로이드는 안드로이드 개발자들의 질문과 답변을 위한 지식 커뮤니티 사이트입니다. 안드로이드펍에서 운영하고 있습니다. [사용법, 운영진]

메뉴바 메뉴에서 프래그먼트로 이동하는 법

0 추천

메뉴바 메뉴에서 액티비티로 이동은 되는데, 프래그먼트의 경우에는 문법이 조금 다른 것 같더라고요.

액티비티 문법과 동일하게 작성했는데 오류가 발생했는지 제대로 실행이 되지 않네요.

어느 부분에서 오류가 난 것일까요.. 구글링 하다가 관련 게시글이 없어서 이렇게 질문 남깁니다.

@Override
    public boolean onOptionsItemSelected(@NonNull MenuItem item) {
        super.onOptionsItemSelected(item);
        if(item.getItemId() == R.id.menu1) {
            Intent intent = new Intent(getApplicationContext(), IntroActivity.class);
            startActivity(intent);
        }
        else if(item.getItemId() == R.id.menu2) {
            Intent intent = new Intent(getApplicationContext(), AddVocaFragment.class);
            startActivity(intent);
        }
        return true;
    }

 

희망을기억해 (200 포인트) 님이 2021년 12월 11일 질문

1개의 답변

0 추천

Fragment는 FragmentManager를 사용하셔야 합니다. 보통은 버전간의 호환성을 위해 SupportFragmentManager를 사용하게 되는데, Activity가 FragmentActivity의 하위클래스여야 getSupportFragmentManger()메소드를 이용해서 Activity 내에서 FragmentManager에 접근해서 사용할 수 있습니다. 프레그먼트 네비게이션은 간단하지 않기 때문에, 아래 개발자 문서를 꼭 읽어보세요. 잘못 사용하시면 이상한 증상에 시달리실 수 있습니다.

https://developer.android.com/guide/fragments/fragmentmanager

프레그먼트는 액티비티 안에서 여러개를 스위치하는 형태로 사용하게 되는데, 이 스위치 과정은 Transaction이라고 부릅니다.  개발자 문서의 예제입니다.
 

FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction()
    .replace(R.id.fragment_container, ExampleFragment.class, null)
    .setReorderingAllowed(true)
    .addToBackStack("name") // name can be null
    .commit();

 

beginTransaction()과 commit() 사이에는 여러개의 동작을 집어넣을 수가 있습니다. commit()을 호출하는 순간 데이터베이스의 트랜잭션처럼 모든 동작들이 한번에 수행되게 됩니다. setReoderingAllowed는 상태복구 등을 위해 최신버전에서 추가된 메소드이고 addToBackStack의 백스택이라는 곳에 프레그먼트 트랜잭션을 보관했다가 뒤로 이동할 때 사용합니다. 각각의 메소드에 대해서는 문서를 잘 읽어보시는게 좋습니다.

그리고 액티비티가 onCreate될 때 보통 시작 프레그먼트로 이동을 하게 되는데, 이 때 주의하셔야 할 점은 액비티가 디바이스 로테이션 등으로 인해 다시 생성되지 않은 경우만, 시작 프레그먼트로 이동하는 코드를 사용해야 합니다. 그렇지 않으면 같은 프레그먼트가 백스택에 겹치게 되는 증상이 생기게 됩니다. 따라서 아래처럼 Activity의 onCreate에서

public void onCreate(@Nullable Bundle savedInstance) {
    super.onCreate(savedInstance);
    setContentView(...);

    if (saveInstance == null) {
         showStartingFragment();
    }
}

 

안드로이드 네비게이션을 라이프싸이클과 밀접한 관련이 있고 복잡하기 때문에, 경험이 많은 개발자들도 자주 개발자 문서를 참고해야하는 아주 골치아픈 토픽입니다. 안드로이드 개발의 어려움 중의 하나죠.

참고로 구글의 권장사항은 Navigation Component의 사용입니다. 위에서 말씀드린 사항들을 많이 몰라도 사용할 수 있도록 간소화시켜놓았습니다.

 

그리고 네비게이션 관련 코드는 여러군데서 재사용하거나 로그인여부 등을 체크해서 조건에 따라 분기를 하게 되므로, 담당 클래스를 하나 두시면 한군데서 관리하기가 수월해집니다. 아주 간단하게는 클래스 하나를 만들어서 거기에 네비게이션 코드를 집어 넣으면 됩니다.

public class ScreensNavigator {

     public FragmentActivity activity;
     public ScreensNavigator(FragmentActivity activity) {
         this.activity = activity;
     }
    
     public void navigateToIntro((){
           Intent intent = new Intent(activity, IntroActivity.class);
           startActivity(intent);
     }

     public void navigateToIntro(){
           FragmentManager fragmentManager = activity.getSupportFragmentManager();
           fragmentManager.beginTransaction()
                       .replace(R.id.fragment_container, AddVocaFragment(), null)
                       .setReorderingAllowed(true)
                       .addToBackStack(null)
                       .commit();
     }
}


public class MyActivity etends AppCompatActivity {
     
     private ScreensNavigator navigatror;

    public void onCreate(Bundle savedinstance) {
        navigator = new ScreensNavigator(this);
        super.onCreate(savedinstance);
        setContentView(...);

   
       if (savedInstance == null) {
           navigator.navigateToIntro();
       }
    }
}

 

BaseActivity를 만들고 모든 액티비티가 BaseActivity를 상속받게 하면 모든 액티비티에서 위의 클래스를 사용할 수 있을 겁니다.

public abstract BaseActvitity extends AppCompatActivity {
     
    protected ScreensNavigator navigatror;

    public void onCreate(Bundle savedinstance) {
        inject();
        super.onCreate(savedinstance);
    }

    protected void inject() {
        navigator = new ScreensNavigator(this);
    }
}


public class MyActivity extends BaseActvitity {
 
    public void onCreate(Bundle savedinstance) {
        super.onCreate(savedinstance);
        setContentView(...);

       if (savedInstance == null) {
           navigator.navigateToIntro();
       }
    }

}

 

spark (226,420 포인트) 님이 2021년 12월 11일 답변
spark님이 2021년 12월 11일 수정
...