Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> PreferenceActivity源碼分析與簡單應用

PreferenceActivity源碼分析與簡單應用

編輯:關於Android編程

·PreferenceActivity可以顯示一系列Header,每一個Header可以關聯一個Fragment或者Activity。此外,它還可以直接顯示Preference條目。

·PreferenceActivity顯示Header的時候有兩種模式:single pane和two panes;如果是Fragment,那麼在two panes模式下,也就是大屏模式下,它可以同時顯示Header和Fragment,這充分利用了屏幕的空間。而在singlepane模式下只會顯示Header,無論如何,我們都可以在Header關聯的Fragment中再顯示Preference條目。

如上描述可用示意圖標示:

\

 

在介紹它的使用方法之前,為了更好的理解PreferenceActivity,我會先對源碼做一個簡單的分析,分析結束後再介紹它的用法,包括顯示Header和顯示preference,這樣更容易理解為什麼會這麼使用。

這裡的Preference指的是顯示在PreferenceActivity中的UI構建塊,例如ListPreference,CheckBoxPreference等,他們都是Preference的子類(非直接):

\

一.源碼分析

這裡主要介紹分析PreferenceActivity中的Header,onBuildHeaders,加載Preference,加載Header,事件處理等內容,下圖是簡單概要:

\

1.繼承關系:

 

\

可以看到PreferenceActivity繼承自ListActivity,而ListActivity是一個封裝了ListView的Activity,在ListActivity中給ListView設置了事件監聽器:

mList.setOnItemClickListener(mOnClickListener);


這個事件監聽器是這樣的:

private AdapterView.OnItemClickListener mOnClickListener = new AdapterView.OnItemClickListener() {

public void onItemClick(AdapterViewparent, View v, int position, long id)

{

onListItemClick((ListView)parent, v, position, id);

}

};


可以看到在監聽器中,又簡單調用了onListItemClick方法,這個方法的定義如下:

protected void onListItemClick(ListView l, View v, int position, long id) {

}

它是一個空的方法,如果你的Activity繼承自ListActivity,想處理ListView的事件的話,只需要重寫這個方法。

ListActivity中提供了給ListView設置適配器的接口,但是適配器還得自己去寫,因此可以說ListActivity功能有限。PreferenceActivity繼承了ListActivity,那麼它當然主要是一個ListView了,那麼它會怎樣給ListView設置適配器呢?它又怎樣處理按鍵事件?

2.Header

Header是PreferenceActivity一個非常重要的概念,PreferenceActivity可以顯示一系列的Header,每一個Header可以給它關聯一個fragment,這樣當你點擊這個Header時,就會打開它關聯的fragment,但是不局限於此,從源碼來看,如果沒有關聯Fragment,那麼也可以設置Intent,此時,可以通過Intent打開對應的Activity。

這個類還有兩種模式,singlepane和two panes,分別針對小屏幕設備和大屏幕設備。對小屏幕設備而言,屏幕只會顯示header,而大屏則會同時顯示它關聯的frament。

Header是一個定義在PreferenceActivity中的內部類:

