티스토리 뷰

반응형

Stack Overflow에 자주 검색, 등록되는 문제들과 제가 개발 중 찾아 본 문제들 중에서 나중에도 찾아 볼 것 같은 문제들을 정리하고 있습니다.

Stack Overflow에서 가장 먼저 확인하게 되는 가장 높은 점수를 받은 Solution과 현 시점에 도움이 될 수 있는 가장 최근에 업데이트(최소 점수 확보)된 Solution을 각각 정리하였습니다.

 

아래 word cloud를 통해 이번 포스팅의 주요 키워드를 미리 확인하세요.

Fragment MyFragment not attached to Activity

플래그먼트 MyFragment가 액티비티에 연결되지 않음

 문제 내용 

I've created a small test app which represents my problem. I'm using ActionBarSherlock to implement tabs with (Sherlock)Fragments.

제 문제를 나타내는 작은 테스트 앱을 만들었습니다. ActionBarSherlock을 사용하여 (Sherlock)Fragments로 탭을 구현하고 있습니다.

 

My code: TestActivity.java

내 코드: TestActivity.java
public class TestActivity extends SherlockFragmentActivity {
    private ActionBar actionBar;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setupTabs(savedInstanceState);
    }

    private void setupTabs(Bundle savedInstanceState) {
        actionBar = getSupportActionBar();
        actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);

        addTab1();
        addTab2();
    }

    private void addTab1() {
        Tab tab1 = actionBar.newTab();
        tab1.setTag("1");
        String tabText = "1";
        tab1.setText(tabText);
        tab1.setTabListener(new TabListener<MyFragment>(TestActivity.this, "1", MyFragment.class));

        actionBar.addTab(tab1);
    }

    private void addTab2() {
        Tab tab1 = actionBar.newTab();
        tab1.setTag("2");
        String tabText = "2";
        tab1.setText(tabText);
        tab1.setTabListener(new TabListener<MyFragment>(TestActivity.this, "2", MyFragment.class));

        actionBar.addTab(tab1);
    }
}

TabListener.java

public class TabListener<T extends SherlockFragment> implements com.actionbarsherlock.app.ActionBar.TabListener {
    private final SherlockFragmentActivity mActivity;
    private final String mTag;
    private final Class<T> mClass;

    public TabListener(SherlockFragmentActivity activity, String tag, Class<T> clz) {
        mActivity = activity;
        mTag = tag;
        mClass = clz;
    }

    /* The following are each of the ActionBar.TabListener callbacks */

    public void onTabSelected(Tab tab, FragmentTransaction ft) {
        SherlockFragment preInitializedFragment = (SherlockFragment) mActivity.getSupportFragmentManager().findFragmentByTag(mTag);

        // Check if the fragment is already initialized
        if (preInitializedFragment == null) {
            // If not, instantiate and add it to the activity
            SherlockFragment mFragment = (SherlockFragment) SherlockFragment.instantiate(mActivity, mClass.getName());
            ft.add(android.R.id.content, mFragment, mTag);
        } else {
            ft.attach(preInitializedFragment);
        }
    }

    public void onTabUnselected(Tab tab, FragmentTransaction ft) {
        SherlockFragment preInitializedFragment = (SherlockFragment) mActivity.getSupportFragmentManager().findFragmentByTag(mTag);

        if (preInitializedFragment != null) {
            // Detach the fragment, because another one is being attached
            ft.detach(preInitializedFragment);
        }
    }

    public void onTabReselected(Tab tab, FragmentTransaction ft) {
        // User selected the already selected tab. Usually do nothing.
    }
}

MyFragment.java

public class MyFragment extends SherlockFragment {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        new AsyncTask<Void, Void, Void>() {

            @Override
            protected Void doInBackground(Void... params) {
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException ex) {
                }
                return null;
            }

            @Override
            protected void onPostExecute(Void result){
                getResources().getString(R.string.app_name);
            }

        }.execute();
    }
}

I've added the Thread.sleep part to simulate downloading data. The code in the onPostExecute is to simulate use of the Fragment.

데이터 다운로드를 시뮬레이트하기 위해 Thread.sleep 부분을 추가했습니다. onPostExecute의 코드는 Fragment 사용을 시뮬레이션하기 위한 것입니다.

 

When I rotate the screen very fast between landscape and portrait, I get an Exception at the onPostExecute code:

화면을 가로와 세로 사이에서 매우 빠르게 회전하면 onPostExecute 코드에서 예외가 발생합니다.

 

java.lang.IllegalStateException: Fragment MyFragment{410f6060} not attached to Activity

 

I think it's because a new MyFragment has been created in the meantime, and was attached to the Activity before the AsyncTask finished. The code in onPostExecute calls upon a unattached MyFragment.

그동안 새로운 MyFragment가 생성되어 AsyncTask가 완료되기 전에 Activity에 연결되었기 때문이라고 생각합니다. onPostExecute의 코드는 연결되지 않은 MyFragment를 호출합니다..

 

But how can I fix this?

하지만 어떻게 고칠 수 있을까요?

 

 

 

 높은 점수를 받은 Solution 

I've found the very simple answer: isAdded():

아주 간단한 답을 찾았습니다. isAdded():

 

Return true if the fragment is currently added to its activity.

플래그먼트가 현재 액티비티에 추가된 경우 true를 반환합니다.
@Override
protected void onPostExecute(Void result){
    if(isAdded()){
        getResources().getString(R.string.app_name);
    }
}

 

To avoid onPostExecute from being called when the Fragment is not attached to the Activity is to cancel the AsyncTask when pausing or stopping the Fragment. Then isAdded() would not be necessary anymore. However, it is advisable to keep this check in place.

Fragment가 Activity에 연결되어 있지 않을 때 onPostExecute가 호출되지 않도록 하려면 Fragment를 일시 중지하거나 중지할 때 AsyncTask를 취소해야 합니다. 그러면 isAdded()가 더 이상 필요하지 않습니다. 그러나 그것은 확인을 위해 제자리에 두는 것이 좋습니다.

 

 

 

 가장 최근 달린 Solution 

if (getActivity() == null) return;

works also in some cases. Just breaks the code execution from it and make sure the app not crash

경우에 따라 작동하기도 합니다. 코드 실행을 중단하고 앱이 충돌하지 않도록 합니다.

 

 

 

출처 : https://stackoverflow.com/questions/10919240/fragment-myfragment-not-attached-to-activity

반응형
댓글
공지사항
최근에 올라온 글