Adapter data changes the implementation principle and case of the existing View, adapterview

Source: Internet
Author: User

Adapter data changes the implementation principle and case of the existing View, adapterview

First, let's talk about the inheritance relationship of the specific class of the Adapter, as shown in

Adapte serves as a bridge between AdapterView and View. The Adapter loads View (such as the data to be displayed in ListView and girdView ). The data to be displayed in the related View is completely decoupled from the View. The data to be displayed in the View is obtained and displayed from the Adapter. The Adapter is responsible for dividing the actual data into views (each data corresponds to a View) let GirdView and other similar components to display these views ,. That is to say, the data to be displayed in the View depends on the Adapter, and the changes in the View (for example, deleting a ListView or adding an Item) also depend on the changes in the data in the Adapter. This means that when the data in the Adapter changes, the corresponding View (such as ListView) also changes accordingly. When the data in the Adapter changes, the View must also be notified, and the View is re-painted to display the View with the changed data.

The Adapter has the following responsibilities:

1) Adapt source data to one View

2) send a notification when the data changes (send a notification to the observer, and then the observer responds accordingly, in the Observer mode) to make the relevant components (GirdView) make changes on the page display.


Some codes of the Adapter are as follows:

Public interface Adapter {/*** registers the observer and notifies * The observer when the data in the Adapter changes. The observer calls onChanged () method to respond accordingly */void registerDataSetObserver (DataSetObserver observer);/*** cancel the registered observer object */void unregisterDataSetObserver (DataSetObserver observer ); /*** adapt the data in the adapter to one View. Each piece of data corresponds to one View, which is used to display the data and finally display it by GirdView and other related components. The getCount () method determines how many views will be generated */View getView (int position, View convertView, ViewGroup parent );}

We can see that the parent interface of adapter defines the method for registering the observer. Next we will look at what the observer has done: the observer here is an extension class of the DataSetObserver abstract class. This abstract class provides two methods:

Public abstract class DataSetObserver {// call public void onChanged () {// Do nothing} public void onInvalidated () {// Do nothing} when the data source changes }}

So how is the observer associated with the Adapter? In fact, the observer object is placed in an ArrayList set. This set is encapsulated in the abstract class Observable <T>. You can see the source code of this class:

Public abstract class Observable <T >{// Save the protected final ArrayList set of the observer object <T> mObservers = new ArrayList <T> (); // register The public void registerObserver (T observer) {if (observer = null) {throw new IllegalArgumentException ("The observer is null. ");} synchronized (mObservers) {if (mObservers. contains (observer) {throw new IllegalStateException ("Observer" + observer + "is already registered. ");} mObservers. add (observer) ;}}// Delete The registered observer public void unregisterObserver (T observer) {if (observer = null) {throw new IllegalArgumentException ("The observer is null. ");} synchronized (mObservers) {int index = mObservers. indexOf (observer); if (index =-1) {throw new IllegalStateException ("Observer" + observer + "was not registered. ");} mObservers. remove (index) ;}// clear all observer public void unregisterAll () {synchronized (mObservers) {mObservers. clear ();}}}
You can see through the source code that Observervable <T> is mainly responsible for adding and deleting added observers! This abstract class also has a subclass DataSetObservable: This class provides two methods on the basis of inheriting the features of the parent class. These two methods are used to send notifications to a series of observers, so that all the observers in the class can execute onChanged () or onInvalidated () to execute specific actions. The source code is as follows:

Public class DataSetObservable extends Observable <DataSetObserver> {// call this method when the data source changes to allow the View to respond to public void policychanged () {synchronized (mObservers) {for (int I = mObservers. size ()-1; I> = 0; I --) {mObservers. get (I ). onChanged () ;}} public void policyinvalidated () {synchronized (mObservers) {for (int I = mObservers. size ()-1; I> = 0; I --) {mObservers. get (I ). onInvalidated ();}}}}

Through the above description, we know that the work of the observer object is indirectly sent by DataSetObservable to inform and execute the observer's onChange method. After reading this, we can see that the observer is still not associated with the corresponding Adapter and how the Adapter sends a notification when the data changes. The following describes the source code of BaseAdapter:


Public abstract class BaseAdapter implements ListAdapter, SpinnerAdapter {// This object is used to register the observer private final DataSetObservable mDataSetObservable = new DataSetObservable (); public boolean hasStableIds () {return false ;} // register the public void registerDataSetObserver (DataSetObserver observer) {mDataSetObservable. registerObserver (observer);} // Delete the public void unregisterDataSetObserver (DataSetObserver observer) {mDataSetObservable. unregisterObserver (observer);} // call this method when the data source changes. public void policydatasetchanged () {mDataSetObservable. policychanged ();} public void policydatasetinvalidated () {mDataSetObservable. notifyInvalidated ();}

Obviously, BaseAdapter contains a DataSetObservable reference mDataSetObservable. According to the preceding instructions, the object represented by this reference contains several observers, the method for registering an observer is the registerDataSetObserver method of BaseAdapter. By reading the source code, you can find that this class provides the yydatasetchanged () method. When the data in the data source or Adapter changes, you must manually call this method to initiate a notification !!!! So far, we have found the method to send notifications to the observer. It is exactly the notifyDataSetChanged () method.

The above only describes how to notify the observer when data changes along the context of the program. What has been done by the onChange method implemented by the observer is not explained. These are implemented by different observer subclasses. We will not discuss them here. The following describes how to display the data in the adapter in the view.

One of the responsibilities of the Adapter is to organize the data source into one view and return a view object. How to organize it is implemented by getView of the Adapter method, this method is actually called when the onMeasure () method is executed, and then specifically called in the obtainView method. Programmers engaged in android development have to deal with this method. I will not repeat it here.

After the data is put into the Adapter, the data is finally presented using the setAdapter () method of GirdView (or this document uses GirdView as an example in ListView. Perhaps careful readers will find that they have not added an observer to their Adapter during their own development? It's just a simple setAdapter (), so you don't have to worry about anything? Otherwise, you will know what setAdapter has done.


Public void setAdapter (ListAdapter adapter) {// clear the mDataSetObserver object if (mAdapter! = Null & mDataSetObserver! = Null) {mAdapter. unregisterDataSetObserver (mDataSetObserver);} // clears all previous data and initializes some necessary parameters resetList (); mRecycler. clear (); // reset the adapter mAdapter = adapter; // initialize the position of the last selected item: mOldSelectedPosition = INVALID_POSITION; // initialize the position of the last selected row, that is: index of the selected row: mOldSelectedRowId = INVALID_ROW_ID; // AbsListView # setAdapter will update choice mode states. super. setAdapter (adapter); if (mAdapter! = Null) {// record the number of items in girdView mOldItemCount = mItemCount; // The data of items in the current girdView = mItemCount = mAdapter. getCount (); // The data has changed mDataChanged = true; // check focus checkFocus (); // register the observer mDataSetObserver = new AdapterDataSetObserver (); mAdapter. registerDataSetObserver (mDataSetObserver); mRecycler. setViewTypeCount (mAdapter. getViewTypeCount (); int position; // determine whether to find the position of Selectable from the end. // lookForSelectablePosition indicates that the second parameter is useless if (mStackFromBottom) from the method implementation) {position = lookForSelectablePosition (mItemCount-1, false);} else {position = lookForSelectablePosition (0, true);} // select the number, the row and current girdview id setSelectedPositionInt (position) are recorded; // select the next setNextSelectedPositionInt (position); // check whether the selected position changes checkSelectionChanged ();} else {checkFocus (); // Nothing selected checkSelectionChanged () ;}// recharge layout requestLayout ();}

Through the source code above, we can find that the AdapterDataSetObserver object will be registered every time setAdapter is called (33 lines of code above), so that the response can be processed when the adapter changes.

Let's take a look at what the specific observer has done:

Class AdapterDataSetObserver extends AdapterView <ListAdapter>. adapterDataSetObserver {@ Override public void onChanged () {// note that the main logic is in super. in the onChanged () method, super. onChanged (); if (mFastScroller! = Null) {mFastScroller. onSectionsChanged () ;}@ Override public void onInvalidated () {super. onInvalidated (); if (mFastScroller! = Null) {mFastScroller. onSectionsChanged ();}}}

The onChange () method calls the onChange () method of the parent class. The main logic for responding to data changes lies in the onChange () method of the parent class, first, let's take a look at the specific implementation of this method for the parent class:

class AdapterDataSetObserver extends DataSetObserver {        private Parcelable mInstanceState = null;        @Override        public void onChanged() {            mDataChanged = true;            mOldItemCount = mItemCount;            mItemCount = getAdapter().getCount();            if (AdapterView.this.getAdapter().hasStableIds() && mInstanceState != null                    && mOldItemCount == 0 && mItemCount > 0) {                AdapterView.this.onRestoreInstanceState(mInstanceState);                mInstanceState = null;            } else {                rememberSyncState();            }            checkFocus();            requestLayout();        }}

Finally, requestLayout () is executed to re-layout the page to respond to data changes. So far, we have completed the description of changing the current View by changing the adapter data.


The following is a case study:

There are

1

Note that the 12 data items are saved in the GirdView. When I click Edit, the page changes to as shown in:

2

The following describes the specific implementation of this effect.

1) the Adapter code is as follows:

Public class CollectionItemAdapter extends BaseAdapter {private Vector <Collection> collections; public static final int EDIT_STATUS = 0; // when the value is zero, the editing state is public static final int UNEDIT_STATUS =-1; // private int delePosition = UNEDIT_STATUS; // Delete the flag public int getDelePosition () {return delePosition;} public void setDelePosition (int delePosition) {this. delePosition = delePosition;} public Vector <Collection> GetCollections () {return collections;} public void setCollections (Vector <Collection> collections) {this. collections = collections ;}@ Overridepublic int getCount () {if (collections! = Null) {return collections. size () ;}// TODO Auto-generated method stubreturn 0 ;}@ Overridepublic Collection getItem (int position) {if (collections! = Null) {return collections. get (position);} // TODO Auto-generated method stubreturn null;} @ Overridepublic long getItemId (int position) {// TODO Auto-generated method stubreturn position ;} @ Overridepublic View getView (int position, View convertView, ViewGroup parent) {ViewItem viewItem = null; if (convertView = null) {viewItem = new ViewItem (); convertView = App. getLayoutInflater (). inflate (R. layout. collection_item, null); viewItem. img = (ImageView) convertView. findViewById (R. id. item_img); viewItem. name = (TextView) convertView. findViewById (R. id. item_name); viewItem. editBg = (ImageView) convertView. findViewById (R. id. collection_edit_bg); convertView. setTag (viewItem);} else {viewItem = (ViewItem) convertView. getTag ();} viewItem. img. setImageResource (R. drawable. no_pic_small); Collection collection = this. getItem (position); viewItem. name. setText (collection. getName (); ImageLoader. getInstance (). displayImage (collection. getPicUrl (), viewItem. img, App. getOptionsSmall (); viewItem. img. setVisibility (View. VISIBLE); if (delePosition = EDIT_STATUS) {// indicates the editing status. // display and delete the background image viewItem. editBg. setVisibility (View. VISIBLE);} else {// hide and delete the background image viewItem. editBg. setVisibility (View. GONE) ;}return convertView;} private static class ViewItem {ImageView img; TextView name; ImageView editBg; public String toString () {return name. getText (). toString ();}}}
Note that the Adapter has a delePosition to indicate whether the field is in the editing status. At the same time, the getView method determines whether the field is in the editing status. When the field is in the non-editing status, the result is 1, when you click Edit, The delePoition is in the editing status, and the page effect is 2. that is to say, if you want to implement this function, you only need to change this field of the Adapter object and then call the yydatasetchanged () method to notify the observer. Therefore, when you click Edit, the response event is:


// Set the delete flag collectionAdapter. setDelePosition (CollectionItemAdapter. UNEDIT_STATUS); // notify the observer of collectionAdapter. yydatasetchanged ();


2) The collection_item.xml configuration file is as follows:

<? Xml version = "1.0" encoding = "UTF-8"?> <RelativeLayout xmlns: android = "http://schemas.android.com/apk/res/android" android: layout_width = "fill_parent" android: layout_height = "fill_parent"> <RelativeLayout android: layout_width = "@ dimen/wiki_item_w" android: layout_height = "@ dimen/wiki_item_h"> <! -- Poster --> <RelativeLayout android: layout_width = "match_parent" android: layout_height = "match_parent" android: padding = "@ dimen/pading_17"> <ImageView android: id = "@ + id/item_img" android: layout_width = "fill_parent" android: layout_height = "fill_parent" android: focusable = "false" android: src = "@ drawable/test"/> </RelativeLayout> <! -- Basemap of the program name --> <RelativeLayout android: layout_width = "match_parent" android: layout_height = "match_parent" android: padding = "@ dimen/pading_15"> <ImageView android: id = "@ + id/item_bg_img" android: layout_width = "fill_parent" android: layout_height = "fill_parent" android: focusable = "false" android: src = "@ drawable/item_txt_bg"/> </RelativeLayout> <! -- Focus frame image --> <ImageView android: id = "@ + id/collection_focus" android: layout_width = "match_parent" android: layout_height = "match_parent" android: background = "@ drawable/item_focus_selecter"/> <! -- The background image is in the editing status, and the visibility is gone. When you click "edit", the image is visible. --> <RelativeLayout android: layout_width = "match_parent" android: layout_height = "match_parent" android: padding = "@ dimen/pading_19"> <ImageView android: id = "@ + id/collection_edit_bg" android: layout_width = "match_parent" android: layout_height = "match_parent" android: focusable = "false" android: background = "@ drawable/record_collection_edit_selecter" android: visib Ility = "gone"/> </RelativeLayout> <! -- Program name --> <TV. huan. epg. vod. qclt. ui. widget. scrollForeverTextView android: id = "@ + id/item_name" android: layout_width = "fill_parent" android: layout_height = "wrap_content" android: layout_alignParentBottom = "true" android: layout_marginBottom = "@ dimen/users" android: layout_marginLeft = "@ dimen/collection_item_name_margin_right" android: layout_marginRight = "@ dimen/users" android: ellipsize = "marquee" android: gravity = "center" android: marqueeRepeatLimit = "marquee_forever" android: singleLine = "true" android: textColor = "@ drawable/font_color_selector" android: textSize = "@ dimen/font_20"/> </RelativeLayout>
In addition, you can click an item during editing to delete the data in the Vector in the Adapter class. After deletion, you can also call the yydatasetchanged () method for notification.

Thank you for your criticism when you are new to android.


How does one implement a custom View on android? Which one can give me a thought?

If you want to divide by type, you can implement custom Views in three ways: custom controls, composite controls, and inherited controls. Next we will learn in sequence how to customize the View in each method.
I. Self-painted controls
The self-painted control means that all the content displayed on this View is drawn by ourselves. The drawn code is written in the onDraw () method, and this part of content has been completely parsed In the Android View rendering process, so you can learn more about View (2) step by step.
Next we prepare to customize a counter View, which can respond to user click events and automatically record the total number of clicks. The code for creating a CounterView inherited from the View is as follows:
<? Xml version = "1.0" encoding = "UTF-8"?> <RelativeLayout xmlns: android = "schemas.android.com/apk/res/android" android: layout_width = "match_parent" android: layout_height = "50dp" android: background = "# ffcb05"> <Button android: id = "@ + id/button_left" android: layout_width = "60dp" android: layout_height = "40dp" android: layout_centerVertical = "true" android: layout_marginLeft = "5dp" android: background = "@ drawable/back_button" android: text = "Back" android: textColor = "# fff"/> <TextView android: id = "@ + id/title_text" android: layout_width = "wrap_content" android: layout_height = "wrap_content" android: layout_centerInParent = "true" android: text = "This is Title" android: textColor = "# fff" android: textSize = "20sp" & #47 ...... remaining full text>

What is the principle of connecting a dview to a database?

The general operation procedure is as follows: bind the datagridiview and dt first (after binding, the data changes of the datagridview, the dt changes and the single table commands of the associated database. This seems to be a bit professional, but the most popular one is

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.