public static final class Header implements Parcelable {

它實現了Parcelable接口,表明它可以被序列化。它無非就是一個容器,裡面保存了一個條目的所有相關的內容,比如這個條目的title-標題,summary-描述,fragment-關聯的fragment等等。當我們要顯示它的時候,我們只需要構造好Header,然後把它提交給PreferenceActivity就可以了,提交的方法是重寫onBuildHeaders方法,這個方法的參數是一個List

,只需要把自己構造的Header添加到這個List就可以了。此外,還需要覆寫isValidFragment方法,後面會有介紹。

3.給ListView設置適配器

setListAdapter(new HeaderAdapter(this, mHeaders, mPreferenceHeaderItemResId,

mPreferenceHeaderRemoveEmptyIcon));


可以看到它給ListView設置的適配器是一個HeaderAdapter.那麼這個Adapter是什麼呢?

private static class HeaderAdapter extends ArrayAdapter

{

private static class HeaderViewHolder {

ImageView icon;

TextView title;

TextView summary;

}

 

private LayoutInflater mInflater;

private int mLayoutResId;

private boolean mRemoveIconIfEmpty;

 

public HeaderAdapter(Context context, List

objects, int layoutResId,

boolean removeIconBehavior) {

super(context, 0, objects);

mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

mLayoutResId = layoutResId;

mRemoveIconIfEmpty = removeIconBehavior;

}

 

@Override

public View getView(int position, View convertView, ViewGroup parent) {

HeaderViewHolder holder;

View view;

 

if (convertView == null) {

view = mInflater.inflate(mLayoutResId, parent, false);

holder = new HeaderViewHolder();

holder.icon = (ImageView) view.findViewById(com.android.internal.R.id.icon);

holder.title = (TextView) view.findViewById(com.android.internal.R.id.title);

holder.summary = (TextView) view.findViewById(com.android.internal.R.id.summary);

view.setTag(holder);

} else {

view = convertView;

holder = (HeaderViewHolder) view.getTag();

}

 

// All view fields must be updated every time, because the view may be recycled

Header header = getItem(position);

if (mRemoveIconIfEmpty) {

if (header.iconRes == 0) {

holder.icon.setVisibility(View.GONE);

} else {

holder.icon.setVisibility(View.VISIBLE);

holder.icon.setImageResource(header.iconRes);

}

} else {

holder.icon.setImageResource(header.iconRes);

}

holder.title.setText(header.getTitle(getContext().getResources()));

CharSequence summary = header.getSummary(getContext().getResources());

if (!TextUtils.isEmpty(summary)) {

holder.summary.setVisibility(View.VISIBLE);

holder.summary.setText(summary);

} else {

holder.summary.setVisibility(View.GONE);

}

 

return view;

}

}

 

從定義中可以看到,HeaderAdapter是一個ArrayAdapter的子類,並且復寫了getView方法。在getView方法中,根據header中的內容,填充icon,title.summary等。

4.PreferenceActivity的事件處理

@Override

protected void onListItemClick(ListView l, View v, int position, long id) {

if (!isResumed()) {

return;

}

super.onListItemClick(l, v, position, id);

 

if (mAdapter != null) {

Object item = mAdapter.getItem(position);

if (item instanceof Header) onHeaderClick((Header) item, position);

}

}

可以看到它重寫了onListItemClick方法,用於處理事件,在這個方法中調用了onHeaderClick方法:

public void onHeaderClick(Header header, int position) {

if (header.fragment != null) {

if (mSinglePane) {

int titleRes = header.breadCrumbTitleRes;

int shortTitleRes = header.breadCrumbShortTitleRes;

if (titleRes == 0) {

titleRes = header.titleRes;

shortTitleRes = 0;

}

startWithFragment(header.fragment, header.fragmentArguments, null, 0,

titleRes, shortTitleRes);

} else {

switchToHeader(header);

}

} else if (header.intent != null) {

startActivity(header.intent);

}

}


這個方法中判斷header中是否設置了frament,如果設置了,又會判斷是不是處於singpane模式,如果是,就會啟動fragment,如果不是singlepane,那麼肯定就是two panes模式了,這個時候則切換到Header關聯的Fragment中顯示Fragment中的preference。如果沒有設置fragment,那麼又會判斷有沒有設置Intent,如果設置了Intent,那麼會啟動Intent所指向的Activity。

關於Header的顯示,我們可以自定義適配器,這時候需要重寫setListAdapter方法,比如:

@Override

public void setListAdapter(ListAdapter adapter) {

if (adapter == null) {

super.setListAdapter(null);

} else {

 

}

}

這個方法是ListActivity中提供的用於設置適配器的方法,這個方法在PreferenceActivity的onCreate方法中調用,用來給ListView設置適配器。
構造Header則需要重寫onBuildHeaders方法,比如:

@Override

public void onBuildHeaders(List

headers) {

 

}

這個方法在PreferenceActivity的onCreate方法中調用。它的調用在setListAdapter之前,用來構造Header。

二.簡單的使用舉例:

1.代碼構造Header

寫一個Activity,繼承PreferenceActivity,然後覆寫onBuildHeaders方法即可:

public class MainActivity extends PreferenceActivity {

 

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

//setContentView(R.layout.activity_main);

}

 

@Override

public void onBuildHeaders(List

target) {

for(int i=0;i<5;i++){

Header header = new Header();

header.title = "hello"+i;

header.summary = "hehe"+i;

header.extras = new Bundle();

header.fragment = MyFrament.class.getName();

 

target.add(header);

}

super.onBuildHeaders(target);

}

 

}


