天天看點

Android 5.1 Contacts源碼分析(三):Contacts子產品Fargment結構

1. Contacts 子產品Fragment結構:

下圖為聯系人子產品主要視窗中的Fragment類圖:

Android 5.1 Contacts源碼分析(三):Contacts子產品Fargment結構

從類圖中可以看出,聯系人大部分原生的清單界面(主界面,多選界面等,餘下Fragment未列出),其中的Fragment都繼承自ContactEntryListFragment,,而基類

實作了下面五個接口:

OnFocusChangeListener         //監聽焦點變化;
OnTouchListener               //監聽觸摸時間;
LoaderManager.LoaderCallbacks //傳回LoaderManager中加載的資料;
OnScrollListener              //監聽ListView滾動狀态;
OnItemClickListener           //監聽ListView Item點選事件。
mListView.setOnFocusChangeListener(this);
mListView.setOnTouchListener(this); 
mListView.setOnItemClickListener(this);
mListView.setOnScrollListener(this);
           

(1). OnFocusChangeListener:

@Override
public void onFocusChange(View view, boolean hasFocus) {
    if (view == mListView && hasFocus) {
        hideSoftKeyboard();
    }
}
           

(2). OnTouchListener:

@Override
public boolean onTouch(View view, MotionEvent event) {
    if (view == mListView) {
        hideSoftKeyboard();
    }
    return false;
}
           

從源碼中可以看出,當焦點或者觸摸事件到ListView中時,會做隐藏軟鍵盤的操作。

(3). OnItemClickListener:

protected abstract void onItemClick(int position, long id);
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
    hideSoftKeyboard();

    int adjPosition = position - mListView.getHeaderViewsCount();
    if (adjPosition >= ) {
        onItemClick(adjPosition, id);
    }
}
           

當點選ListView item時觸發該方法,進而調用抽象方法onItemClick(position, id);子類中不需要再去監聽OnItemClickListener,隻需要重寫該方法即可,

(4). OnScrollListener:

@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,
    int totalItemCount) {
}
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
    if (scrollState == OnScrollListener.SCROLL_STATE_FLING) {
        mPhotoManager.pause();
    } else if (isPhotoLoaderEnabled()) {
        mPhotoManager.resume();
    }
}
           

源碼OnScrollListener中定義了3個常量:

public static int SCROLL_STATE_IDLE = ;         //停止滾動
public static int SCROLL_STATE_TOUCH_SCROLL = ; //正在滾動
public static int SCROLL_STATE_FLING = ;        //手指做了抛的動作(手指離開螢幕前,用力滑了一下)
           

這裡當ListView 滾動時,觸發該事件,當使用者手指做了抛的動作時,聯系人頭像會暫停加載(防止畫面出現卡頓現象);否則當照片加載器可用時,會恢複加載聯系人頭像。

以及定義了些公用方法:

protected abstract View inflateView(LayoutInflater inflater, ViewGroup container);
protected abstract T createListAdapter();
protected abstract void onItemClick(int position, long id);
public CursorLoader createCursorLoader(Context context);
……
           

使代碼更可控,風格更統一,大大縮減了重複代碼。

其中:

DefaultContactBrowseListFragment:為聯系人應用展現給使用者的第一個頁面;

以下是AndroidManifest.xml以及ContactSelectionActivity中部分源碼:

<activity android:name=".activities.ContactSelectionActivity">
    <intent-filter>
        <action android:name="android.intent.action.INSERT_OR_EDIT" />
        <category android:name="android.intent.category.DEFAULT" />
        <data android:mimeType="vnd.android.cursor.item/person" />
        <data android:mimeType="vnd.android.cursor.item/contact" />
        <data android:mimeType="vnd.android.cursor.item/raw_contact" />
    </intent-filter>

    <intent-filter>
        <action android:name="android.intent.action.PICK" />
        <category android:name="android.intent.category.DEFAULT" />
        <data android:mimeType="vnd.android.cursor.dir/contact" />
        <data android:mimeType="vnd.android.cursor.dir/person" />
        <data android:mimeType="vnd.android.cursor.dir/phone_v2" />
        <data android:mimeType="vnd.android.cursor.dir/phone" />
        <data android:mimeType="vnd.android.cursor.dir/postal-address_v2" />
        <data android:mimeType="vnd.android.cursor.dir/postal-address" />
        <data android:mimeType="vnd.android.cursor.dir/email_v2" />
    </intent-filter>

    <intent-filter>
        <action android:name="android.intent.action.GET_CONTENT" />
        <category android:name="android.intent.category.DEFAULT" />
        <data android:mimeType="vnd.android.cursor.item/contact" />
        <data android:mimeType="vnd.android.cursor.item/person" />
        <data android:mimeType="vnd.android.cursor.item/phone_v2" />
        <data android:mimeType="vnd.android.cursor.item/phone" />
        <data android:mimeType="vnd.android.cursor.item/postal-address_v2" />
        <data android:mimeType="vnd.android.cursor.item/postal-address" />
    </intent-filter>

    <intent-filter>
        <action android:name="com.android.contacts.action.JOIN_CONTACT" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>
           
public void configureListFragment() {
    switch (mActionCode) {
        case ContactsRequest.ACTION_INSERT_OR_EDIT_CONTACT: {
            ContactPickerFragment fragment = new ContactPickerFragment();
            fragment.setEditMode(true);
            fragment.setDirectorySearchMode(DirectoryListLoader.SEARCH_MODE_NONE);
            fragment.setCreateContactEnabled(!mRequest.isSearchMode());
            mListFragment = fragment;
            break;
        }

        case ContactsRequest.ACTION_DEFAULT:
        case ContactsRequest.ACTION_PICK_CONTACT: {
            ContactPickerFragment fragment = new ContactPickerFragment();
            fragment.setIncludeProfile(mRequest.shouldIncludeProfile());
            mListFragment = fragment;
            break;
        }

        case ContactsRequest.ACTION_PICK_OR_CREATE_CONTACT: {
            ContactPickerFragment fragment = new ContactPickerFragment();
            fragment.setCreateContactEnabled(!mRequest.isSearchMode());
            mListFragment = fragment;
            break;
        }

        case ContactsRequest.ACTION_CREATE_SHORTCUT_CONTACT: {
            ContactPickerFragment fragment = new ContactPickerFragment();
            fragment.setShortcutRequested(true);
            mListFragment = fragment;
            break;
        }

        case ContactsRequest.ACTION_PICK_PHONE: {
            PhoneNumberPickerFragment fragment = getPhoneNumberPickerFragment(mRequest);
            mListFragment = fragment;
            break;
        }

        case ContactsRequest.ACTION_PICK_EMAIL: {
            mListFragment = new EmailAddressPickerFragment();
            break;
        }

        case ContactsRequest.ACTION_CREATE_SHORTCUT_CALL: {
            PhoneNumberPickerFragment fragment = getPhoneNumberPickerFragment(mRequest);
            fragment.setShortcutAction(Intent.ACTION_CALL);

            mListFragment = fragment;
            break;
        }

        case ContactsRequest.ACTION_CREATE_SHORTCUT_SMS: {
            PhoneNumberPickerFragment fragment = getPhoneNumberPickerFragment(mRequest);
            fragment.setShortcutAction(Intent.ACTION_SENDTO);

            mListFragment = fragment;
            break;
        }

        case ContactsRequest.ACTION_PICK_POSTAL: {
            PostalAddressPickerFragment fragment = new PostalAddressPickerFragment();

            mListFragment = fragment;
            break;
        }

        case ContactsRequest.ACTION_PICK_JOIN: {
            JoinContactListFragment joinFragment = new JoinContactListFragment();
            joinFragment.setTargetContactId(getTargetContactId());
            mListFragment = joinFragment;
            break;
        }

        default:
            throw new IllegalStateException("Invalid action code: " + mActionCode);
    }

    // Setting compatibility is no longer needed for PhoneNumberPickerFragment since that logic
    // has been separated into LegacyPhoneNumberPickerFragment.  But we still need to set
    // compatibility for other fragments.
    mListFragment.setLegacyCompatibilityMode(mRequest.isLegacyCompatibilityMode());
    mListFragment.setDirectoryResultLimit(DEFAULT_DIRECTORY_RESULT_LIMIT);

    getFragmentManager().beginTransaction()
            .replace(R.id.list_container, mListFragment)
            .commitAllowingStateLoss();
}
           

從源碼中可知:

其餘的Fragment都屬于聯系人多選界面ContactSelectionActivity:

ContactPickerFragment,

JoinContactListFragment,

PostalAddressPickerFragment,

EmailAddressPickerFragment,

PhoneNumberPickerFragment,

LegacyPhoneNumberPickerFragment;

啟動ContactSelectionActivity時,會根據不同的action打開對應的Fragment,進行相應的操作。