Android應用Preference相關及源碼淺析 Preference相關基礎概念
1 前言
(資料圖)
前一篇(點我閱讀前一篇《Android應用Preference相關及源碼淺析(SharePreferences篇)》)我們討論分析使用了Android的SharePreferences,相信看過的朋友都有了自己的感悟與理解,這一篇我們繼續乘熱打鐵來說說SharePreferences的衍生品—-Preference組件。
其實Preference組件大家一定不陌生,因為android系統的Setting應用及我們市面上一些符合Android設計思想的應用的設置界面一般都會用它來實現,而且Google原生Android代碼中大量的使用了Preference組件。
簡單說,Preference組件其實就是Android常見UI組件與SharePreferences的組合封裝實現。
2 Preference組件家族基礎
2-1 Preference相關基礎概念
既然要先說說Preference組件家族基礎,那不得不先簡單說說這些Preference組件間的關系,如下一張圖是基于API 22繪制的一副Preference組件繼承關系圖:
怎么樣?相比以前低版本的API來說,谷歌官方又增加了一些實用的Preference組件,不過遺憾的是這里面有些是被hide掉的,有些是在com.android.internal.preference包下的,所以這些hide和com.android.internal.preference包的preference我們應用層是不能直接使用的。
到此你指定會說,這些組件和我們平時用的EditText等組件很類似,而我們平時用的EditText等組件顯示是依賴于Activity和Fragment的,那么這里的Preference組件是怎么顯示的呢?
答案就是Preference組件也有自己依賴顯示的框架,最常見的就像PreferenceActivity等,具體看代碼我們會發現如下:
public abstract class PreferenceActivity extends ListActivity implements PreferenceManager.OnPreferenceTreeClickListener, PreferenceFragment.OnPreferenceStartFragmentCallback {......}public abstract class PreferenceFragment extends Fragment implements PreferenceManager.OnPreferenceTreeClickListener {......}12345678
嘿嘿,明白了吧?其實Preference組件的使用及展示到Window的原理和普通EditText控件展示使用是類似的,因為Preference組件的顯示框架PreferenceActivity及PreferenceFragment都是從基本的Activity及Fragment繼承而來,只是針對Preference進行了二次封裝而已。
到此對Preference組件已經有一個基本的概念認識了,接下來我們就一步一步往下看。
2-2 常用Preference相關基礎組件屬性說明
我們可以發現,Preference組件家族的控件還是比較豐富的,這里肯定不能一一介紹,所以還是代表性的說幾個使用頻率最高作為指引就行了,其他的用到時參考相關官方API或者源碼即可。
2-2-1 獨立控件Preference
所有Preference組件的基類,類似常見控件的TextView,一個單純的item,用于通過SharePreferences存儲操作的設置值,具體翻墻點我。
如下是基類Preference的相關屬性介紹:
attrdescription
android:defaultValue默認值。
android:dependency設置此元素附屬于另一個元素,依賴的可用則當前元素也可用(enable),反之。
android:enabled設置是否可用。
android:fragment指定fragment。
android:icon指定左側的圖標。
android:key選項的名稱,也是用來存儲時唯一的key。
android:layout給當前元素指定一個自定義布局。
android:order偏好的順序。如果不指定,默認的順序將字母。
android:persistent是否將其值存儲到共享SharePreferences。
android:selectable設置是否可以選擇操作。
android:shouldDisableView當enabled設置為false變暗,同時此屬性設置為false時disable但不變暗。
android:summary摘要,配置的簡要說明,顯示在標題下面。
android:title選項的標題,當沒有設置summary時自動垂直居中顯示。
android:widgetLayout控件可調小部件的布局。是為一個優先選擇的布局,比如一個復選框選擇要指定一個自定義布局(注意:包括的只是復選框)在這里。
關于基類Preference提供的方法這里就不再詳細列出了,如需查看,具體翻墻點我。
2-2-2 獨立控件CheckPreference
CheckPreference類似常見控件的CheckBox,一個item,右側有一個CheckBox,用于通過SharePreferences存儲操作的設置值,具體翻墻點我。
如下是CheckPreference的相關屬性介紹:
attrdescription
android:disableDependentsState與android:dependency相反;B可用,則A不可用;B不可用,則A可用。
android:summaryOff選項未選中時顯示的摘要。
android:summaryOn選項被選中時顯示的摘要。
2-2-3 獨立控件EditTextPreference
EditTextPreference類似常見控件的EditText,一個item,點擊彈出一個EditText的對話框,用于通過SharePreferences存儲操作的設置值,具體翻墻點我。
該控件無自有屬性。具體不再介紹,相關方法查看官方API。
2-2-4 獨立控件ListPreference
ListPreference類似常見控件的ListView,一個item,點擊彈出一個ListView的Dialog,用于通過SharePreferences存儲操作的設置值,具體翻墻點我。
如下是ListPreference的相關屬性介紹:
attrdescription
android:entrieslist要顯示的item數組名字。
android:entryValueslist要顯示的item數組值。
2-2-5 獨立控件MultiSelectListPreference
MultiSelectListPreference類似常見控件的ListView,一個item,點擊彈出一個多選的ListView的Dialog,用于通過SharePreferences存儲操作的設置值,具體翻墻點我。
MultiSelectListPreference的相關屬性同上ListPreference。
2-2-6 獨立控件SwitchPreference
SwitchPreference類似常見控件的Switch,一個item,右側有一個Switch控件,用于通過SharePreferences存儲操作的設置值,具體翻墻點我。
如下是SwitchPreference的相關屬性介紹:
attrdescription
android:disableDependentsState與android:dependency相反;B可用,則A不可用;B不可用,則A可用。
android:summaryOff選項未選中時顯示的摘要。
android:summaryOn選項被選中時顯示的摘要。
android:switchTextOff關閉狀態的文字提示。
android:switchTextOn打開狀態的文字提示。
2-2-7 獨立控件RingtonePreference
RingtonePreference就是一個鈴聲選擇item,點擊彈出鈴聲選擇list的dialog,用于通過SharePreferences存儲操作的設置值,具體翻墻點我。
如下是RingtonePreference的相關屬性介紹:
attrdescription
android:ringtoneType鈴聲類型。ringtone/notification/alarm/all
android:showDefault選項中默認的鈴聲。
android:showSilent是否顯示靜音項。
2-2-8 組合控件PreferenceScreen
PreferenceScreen就Preference hierarchy的root節點,實例化他可以使用createPreferenceScreen(Context)方法;這個類可以依附于兩個地方,當一個preferenceactivity指向他時用來作為根布局顯示偏好,當他嵌套出現在另一個Preference hierarchy內部時他會啟動一個新的界面來顯示子項Preference或者設置的intent;綜上也就是說它不僅可以作為設置界面顯示,而且還能夠啟動activity,具體翻墻點我。
如下展示了作為根布局及子布局的兩種情況:
<--!>... other preferences here ...123456789101112131415
<--!>1234567
2-2-9 組合控件PreferenceCategory
PreferenceCategory類似于LinearLayout,用于組合一組可設置標題的Preference,使布局更具備層次感,具體翻墻點我。
這個類也沒有啥特殊的東西介紹,詳細參考API。
到此常用的Preference組件xml屬性介紹完畢,對應的Java方法就不再說明了,還有就是他們的protect方法也不再詳細介紹,具體參見API。
2-3 新增Headers相關基礎組件屬性說明
上面我們簡單介紹了PreferenceScreen相關xml的屬性,這些其實是老版本的處理方式;自從Android 3.0引入Fragment之后,Preference相關的控件也有了變化。
由于PreferenceActivity在3.0開始也需要能夠處理多屏幕碎片化問題,所以Android 3.0之前采用PreferenceScreen嵌套的方法來跳轉分類細則,而Android 3.0及之后使用了Preference Headers的方法來適配多屏幕碎片化問題。
他的核心就是在主屏中通過headers的xml布局列出所有的主題設置項,每個主題設置的詳細設置由各自指定的PreferenceFragment負責,而各自的PreferenceFragment可以如傳統的PreferenceActivity 一樣布局自身的PreferenceScreen。
preference-headers就是他們的root,既然這樣,那我們就來看看Headers相關的組件及方法吧。
2-3-1 PreferenceActivity.Header相關屬性方法使用基礎
點我翻墻查看。Header繼承自Object,實現了Parcelable,用來展示一個item的header。
相關屬性如下:
attrdescription
android:icon
android:breadCrumbShortTitle在fragment顯示的短標題文字。
android:breadCrumbTitle在fragment顯示的標題文字。
android:fragment當選擇該頭文件時,將顯示該fragment的全名稱。
android:id唯一識別id。
android:summaryitem描述信息。
android:titleitem頭名稱。
如下是一個簡單展示:
...... ...... 節點,類似extra,此處省略 -->123456
關于Header的用法下面會詳細演示,基本情況就介紹到這里。
2-4 Preference相關組件顯示操作控制API解釋
有了上面Preference組件基本概念及屬性介紹以后就相當于我們有了磚瓦,接下來就是咋蓋房子了,也就是如何組合這些組件顯示在屏幕上,我們現在就來看看這些常用的操作。
2-4-1 PreferenceActivity相關屬性方法使用基礎
翻墻點我查看。PreferenceActivity繼承自ListActivity,這個類是Preference相關控件展示的基類,在Android 3.0以前推薦直接使用,3.0以后推薦和preferencefragment一起使用,所以你可以看見PreferenceActivity中有些方法現在已經是過時的了。
首先看下PreferenceActivity加載xml目錄下的文件使用的方法,如下:
public class DemoActivity extends PreferenceActivity {@Override public void onBuildHeaders(List target) { super.onBuildHeaders(target); //當大于等于3.0版本時推薦重寫該方法加載xml,headers+fragments模式 loadHeadersFromResource(R.xml.preference_header, target); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) { //當小于3.0版本時推薦重寫該方法加載xml,當然大于時也可以用,只是不推薦而已 addPreferencesFromResource(R.xml.preference); } }}1234567891011121314
如下我們來看看PreferenceActivity相關的常用方法:
methoddescription
public void addPreferencesFromIntent(Intent intent)@deprecated,添加一個匹配intent的preferences activity。
public void addPreferencesFromResource(int preferencesResId)@deprecated,添加一個xml到activity。
public Preference findPreference(CharSequence key)@deprecated,查找一個指定key的Preference。
public void finishPreferencePanel(Fragment caller, int resultCode, Intent resultData)結束指定的fragment,參數返回類似activity。
public PreferenceManager getPreferenceManager()@deprecated,獲取activity使用的PreferenceManager實例。
public PreferenceScreen getPreferenceScreen()@deprecated,獲取當前activity的根布局視圖。
public boolean hasHeaders()返回當前activity是否顯示了header list。
public void invalidateHeaders()刷新已經顯示的header list,會重新回調onBuildHeaders()。
public boolean isMultiPane()是否同時顯示headers和fragment。
public void loadHeadersFromResource(int resid, List target)解析一個headers的xml然后添加到target列表里。
public void onBuildHeaders(List target)一般需要重寫,注意!這個函數可能不是總會被調用,例如,如果該Activity已被要求顯示一個特定的Fragment而不需要頭文件,就不需要構建Headers,所以不調運。
public Intent onBuildStartFragmentIntent(String fragmentName, Bundle args, int titleRes, int shortTitleRes)構造一個顯示Fragment的Intent對象。
public void onContentChanged()當界面發生變化時回調。
public void onHeaderClick(PreferenceActivity.Header header, int position)當選擇Headers列表項時調用,默認實現調用startwithfragment或switchtoheader。
public boolean onIsMultiPane()大屏下默認實現是true。
public boolean onPreferenceStartFragment(PreferenceFragment caller, Preference pref)當單擊某個具有與它相關聯的gragment類名稱時調用。
public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference)@deprecated,當Preference控件被點擊時,觸發該方法。參數preference為點擊的對象,返回值true代表點擊事件已成功捕捉,無須執行默認動作或者返回上層調用,例如,不跳轉至默認Intent。
public void setListFooter(View view)給Headers list設置foot view。
public void startPreferenceFragment(Fragment fragment, boolean push)起一個fragment,push決定是否入棧。
public void startPreferencePanel(String fragmentClass, Bundle args, int titleRes, CharSequence titleText, Fragment resultTo, int resultRequestCode)依據是否multi-pane模式啟動一個preference的fragment(如果是小屏會重啟一個activity顯示)。
public void startWithFragment(……)啟動一個新的fragment。
public void switchToHeader(……)在大屏multi-pane模式下切換到fragment顯示給定參數的fragment。
2-4-2 PreferenceFragment相關屬性方法使用基礎
翻墻點我查看。PreferenceFragment繼承自Fragment,這個類是3.0以后推薦使用的,用來處理碎片化問題。
該類的常用方法和上面PreferenceActivity的介紹差不多,這里不再詳細說明,只是PreferenceActivity的@deprecated方法在PreferenceFragment中不是@deprecated的而已。
2-4-3 PreferenceManager相關方法使用基礎
翻墻點我查看。PreferenceManager繼承自Object,這個類其實我們前一篇《Android應用Preference相關及源碼淺析(SharePreferences篇)》獲取Preference實例就該說明的,這里才說而已。
Android中得到SharedPreference的方式有四種:
ContextWrapper.getSharedPreferences(String name, int mode) 可以自己設置SharedPreference的名字與模式。
Activity.getPreferences(int mode) name是Activity名字,不能設置。
PreferenceManager.getSharedPreferences() 通過PreferenceManager維護一個SharedPreference,我們可以調用PreferenceManager的API來設置name和mode,并且最終也是調用到ContextWrapper的getSharedPreferences。
PreferenceManager.getDefaultSharedPreferences(Context context) 得到的SharedPreference是某個包名下共享私有的,不能讓其他的包訪問,而且name和mode不能設置,最終也會調用到ContextWrapper的getSharedPreferences。
接下來簡單看下PreferenceManager相關方法,如下:
methoddescription
PreferenceManager.OnActivityDestroyListener當所依賴的activity銷毀時回調接口。
PreferenceManager.OnActivityResultListener當所依賴的activity得到返回result時回調接口。
PreferenceManager.OnActivityStopListener當所依賴的activity停止時回調接口。
public Preference findPreference(CharSequence key)通過key找到Preference。
public static SharedPreferences getDefaultSharedPreferences(Context context)每個應用有一個默認的preferences文件,通過該方法獲取。
public SharedPreferences getSharedPreferences()通過PreferenceManager維護一個SharedPreference,可以調用PreferenceManager的API來設置name和mode。
public int getSharedPreferencesMode()獲取當前的mode。
public String getSharedPreferencesName()獲取當前的name。
public static void setDefaultValues(Context context, String sharedPreferencesName, int sharedPreferencesMode, int resId, boolean readAgain)更加靈活的設置默認值,注意readAgain參數。
public static void setDefaultValues(Context context, int resId, boolean readAgain)設置默認值,注意readAgain參數。
public void setSharedPreferencesMode(int sharedPreferencesMode)設置當前的mode。
public void setSharedPreferencesName(String sharedPreferencesName)設置當前的name。
可以看見,這個類其實也沒啥介紹的,重點關注下setDefaultValues的幾個核心參數就行。如果我們的設置項很多,而且每項在代碼中都需要設置默認缺省值,那就推薦使用setDefaultValues方法。在應用第一次運行時,從preference的xml中獲取缺省值,并生成文件保存(如果已經有一個SharedPrefferences對象,也會進行更新,就像下面代碼中三四行對調);不是第一運行就不會改現有保存值。
protected void onCreate(Bundle savedInstanceState) { ...... PreferenceManager.setDefaultValues(this, R.xml.default_value, false); SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); String option = prefs.getString("key", null); }12345
好了,控件使用就到這里了。
2-5 Preference控件家族實例
關于Preference控件家族的使用比較簡單,自定義網上也一大把,所以不再給出例子。如果你想看例子可以參考如下:
官方Settings設計原理。
Settings源碼。
其他的相關用法參考API及網絡例子。
【工匠若水 http://blog.csdn.net/yanbober 轉載請注明出處。點我開始Android技術交流】
3 Preference組件源碼設計簡單分析
扯蛋了這么多,唉,嘆個氣繼續吧,接下來就到了有意思的環節,源碼結構簡介。這里只是針對Preference控件特性介紹分析,不會過多追究View及Activity和Fragment細節,具體View及Activity和Fragment細節后面會寫文章分析的。
3-1 PreferenceFragment源碼淺析
首先還記得上面基礎說了,PreferenceFragment使用第一步就是使用其內部方法addPreferencesFromResource或者addPreferencesFromIntent設置源。所以這里我們以addPreferencesFromResource為例來說明,如下源碼:
//PreferenceFragment的方法public void addPreferencesFromResource(int preferencesResId) { //判斷異常說明了該方法至少得在super.onCreate方法之后調運,以便初始化PreferenceManager requirePreferenceManager(); //這個前面也介紹過的,設置根布局PreferenceScreen setPreferenceScreen(mPreferenceManager.inflateFromResource(getActivity(), preferencesResId, getPreferenceScreen()));}1234567
接著我們看下setPreferenceScreen方法源碼,如下:
public void setPreferenceScreen(PreferenceScreen preferenceScreen) { //設置根布局到PreferenceManager里 if (mPreferenceManager.setPreferences(preferenceScreen) && preferenceScreen != null) { //空方法 onUnbindPreferences(); //設置標記,在onActivityCreated方法中有用 mHavePrefs = true; //決定是否重設bind布局,核心都是為了執行bindPreferences方法 if (mInitDone) { postBindPreferences(); } }}123456789
到此接下來就是bind了,至于在這里通過Handler發消息bindPreferences還是在onActivityCreated自動調bindPreferences方法取決于你把addPreferencesFromResource方法寫在那個生命周期方法里。如下我們直接來看bindPreferences方法,如下源碼:
//這個方法是搭建顯示的核心方法!?。。。。。。?!private void bindPreferences() { //拿到PreferenceManager中存的根視圖PreferenceScreen final PreferenceScreen preferenceScreen = getPreferenceScreen(); if (preferenceScreen != null) { //傳遞當前ListView到preferenceScreen的bind方法 preferenceScreen.bind(getListView()); } //PreferenceFragment的空方法 onBindPreferences();}12345
到此可以看見PreferenceFragment里bind最終是交給了PreferenceScreen的bind來關聯PreferenceFragment的ListView與PreferenceScreen的ListAdapter。我們現在就來看下PreferenceScreen的bind源碼,如下:
//PreferenceScreen類的方法public void bind(ListView listView) { //設置listview的item監聽 listView.setOnItemClickListener(this); //PreferenceScreen中bind的重點核心?。。。。。。。。。。。?!給listview設置adapter listView.setAdapter(getRootAdapter()); //一些register操作,忽略 onAttachedToActivity();}123456
好了,我們還是來關注這個adapter咋來的吧,如下就是getRootAdapter方法源碼:
public ListAdapter getRootAdapter() { if (mRootAdapter == null) { mRootAdapter = onCreateRootAdapter(); } return mRootAdapter;}protected ListAdapter onCreateRootAdapter() { return new PreferenceGroupAdapter(this);}1234567891011
終于真相快要大白了,PreferenceFragment的listview設置的adapter原來是PreferenceGroupAdapter。哈哈,我們繼續來看看這個類,如下:
//hide類,專門用來Preference的list顯示的adapterpublic class PreferenceGroupAdapter extends BaseAdapter implements OnPreferenceChangeInternalListener {//省略相關屬性定義 ...... //構造方法,傳入的是PreferenceScreen根布局 public PreferenceGroupAdapter(PreferenceGroup preferenceGroup) { ...... //sync設置相關list列表數據后通知listview刷新 syncMyPreferences(); } private void syncMyPreferences() { ...... //通知listview刷新當前準備的Preference列表 notifyDataSetChanged(); ...... } //省略一堆方法 ...... //notifyDataSetChanged后和普通adapter一樣item繪制會回調getView方法 public View getView(int position, View convertView, ViewGroup parent) { //拿到當前item的Preference組件 final Preference preference = this.getItem(position); ...... //調運Preference的getView方法得到當前item真正的view顯示,這是核心?。。。。。。。。。。?! //關于Preference的getView方法下面分析Preference源碼會說到的,或者你可以直接跳到Preference源碼分析部分查看。 View result = preference.getView(convertView, parent); ...... return result; } ......}1234567891011121314151617181920212223242526272829303132
到此你會發現,其實無非就是ListView和Adapter的關系,而Adapter的getView所得到的View由Preference提供而已,而Adapter由PreferenceScreen管理而已。
3-2 PreferenceActivity源碼淺析
說到PreferenceActivity現在不推薦的addPreferencesFromResource方法時其實是沒啥解釋的,這種模式現在被官方推薦通過PreferenceFragment的addPreferencesFromResource來實現,所以也就是說關于PreferenceActivity的addPreferencesFromResource方法(也就是在PreferenceActivity中直接添加Preference組件)其顯示原理和上面分析的PreferenceFragment是一樣的,所以這里就不再過多解釋了。
我們把重點放在loadHeadersFromResource方法上,也就是現在推薦的PreferenceActivity放置Headers模式。接下來就來分析分析吧。
public abstract class PreferenceActivity extends ListActivity implements PreferenceManager.OnPreferenceTreeClickListener, PreferenceFragment.OnPreferenceStartFragmentCallback {...... //省略一堆方法 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //設置基礎布局 setContentView(com.android.internal.R.layout.preference_list_content); //獲取一些ContentView里的控件實例 ...... //判斷是啥模式,左右展示還是單頁 boolean hidingHeaders = onIsHidingHeaders(); mSinglePane = hidingHeaders || !onIsMultiPane(); //獲取fragment參數(其實是PreferenceActivity中點擊Header item重啟PreferenceActivity時傳遞的) String initialFragment = getIntent().getStringExtra(EXTRA_SHOW_FRAGMENT); Bundle initialArguments = getIntent().getBundleExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS); int initialTitle = getIntent().getIntExtra(EXTRA_SHOW_FRAGMENT_TITLE, 0); int initialShortTitle = getIntent().getIntExtra(EXTRA_SHOW_FRAGMENT_SHORT_TITLE, 0); if (savedInstanceState != null) { ...... //忽略,非重點主線 } else { if (initialFragment != null && mSinglePane) { //SinglePane時有參數則替換顯示Fragment switchToHeader(initialFragment, initialArguments); ...... } else { //核心方法之一?。。。。。。。。。。。? //記得上面基礎使用介紹過嗎?新的實現重寫onBuildHeaders空方法,在其中 //調運loadHeadersFromResource方法加載header list xml文件 onBuildHeaders(mHeaders); //如果存在header list則走這里(上面onBuildHeaders里會組織生成mHeaders的list結構) if (mHeaders.size() > 0) { //header-fragment左右各半屏模式 if (!mSinglePane) { if (initialFragment == null) { //設置顯示header Header h = onGetInitialHeader(); switchToHeader(h); } else { //設置顯示header及fragment switchToHeader(initialFragment, initialArguments); } } } } } if (initialFragment != null && mSinglePane) { //當SinglePane加載的是Fragment時隱藏header,顯示fragment findViewById(com.android.internal.R.id.headers).setVisibility(View.GONE); mPrefsContainer.setVisibility(View.VISIBLE); ...... } else if (mHeaders.size() > 0) { //重點?。。。。。。。。。。。。。。。?!這就是要分析的header的listview的adapter放置地 setListAdapter(new HeaderAdapter(this, mHeaders)); ...... } else { //這就是最原始的供已經不推薦的addPreferencesFromResource方式加載Preference組件了 //具體原理同上PreferenceFragment的加載顯示原理了,不再分析 setContentView(com.android.internal.R.layout.preference_list_content_single); ...... } //其他初始設置 ...... }}123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354
通過上面的分析可以看見其實對于Header的adapter核心就是setListAdapter(new HeaderAdapter(this, mHeaders));這句代碼。那我們就來看看這個內部類HeaderAdapter,源碼如下:
//可以發現PreferenceActivity的內部類HeaderAdapter是繼承自ArrayAdapter的,//這個Adapter就是用來給推薦的Header list的listview提供數據的。private static class HeaderAdapter extends ArrayAdapter {//Holder里只有最典型經典的三個組件 private static class HeaderViewHolder {ImageView icon; TextView title; TextView summary; } private LayoutInflater mInflater; //構造方法,不解釋 public HeaderAdapter(Context context, List objects) { super(context, 0, objects); mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); } //最最核心方法?。。。。?!Header list被顯示到PreferenceActivity的listview關鍵點 @Override public View getView(int position, View convertView, ViewGroup parent) { HeaderViewHolder holder; View view; //再常見不過的Adapter數據加載ViewHolder寫法了 if (convertView == null) { //加載header的item布局,都是用的preference_header_item文件,如下會介紹 view = mInflater.inflate(com.android.internal.R.layout.preference_header_item, 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(); } //一堆顯示,通過getItem(position)拿到構造里傳入的List類型objects的item // All view fields must be updated every time, because the view may be recycled Header header = getItem(position); 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; }}1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253
可以看見這個adapter的getView中的item核心是加載了一個preference_header_item的xml文件,然后設置作為item的header。這個xml源碼如下:
12345678910111213141516171819202122232425262728293031323334353637383940414243444546
哈哈,到此就不在解釋啥了,很直觀了,就是這么任性,就是這么簡單的實現了Header List的顯示。
3-3 Preference源碼淺析
說這個的原因是上面PreferenceFragemnt分析加載設置adapter的getView方法時留下的歷史問題。我們先來看看這個文件的核心代碼,后面總結串起來你就明白了,如下源碼:
//可以看見,他不是一個View,但是組合管理了一個View和PreferenceManagerpublic class Preference implements Comparable{...... //各種屬性 ...... private PreferenceManager mPreferenceManager; //重點關注,和自定義及Preference顯示原理息息相關,preference就是下面列出的xml資源 private int mLayoutResId = com.android.internal.R.layout.preference; private int mWidgetLayoutResId; ...... //各種getXXX及setXXX方法 ...... /** * Gets the View that will be shown in the {@link PreferenceActivity}. * 獲取Preference的item顯示view */ public View getView(View convertView, ViewGroup parent) { if (convertView == null) { convertView = onCreateView(parent); } onBindView(convertView); return convertView; } protected View onCreateView(ViewGroup parent) { final LayoutInflater layoutInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); final View layout = layoutInflater.inflate(mLayoutResId, parent, false); final ViewGroup widgetFrame = (ViewGroup) layout.findViewById(com.android.internal.R.id.widget_frame); if (widgetFrame != null) { //mWidgetLayoutResId有專門的set方法可以設置或者重寫 if (mWidgetLayoutResId != 0) { //android:id/widget_frame為mWidgetLayoutResId所對應的布局預留空間插入 layoutInflater.inflate(mWidgetLayoutResId, widgetFrame); } else { //默認實現是null的 widgetFrame.setVisibility(View.GONE); } } return layout; } /** * Binds the created View to the data for this Preference. ** This is a good place to grab references to custom Views in the layout and * set properties on them. * */ protected void onBindView(View view) { //設置子View相關屬性 final TextView titleView = (TextView) view.findViewById(com.android.internal.R.id.title); if (titleView != null) { final CharSequence title = getTitle(); if (!TextUtils.isEmpty(title)) { titleView.setText(title); titleView.setVisibility(View.VISIBLE); } else { titleView.setVisibility(View.GONE); } } ...... //類似的各種子View設置操作,不再列出 } ......}12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596
可以看見,這個getView其實就是上面PreferenceFragment分析中Adapter中getView調運的Preference的getView。怎么樣,串起來吧。也就是說Preference不是View,但是他提供View給ListView的每一個Item顯示,其提供的View的基類布局(上面Preference類中mLayoutResId屬性的值)如下:
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556
哈哈,不用解釋了吧,這下相信你可以將前面基礎使用和源碼分析幾部分完全串起來理解了吧。
3-4 Preference組件家族源碼分析總結
通過上面分析可以知道Preference其實不是View,但是其內部創建管理了一個View(ListView的item,被Adapter的getView通過Preference.getView方法獲得顯示)。
可以看出來,上面我們分析Preference的onCreateView、getView、onBindView這幾個方法其實是整個Preference組件顯示等的核心方法,所以正如系統提供的Preference的各種實用子類一樣,當我們想自定義Preference的時候完全可以重寫這些方法來得到自己的各種自定義View,這樣就完美的解決了代碼的擴展性,我們不用去修改ListAdapter的實現就能實現自定義的Preference,所以說可見Google的工程師在設計Preference結構時是多么的牛叉,不得不膜拜。
【工匠若水 http://blog.csdn.net/yanbober 轉載請注明出處。點我開始Android技術交流】
4 Preference組件家族總結
題外話:其實這篇文章是受我一個朋友邀請幫忙寫的。還記得去年年初我在上家公司(做Android盒子)負責修改一個項目的Settings源碼,添加一個屏幕縮放功能在Settings里面。后來做好以后維護轉手給了別人,當時別人是個新手,各種問。所以落下后遺癥,于是乎就在邀請之下打算寫了這一系列兩篇文章,以幫助快速上手原生Settings的修改。
其實沒啥總結的,還記得前段時間在網上看見有人吐槽Preference是google設計的一個失敗品,一點也不好用啥的。其實我想說Preference的設計還是不錯的,是值得借鑒的,隨便舉個例子如下:
在布局設計上可以保持統一預留差異區域供自定義動態插入,達到復用的目的。
在實現listView各個item不同的Adapter的getView方法時不用像傳統那樣if-else或者switch操作,而是預留一個基類用于實現回調,這樣更加靈活。
其他的慢慢體會就行了。
標簽:
相關推薦:
精彩放送:
- []克羅地亞終獲世界杯季軍,海信電視為每個強者喝彩
- []棕櫚股份景觀設計展現現代與自然的和諧之美
- []世界杯消費趨勢洞察:大屏電視翻倍增長,ULED電視奪冠
- []世界杯觀賽調研公布: Z世代消費者首選海信電視
- []【東海期貨12月20日產業鏈日報】能化篇:中國需求預期提振,油價小漲
- []環球即時看!三立期貨12月20日早間內參——宏觀
- []十八數藏創始人柏松受邀出席“西部國家版權鏈”發布會并作主題發言
- []廣西文旅產業簽約6個重大項目 計劃總投資額達113.6億元
- []今日看點:五礦地產獲授7.8億港元循環貸款額度
- []千紅制藥:公司臨床階段新藥各項工作均在正常推進中,請關注公司定期報告與臨時公告
- []世界信息:三湘印象擬非公開發行股票,募集資金總額不超16億元
- []天天速遞!12月LPR連續4個月維持不變:1年期3.65%、5年期4.30%
- []利民股份:公司子公司江蘇卓邦新能源科技有限公司擬投資建設新能源電池用電解質鹽、功能添加劑及電解液項目
- []每日視點!華夏幸福:相關債務置換議案獲董事會通過
- []當前看點!三木集團:公司的經營一切正常
- []旅游年票發行大勢所趨,專家:要體現出誠意
- []【新要聞】重慶九龍坡區落戶13個重點項目 總投資139.23億元
- []環球聚焦:住建部:1-10月老舊小區改造開工率已達101.7%
- []旭輝將配售8.4億股現有股份 所得款凈額約9.46億港元
- []大消息!500強金融巨頭罕見出手,50億拿下上海外灘核心地塊
- []全球熱點評!廣東肇慶1宗商住地將于2023年1月5日出讓 起價1.2億元
- []世界百事通!深圳機場啟動物流設施建設項目 總投資超50億元
- []天天訊息:新致軟件:本次可轉債的募投項目正在按既定計劃推進,具體進度請關注公司相關公告
- []天天速讀:首都機場:尤為艱難
- []公攤面積內衛生間“消失”,業主起訴房地產公司獲賠償
- []房產中介推銷“添油加醋” 購房者需提高警惕
- []焦點短訊!塔里木油田向新疆南部累計供氣500億立方米
- []今日熱聞!道通科技數字能源中國區產品發布會擬于12月22日舉行
- []動態:新疆為何能成為中國電力新高地?
- []環球信息:上海實業控股46.08億出售上海實森90%股權及相關債權予友邦人壽
- []全球快播:車損包括哪些險種
- []不買交強險上路會怎樣 上路車輛不買交強險會怎樣
- []賦能電力數字化多樣場景 ——深信服云邊安一體化建設方案助力發電行業數字化轉型
- []要聞:網上交車保險怎么辦理 如何在網上交車險
- []儲能電池主要應用在哪些地方?
- []世界快消息!棗莊99元的惠民保險在哪里買 在哪里買棗莊99元的惠民保險
- []實時:怎么查詢自己車輛保險是哪個公司 自己車輛保險是哪個公司怎么查詢
- []滾動:因現行市況 達美樂中國特許經營商達勢股份延遲全球發售
- []華發股份選舉李偉杰為第十屆監事會監事長?
- []今頭條!美股盤前:特斯拉升逾3% 中概股輕微上升 阿里升逾3%
- []拓新藥業:12月16日公司高管蔡玉瑛、渠桂榮、董春紅減持公司股份合計11.14萬股
- []今日聚焦!土地周報 | 重點城市土地供應“斷檔”,市場熱度繼續下行(12.12-12.18)
- []快報:遠洋集團與郵儲銀行簽署全面戰略合作協議 獲180億元授信額度
- []全球觀焦點:房地產逆周期之下,貝殼如何詮釋“堅持難而正確的事”?
- []環球快報:道道全:12月16日公司高管張軍減持公司股份合計6.5萬股
- []九典制藥:12月16日公司高管段立新減持公司股份合計15.51萬股
- []中國建筑1-11月地產業務合約銷售額3484億元
- []全球今熱點:三湘印象擬非公開發行股票 募集資金總額不超過16億
- []全球最資訊丨璞泰來:12月16日至12月19日公司高管陳衛增持公司股份合計3.25萬股
- []全球微動態丨廣東東莞4宗地塊56億成交,華潤聯合體29億斬獲交椅灣地塊
- []當前消息!萬科董事會審議通過發行境外上市外資股(H股)方案
- []【全球報資訊】統聯精密:12月16日公司高管楊虎增持公司股份合計5000股
- []龍軟科技:12月15日公司高管任永智減持公司股份合計1.24萬股
- []中交地產:3個交易日收盤價漲幅累計20%,無應披未披重大事項
- []焦點關注:天津第四批供地收官:24宗地收金99.8億元,僅2宗溢價成交
- []直播預告|一起來看旅游業“神仙打架”名場面!
- []今日報丨南都電源:公司股東人數請參見公司定期報告
- []當前快訊:快訊丨華發股份:選舉李偉杰任監事長
- []前11個月上海商品房銷售面積約1526萬平方米
- []世界今頭條!家居丨奧普家居:回購注銷限制性股票合計279.8萬股
- []財面兒丨大悅城完成發行15億元公司債券 票面利率為4.27%
- []【世界新要聞】昊華能源虛假陳述案開庭 投資者索賠金額已超億元
- []名臣健康:12月16日公司高管彭小青減持公司股份合計27.9萬股
- []簡訊:招商局蛇口36.4億元公司債將上市 利率分別為2.40%、2.80%
- []世界觀點:首開股份:完成發行10億元中期票據 票面利率5%
- []全球報道:金逸影視: 公司暫未涉及上述業務。 祝您生活愉快,投資順利!
- []天天視訊!新希望地產累計獲綜合授信超480億元
- []實時:北上廣深等13市共同發布《城市治理現代化北京宣言》
- []當前簡訊:洲明科技:公司具體產量、銷量及投產情況詳見公司于巨潮資訊網披露的定期報告及相關公告
- []當前視訊!金科股份:截至 2022年11月末,公司已到期未支付的債務本金合計金額90.91億元
- []徽商期貨榮獲和訊第20屆中國財經風云榜“2022年度品牌影響力期貨公司”
- []2元20片退燒藥沖上熱搜第一 股價一字漲停!東北制藥的背后是...?
- []嶺南控股:截至目前,公司的控股子公司廣州廣之旅國際旅行社股份有限公司的出入境旅游組團業務尚未恢復
- []每日觀點:金融街威斯汀酒店30.01億元資產支持ABS已獲受理
- []每日視訊:中鐵建設創業大廈6.7億元資產支持ABS(類REITs)已獲受理
- []深圳南山將再發2億元消費券,推出近百場線上線下促消費活動
- []通訊!中海企業發展30億元公司債券票面利率為2.7%
- []全球熱頭條丨襄陽住房投資10億元公司債券已獲受理
- []【環球播資訊】【券商聚焦】中信證券指地產市場拐點有望顯現 推薦萬科企業(02202)等優秀開發企業
- []ST三圣:百康藥業暫無擴產計劃,將全力保障生產經營,滿足目前市場需求
- []至純科技:公司8寸涂膠顯影設備正在驗證中
- []世界簡訊:天津四批次集中供地收官,全年總成交額315億元
- []迪馬股份:陳涵辭任公司副總裁職務
- []環球觀點:上周樓市整體環比略有上漲,同比持續下降,土地供求環比走高,宅地成交量增近三成
- []得利斯:今年以來,預制菜產品銷量較去年同期有較大幅度增長
- []每日熱文:夢潔股份:公司實施高端品牌戰略,為顧客提供高品質的家居生活方式,傳導充滿愛的家居生活態度
- []全球熱推薦:通行寶:公司近日暫無資產出售和收購重組等的計劃,后續信息請以公司公告為準
- []達安基因:公司全資子公司中山生物工程有限公司已進入24小時持續生產狀態中,已經面向國內市場銷售
- []【天天快播報】市場看漲情緒高漲,2022年黃金有望強勁收官!
- []環球即時:美原油交易策略:下行趨勢線壓制明顯,提防進一步下探風險
- []當前時訊:12月19日匯市觀潮:歐元、英鎊和日元技術分析
- []環球熱點!蜂巢能源第三屆電池日發布超300Ah大容量儲能電池引領新風向
- []熱點評!現貨黃金交易策略:美聯儲進一步加息前景抵消美元走軟影響,金價仍有見頂風險
- []【華安期貨】貴金屬12月18日周報:12月加息落地,金價延續偏強態勢
- []每日播報!國產客機再入印尼,能否雪恥撲朔迷離
- []信息:北京大部分酒店已恢復承辦婚宴、公司年會,接受年夜飯預訂
- []當前通訊!長三角鐵路多地客流增幅明顯,加開多個方向旅客列車保障出行
- []天天速看:民航:明年1月初先恢復到疫情前七成航班量
- []當前熱文:上千條魚涌入柏林市中心,麗笙酒店內世界最大圓柱水族箱炸裂
- []全球頭條:12月19日海源復材漲停分析:蔚來汽車概念股,寧德時代概念股,碳纖維概念熱股
- Makefile宏控是什么?宏控與systemProperty取名對應
- 全球熱點!QGIS|構建選址模型 模型需求分析
- 世界速訊:視頻在html不能播放器怎么辦?網頁播放器打不開的解決方法
- 看熱訊:QT部署YOLOV5 pyqt5搭建YOLOV5的檢測平臺
- Android應用Preference相關及源碼淺析 Preference相關基礎概念
- 世界速看:2021慶陽一中高考成績查詢 2020年慶陽市多所中學高考喜報
- 一個沒有四肢的人 卻給了無數人的力量
- 今日觀點!Win7安裝IE10或IE11怎么操作?離線安裝注意問題
- 《阿凡達2》重磅回歸,聯手海信電視呈現光影之美
- ? 《阿凡達2》震撼首映,與海信電視攜手上演“美學巔峰”
- B站注冊資本增幅400%至5億 目前由陳睿全資持股
- 光源資本出任獨家財務顧問 沐曦集成電路10億元A輪融資宣告完成
- 巨輪智能2021年上半年營收11.24億元 期內研發費用投入增長19.05%
- 紅棗期貨尾盤拉升大漲近6% 目前紅棗市場總庫存約30萬噸
- 嘉銀金科發布2021年Q2財報 期內凈利潤達1.27億元同比增長208%
- 成都銀行2021上半年凈利33.89億元 期內實現營收同比增長17.27億元
- 汽車之家發布2021年第二季度業績 期內新能源汽車品牌收入增長238%
- 中信銀行上半年實現凈利潤290.31億元 期末不良貸款余額706.82億元
- 光伏概念掀起漲停潮交易價格創新高 全天成交額達1.29億元
- 上半年生物藥大增45% 關鍵財務指標好轉營收賬款持續下降
- 全球熱點!12月19日全 聚 德漲停分析:餐飲,預制菜,休閑食品概念熱股
- 天天速讀:上海松江今年推出1701套公租房
- 博眾精工:牽手蜂巢能源 疊片機設備領域將極具競爭優勢
- 每日熱門:中交地產:10億元公司債券票面利率為5.9%
- 阿根廷斬獲大力神杯 海信電視見證梅西圓夢卡塔爾
- 全球速看:浙江義烏3宗地塊40.9億元成交
- 天天快消息!合景泰富擬配售2.35億股 籌資4.67億港元
- 越秀地產上市30年,高質量發展再謀新篇
- 環球資訊:12月19日悅心健康漲停分析:養老產業,裝修裝飾,口腔概念熱股
- 全球信息:12月19日黑芝麻漲停分析:鋰電池,新能源汽車,休閑食品概念熱股
- 利德治療儀 多年良心價格回報客戶
- 梅西加冕!海信電視為潘帕斯雄鷹喝彩
- 觀速訊丨install安裝命令的常見用法 install有哪些優點?
- 天天快看點丨vue怎么引入阿里巴巴圖標?引入的方法教程
- 世界熱頭條丨英偉達開發板中的編譯系統 能否在ZC706的板子上執行?
- 全球今亮點!sprintf函數是什么?sprintf函數用法的詳解
- 全球快播:什么是黑蘋果系統?黑蘋果Mac系統安裝教程
- 今日精選:Linux命令之restore命令 使用語法及參數說明
- 報道:ICMP是什么意思?ICMP的詳解
- 世界消息!Steam賬號怎么注冊?Steam賬號注冊流程
- 【世界快播報】深入理解BootStrap--面板panel BootStrap的原理分析
- 【環球熱聞】杳無音信拼音怎么讀?杳無音信的含義
- 送嬰兒選什么禮物好?送嬰兒禮物排行榜
- 當前報道:什么是audit? audit可以用來干什么?
- 當前熱議!什么是 “云”?云的最后形成
- group by是什么意思?關于group by的用法和原理
- 全球消息!好萊塢十大最可愛的女演員是誰?瑪麗昂歌迪亞僅排末尾
- 天天熱議:【音頻】syntax How to Write Custom Syntax
- JAVA的forEach用法是什么?JAVA的forEach的格式
- 【環球播資訊】大蛇丸的兒子的母親 大蛇丸的老婆是誰?
- 環球滾動:戰地4配置要求有哪些?推薦幾個戰地4配置
- 世界球精選!石家莊核酸檢測20-22號完成 24號低風險區域會讓出門嗎?
- 天天即時看!QPS是什么?QPS的計算方法
- 全球今亮點!box-shadow屬性語法 box-shadow屬性詳解
- 微頭條丨咐組詞和拼音是什么?咐怎么讀?
- linux中常用的sftp命令有哪些?sftp介紹
- 即時焦點:youbastard怎么發音?youbastard的含義
- 世界速遞!sql中的left join 查詢 left join之后的記錄有幾條?
- 全球觀點:瘦金體由誰所創?關于瘦金體由誰所創的介紹
- 如何禁用Windows期自動更新?禁用方法步驟
- 全球信息:乘風破浪的姐姐四公淘汰了誰?乘風破浪的姐姐復活名單
- 環球報道:泰山門票多少錢一張2022 泰山門票價格
- 環球速遞!Windows 10怎么重新安裝微軟商店Microsoft Store?方法步驟
- 天天熱訊:《愛的厘米》好看嗎?佟麗婭佟大為撒狗糧 郭家銘與男主再續兄弟情
- 世界熱議:林丹的個人資料曝光 林丹是誰?
- 視焦點訊!索愛手機w800c怎么樣?索愛手機w800c綜合評測與最新報價
- 環球熱資訊!王力宏被娃哈哈解約后 看到他隨身攜帶的水太佩服
- 環球實時:長絲巾有哪些系法?長絲巾的系法圖解
- 世界通訊!捷安特770d怎么樣?捷安特770d詳細評測
- 硬盤s.m.a.r.t指標數據異常修復工具 硬盤的s m a r t指標數據異常怎么修復?
- 311是什么意思?關于311的詳情介紹
- 世界簡訊:HTC One X Recovery一鍵刷入步驟介紹 HTC One X Recovery一鍵刷入教程
- 當前快報:htc是什么牌子?htc手機的評測
- 環球熱資訊!臺式機硬盤報價如何?臺式機硬盤尺寸
- 世界報道:羽毛球奧運冠軍都有誰?國羽男子奧運冠軍排名
- 全球球精選!諾亞舟np360學習機怎么樣?諾亞舟np360性能介紹
- 定位賽10連勝什么段位?LOL S5定位賽勝率高為什么沒有上段?
- 即時焦點:三星9050好不好?三星9050如何刷機?
- 世界時訊:純甲類功放價格參考及其介紹 純甲類功放的價格
- 世界快看點丨聯想S890支持什么視頻格式?聯想S890支持RMVB播放嗎?
- 操作系統有哪些類型?操作系統的特點是什么?
- 世界熱文:手機鋼化膜哪個品牌質量好?手機鋼化膜的優缺點是什么?
- 死或生5最后一戰怎么反擊?死或生5最后一戰反擊技巧攻略
- 環球視點!諧波減速機優點是什么?齒輪式怎么滾動?
- 焦點快報!計算機主板結構你了解多少?計算機主板的分類
- 報道:計算機撥號連接無法建立連接怎么辦?電信撥號上網連接不上的解決方法
- 怎么用電腦攝像頭錄像?電腦攝像頭錄像的使用方法
- APP(ios、Android)實現充值的方案 ios中充值功能的2種方案
- 暴風影音如何倍速播放?暴風影音倍數播放的方法
- Cubase延音踏板怎么設置?Cubase延音踏板設置延音效果
- 瀏覽器市場占有率排行表 2020年8月國內瀏覽器排行
- 【環球新要聞】人工智能算法是什么?簡化圖形文件
- 環球微動態丨光電耦合器是什么?光電耦合器工作原理詳解
- 焦點簡訊:百度云盒怎么預約購買?電視應用購買教程
- 全球微頭條丨vice versa是什么意思?vice versa通常翻譯
- 【環球報資訊】咸魚Maya筆記 Maya界面是怎么組成的?
- 520還在畫玫瑰?教你用MATLAB畫個玫瑰花球
- 賓得鏡頭簡介 鏡頭術語都有哪些?
- 世界熱門:百度如何清除搜索框內的搜索歷史記錄?清除歷史記錄
- 小米與華為手機哪個好些?小米與華為手機詳細評測
- 華為榮耀4C詳細評測 再次刷新安卓手機性價比
- 世界新動態:人生中的第一個Java程序:HelloWorld
- 世界視點!arp防火墻哪個最好?風云arp防火墻的基本介紹
- 聯想服務器linux系統raid驅動 IntelRAID 6.12版RAID卡驅動官方正式版下載
- 環球觀速訊丨有哪些好看的電影推薦?吐血推薦250部必看電影
- 微動態丨我們為什么要上學?奧巴馬開學演講稿
- 環球熱點!我的世界android制作教程 我的世界怎么去月球?
- 當前滾動:安卓怎么開啟啟動模式?Android四種啟動模式
- 當前速讀:南陽五中2021年高考成績查詢時間 南陽市五中舉行2021年春期開學典禮
- 世界訊息:E. Border是什么?拓展歐幾里得+mod分析
- 世界微資訊!電阻式觸摸屏好用嗎?電阻式觸摸屏工作原理
- 實時:AssemblyInfo.cs文件的作用是什么?AssemblyInfo.cs文件詳情
- 焦點熱訊:小眾國度酒店,如何異國生長?
- 世界時訊:中國鐵建轉讓蘇州京發地產30%股權 廣州新鐵鑫建接盤
- 今日播報!富臨運業:截至2022年12月9日,公司股東人數為24,367人
- 華盛昌:公司正在積極推進呼吸機產品的國內醫療注冊認證相關事宜
- 焦點播報:南雄長和物業擬轉讓南雄市壹城物業30%股權 底價30萬元
- 全球信息:全國畜牧總站掛牌北京元立物業100%股權 轉讓底價為165萬元
- 普利制藥:當前公司生產及產能利用率情況正常,在建產能達到GMP標準的可使用狀態后公司將進行商業化產投
- 每日快報!長株潭煙草物流園100%股權及2.32億債權被掛牌 底價3.67億