[Android] Fragment 소스 코드 분석 (3) 사무

Fragment 관리 에서 말 하지 않 을 수 없 는 것 은 바로 그의 사무 관리 이다. 그의 사무 관 리 는 매우 훌륭 하 다.우 리 는 먼저 간단 하고 자주 사용 하 는 Fragment 사무 관리 코드 세 션 을 도입 합 니 다.
            FragmentTransaction ft = this.getSupportFragmentManager().beginTransaction();
            ft.add(R.id.fragmentContainer, fragment, "tag");
            ft.addToBackStack("<span style="font-family: Arial, Helvetica, sans-serif;">tag</span><span style="font-family: Arial, Helvetica, sans-serif;">");</span>
            ft.commitAllowingStateLoss();

이 코드 를 실행 하면 fragment Container 컨트롤 에 Fragment 의 내부 에 컨트롤 을 추가 할 수 있 습 니 다.지난번 에 프 래 그 먼 트 는 상태 기 변경 을 통 해 내부 mView 를 생 성 한다 고 했 습 니 다.from layout. xml 방식 을 사용 하지 않 을 때 Fragment. REATED 상태 에서 container 에 대응 하 는 컨트롤 을 검색 한 다음 mView 를 이 부모 컨트롤 에 추가 합 니 다.그렇다면 이 일 은 또 이 안에서 어떤 역할 을 할 까?
먼저 Manager. beginTransaction 이 방법의 반환 값 을 살 펴 보 겠 습 니 다.
/**
     * Start a series of edit operations on the Fragments associated with this
     * FragmentManager.
     *
     * <p>
     * Note: A fragment transaction can only be created/committed prior to an
     * activity saving its state. If you try to commit a transaction after
     * {@link FragmentActivity#onSaveInstanceState
     * FragmentActivity.onSaveInstanceState()} (and prior to a following
     * {@link FragmentActivity#onStart FragmentActivity.onStart} or
     * {@link FragmentActivity#onResume FragmentActivity.onResume()}, you will
     * get an error. This is because the framework takes care of saving your
     * current fragments in the state, and if changes are made after the state
     * is saved then they will be lost.
     * </p>
     */
    public abstract FragmentTransaction beginTransaction();

Fragment 관리 에서 Fragment Manager 의 실현 클래스 는 Fragment Manager Impl 입 니 다. 물론 이것 도 Android 의 일 관 된 명명 방식 입 니 다.
FragmentManagerImpl.java:
@Override
    public FragmentTransaction beginTransaction() {
        return new BackStackRecord(this);
    }

Fragment Manager 는 BackStackRecord 라 는 대상 을 되 돌려 업무 처 리 를 완료 합 니 다.안 드 로 이 드 자 체 를 떠 나 우 리 는 업무 에 대한 이 해 는 주로 데이터 베이스 에서 비롯 된다. 즉, 대량의 조작 으로 당신 의 조작 집합 을 기록 한 다음 에 한꺼번에 처리 하여 업무 처리 시의 안전성 과 효율 성 을 확보한다.Fragment Manager 가 사 무 를 보 는 관점 도 대체적으로 일치 합 니 다. BackStackRecord 의 핵심 방법 은 addOp (Op) 입 니 다.
void addOp(Op op) {
        if (mHead == null) {
            mHead = mTail = op;
        } else {
            op.prev = mTail;
            mTail.next = op;
            mTail = op;
        }
        op.enterAnim = mEnterAnim;
        op.exitAnim = mExitAnim;
        op.popEnterAnim = mPopEnterAnim;
        op.popExitAnim = mPopExitAnim;
        mNumOp++;
    }

우 리 는 BackStackRecord 의 조작 처리 조직 에 대해 '교체 기' 모델 을 사용 하고 모든 조작 이 Op 대상 으로 기록 되 고 '비망록' 모델 로 볼 수 있다 는 것 을 보 았 다.추가 작업 의 입구:
public FragmentTransaction add(Fragment fragment, String tag) {
        doAddOp(0, fragment, tag, OP_ADD);
        return this;
    }

    public FragmentTransaction add(int containerViewId, Fragment fragment) {
        doAddOp(containerViewId, fragment, null, OP_ADD);
        return this;
    }

    public FragmentTransaction add(int containerViewId, Fragment fragment, String tag) {
        doAddOp(containerViewId, fragment, tag, OP_ADD);
        return this;
    }

"Builder" 방식 으로 조직 합 니 다.글 을 시작 할 때 저 는 Fragment 의 사무 관 리 는 비교적 훌륭 한 코드 라 고 언급 했 습 니 다. 단순 한 사 무 는 적어도 세 가지 모델 로 조직 되 었 고 조직 하면 전혀 느낌 이 없습니다.물론 프 래 그 먼 트 가 우리 에 게 준 서 프 라 이 즈 는 여기에 그 치지 않 는 다.우 리 는 위의 코드 세 션 을 통 해 알 수 있 듯 이 실제 적 으로 사무 류 BackStackRecord 를 통 해 Op 대상 이 실제 적 으로 BackStackRecord 의 속성 을 복사 하고 있 기 때문에 모든 Op 안의 데 이 터 를 분석 할 때 BackStackRecord 의 속성 으로 직접 매 핑 할 수 있다.
    int mNumOp;//Op  
    int mEnterAnim;//    
    int mExitAnim;//    
    int mPopEnterAnim;//      
    int mPopExitAnim;//      
    int mTransition;//    
    int mTransitionStyle;
    boolean mAddToBackStack;//     BackStack 

Op 자 체 는 Command 모드 에 속 합 니 다. Command 목록 은 다음 과 같 습 니 다.
    static final int OP_NULL = 0;
    static final int OP_ADD = 1;
    static final int OP_REPLACE = 2;
    static final int OP_REMOVE = 3;
    static final int OP_HIDE = 4;
    static final int OP_SHOW = 5;
    static final int OP_DETACH = 6;
    static final int OP_ATTACH = 7;

아마 너 도 알 아 차 렸 을 거 야. 맞 아, Op 의 속성 은 Command 로 서 의 조작 수 야.BackStackRecord 에서 Commit 를 진행 한 후, BackStackRecord 는 자신 을 Fragment Manager Impl 의 명령 대기 열 에 포함 시 켜 처리한다.모든 처리 부 는 각자 의 Op 작업 을 처리 하 는 데 사용 된다.코드 를 살 펴 보 겠 습 니 다.
BackStackRecord.java:
int commitInternal(boolean allowStateLoss) {
        if (mCommitted) throw new IllegalStateException("commit already called");
        mCommitted = true;
        if (mAddToBackStack) {
            mIndex = mManager.allocBackStackIndex(this);
        } else {
            mIndex = -1;
        }
        mManager.enqueueAction(this, allowStateLoss);
        return mIndex;
    }

BackStackRecord 는 제출 할 때 자신 을 mManager 의 Action 대기 열 에 제출 합 니 다.이러한 Action 대기 열 처 리 는 임의의 스 레 드 에서 진행 할 수 있 습 니 다.
FragmentManager.java:
 
public void enqueueAction(Runnable action, boolean allowStateLoss) {
        if (!allowStateLoss) {
            checkStateLoss();
        }
        synchronized (this) {
            if (mActivity == null) {
                throw new IllegalStateException("Activity has been destroyed");
            }
            if (mPendingActions == null) {
                mPendingActions = new ArrayList<Runnable>();
            }
            mPendingActions.add(action);
            if (mPendingActions.size() == 1) {
                mActivity.mHandler.removeCallbacks(mExecCommit);
                mActivity.mHandler.post(mExecCommit);
            }
        }
    }

우 리 는 실제 Action 이 mExec Commit 명령 에 의 해 실 행 된 것 을 보 았 습 니 다. 그것 은 당신 이 제출 한 BackStack Record 의 run 방법 을 되 돌려 줍 니 다.
BackStackRecord.java:
       Op op = mHead;
        while (op != null) {
             ...
        }

우 리 는 명령 이 교체 기 방식 으로 순환 되 고 있 는 것 을 보 았 다.서로 다른 명령 은 Fragment 에 대해 서로 다른 상태 변경 작업 을 할 것 입 니 다. 간단 한 예 를 들 어:
Op.java:

case OP_ADD: {
                    Fragment f = op.fragment;
                    f.mNextAnim = op.enterAnim;
                    mManager.addFragment(f, false);
                } break;

Fragment 를 추가 해 야 할 때 Op 는 Fragment Manager 의 addFragment 방법 을 호출 합 니 다.
FragmentManager.java:
public void addFragment(Fragment fragment, boolean moveToStateNow) {
        if (mAdded == null) {
            mAdded = new ArrayList<Fragment>();
        }
        makeActive(fragment);
        if (!fragment.mDetached) {
            if (mAdded.contains(fragment)) {
                throw new IllegalStateException("Fragment already added: "
                        + fragment);
            }
            mAdded.add(fragment);
            fragment.mAdded = true;
            fragment.mRemoving = false;
            if (fragment.mHasMenu && fragment.mMenuVisible) {
                mNeedMenuInvalidate = true;
            }
            if (moveToStateNow) {
                moveToState(fragment);
            }
        }
    }

Fragment Manager 는 이 를 자신의 mAdded 대기 열 에 먼저 추가 한 다음 moveToState 방법 으로 Fragment 상 태 를 바 꾸 어 상태의 일치 성 을 확보 합 니 다.이 부분 은 바로 우리 가 지난 부분 에서 말 한 내용 이 므 로 우 리 는 더 이상 군말 하지 않 는 다.이렇게 해서 Fragment 는 이런 우아 한 방식 으로 업무 처 리 를 실현 했다.다음 편 에 서 는 프 래 그 먼 트 가 Stack 관리 에 관 한 일부 소스 코드 를 들 려 드 리 겠 습 니 다.

좋은 웹페이지 즐겨찾기