注意:

1.setContentView要注釋掉,因為如果重新設置ContentView,那麼ListActivity中設置的ListView就找不到了。

2.onBuildHeaders中,構造的header要添加到target列表中。

3.fragment一定要設置,不設置就不會顯示的,因此你需要自己實現一個與Header關聯的Fragment,這個Fragment會在點擊Header的時候被打開。

4.因為PreferenceActivity中已經提供了默認的適配器,所以,如果不需要自定義,則不需重寫setListAdapter方法。

這樣只是單純的可以顯示一些Header,但是點擊Header還是會報錯,我們還必須要覆寫一個方法:

@Override

protected boolean isValidFragment(String fragmentName) {

return true;

}

即明確告訴PrefercenceActivity我們准備了一個合法的Fragment。

在Fragment中可以顯示preference了,這裡暫時什麼都不顯示,這樣打開的是一個空頁面:

public class MyFrament extends PreferenceFragment {

public void onCreate(Bundle b) {

super.onCreate(b);

}

@Override

public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

return null;

}

}

代碼效果如下:

\

 

2.xml構造Header

XML構造Header更加簡單方便。

2.1構建xml文件:

xmlns:android="http://schemas.android.com/apk/res/android">

 

 

 

android:icon="@mipmap/ic_launcher"

android:title="Prefs 1"

android:summary="An example of some preferences." />

 

 

 

android:icon="@mipmap/ic_launcher"

android:title="Prefs 2"

android:summary="Some other preferences you can see.">

 

 

 

 

android:title="Intent"

android:summary="Launches an Intent.">

android:data="http://www.baidu.com" />

 

 

 

2.2加載XML文件:

public void onBuildHeaders(List

target) {

// for(int i=0;i<5;i++){

// Header header = new Header();

// header.title = "hello"+i;

// header.summary = "hehe"+i;

// header.fragment = MyFrament.class.getName();

// target.add(header);

// }

// super.onBuildHeaders(target);

loadHeadersFromResource(R.xml.preference_header, target);

}


也就是說還是要重寫onBuilderHeaders方法,只不過這次試用loadHeadersFromResource方法從xml中加載header了。
代碼效果如下:

\

3.PreferenceActivity顯示preference

PreferenceActivity除了可以顯示Header和它關聯的fragment之外,還可以直接顯示preference,這些prefercence可以直接從XML文件中加載。PreferenceActivity顯示preference的Api大都可以在PreferenceFragment中找到,而且更推薦使用PreferenceFragment來顯示preference,不過在很多比較舊的的代碼中,還保留著很多使用PreferenceActivity顯示preference的代碼。

使用PreferenceActivity顯示preference只需要兩步:

3.1在xml文件下創建xml配置文件:

 

android:icon="@drawable/ic_settings_wifi_4"

android:key="network"

android:title="@string/connectivity_network" >

android:targetClass="com.android.tv.settings.connectivity.NetworkActivity"

android:targetPackage="com.android.tv.settings" />

 

android:icon="@drawable/ic_settings_cast"

android:key="cast"

android:title="@string/system_cast" >

 

android:icon="@drawable/ic_settings_apps"

android:key="apps"

android:title="@string/device_apps" >

android:targetClass="com.android.tv.settings.device.apps.AppsActivity"

android:targetPackage="com.android.tv.settings" />

 

android:icon="@drawable/ic_settings_storage"

android:key="storagereset"

android:title="@string/device_storage_reset" >

android:targetClass="com.android.tv.settings.device.StorageResetActivity"

android:targetPackage="com.android.tv.settings" />

 

android:icon="@drawable/ic_settings_about"

android:key="about_device"

android:title="@string/about_preference">

android:targetClass="com.android.tv.settings.about.AboutActivity"

android:targetPackage="com.android.tv.settings" />

 

 


PreferenceScreen中的內容會顯示在一個新的屏幕中,PreferenceCategory標示一個分組,它會成為一組條目的頭目,而且它是不能獲取焦點的。其他的配置選項這裡就不啰嗦了。

3.2在代碼中加載XML文件

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

//setContentView(R.layout.activity_main);

addPreferencesFromResource(R.xml.item);

}

這樣兩步就可以構造一個設置界面了。

 

 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved