ReyclerView.
questions:
- notifyDatasetChanged(), what will this function do ?
AlertDialog.
AlertDialog is very useful when trying to display a "popup window" to user for comfirmation, update small piece of information.
On top level, AlertDialog uses Build pattern to construct the content of a dialog, AlertDialog has several pre-defined view components, such as title, messge, up to 3 buttons. AlertDialog.Builder can help customize the UI and register callbacks.
There are 4 major types of callback listeners, which are defined in DialogInterface:
- OnClickListener : set on the pre-defined buttons, so that when clicked, Button's View.OnClickListener is triggered, then this callabck get called. AlertDialog will ALWAYS send a message to dismiss the dialog after the buttons get clicked.
- OnShowListener : triggered when AlertDialog.show() method get called.
- OnCancelListener : triggered when AlertDialog.cancel() get called, this will also trigger the OnDismissListener() if any, cause dismiss() get called after this.
- OnDismissListener : triggered when AlertDialog.dismiss() called.
Notice all the callback listeners are embeded into andorid.os.Message, "calling the callbacks" means to send corresponding message to the related handlers.
setPositiveButton(text,DialogInterface.onClickListener listener) : what it really do?
This also applies to other buttons.
public Builder setPositiveButton(CharSequence text, final OnClickListener listener) {
P.mPositiveButtonText = text;
P.mPositiveButtonListener = listener;
return this;
}
When AlertController.Param applies to the AlertController:
public void apply(AlertController dialog) {
...
if (mPositiveButtonText != null) {
dialog.setButton(DialogInterface.BUTTON_POSITIVE, mPositiveButtonText,
mPositiveButtonListener, null);
}
...
}
public void setButton(int whichButton, CharSequence text,
DialogInterface.OnClickListener listener, Message msg) {
if (msg == null && listener != null) {
msg = mHandler.obtainMessage(whichButton, listener);
}
switch (whichButton) {
case DialogInterface.BUTTON_POSITIVE:
mButtonPositiveText = text;
mButtonPositiveMessage = msg;
break;
case DialogInterface.BUTTON_NEGATIVE:
mButtonNegativeText = text;
mButtonNegativeMessage = msg;
break;
case DialogInterface.BUTTON_NEUTRAL:
mButtonNeutralText = text;
mButtonNeutralMessage = msg;
break;
default:
throw new IllegalArgumentException("Button does not exist");
}
}
setPositiveButton(text,DialogInterface.onClickListener listener) : How it called ?
When the button is initialized, AlertController give them a View.OnClickListener:
private void setupButtons(ViewGroup buttonPanel) {
int BIT_BUTTON_POSITIVE = 1;
int BIT_BUTTON_NEGATIVE = 2;
int BIT_BUTTON_NEUTRAL = 4;
int whichButtons = 0;
mButtonPositive = (Button) buttonPanel.findViewById(R.id.button1);
mButtonPositive.setOnClickListener(mButtonHandler);
if (TextUtils.isEmpty(mButtonPositiveText)) {
mButtonPositive.setVisibility(View.GONE);
} else {
mButtonPositive.setText(mButtonPositiveText);
mButtonPositive.setVisibility(View.VISIBLE);
whichButtons = whichButtons | BIT_BUTTON_POSITIVE;
}
...
mButtonHandler is mis-named, it is actually a OnClickListener, when triggered, it will send the above registered message to a handler, ButtonHandler:
mButtonHandler will always send out a MSG_DISMISS_DIALOG message.
private static final class ButtonHandler extends Handler {
// Button clicks have Message.what as the BUTTON{1,2,3} constant
private static final int MSG_DISMISS_DIALOG = 1;
private WeakReference<DialogInterface> mDialog;
public ButtonHandler(DialogInterface dialog) {
mDialog = new WeakReference<DialogInterface>(dialog);
}
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case DialogInterface.BUTTON_POSITIVE:
case DialogInterface.BUTTON_NEGATIVE:
case DialogInterface.BUTTON_NEUTRAL:
((DialogInterface.OnClickListener) msg.obj).onClick(mDialog.get(), msg.what);
break;
case MSG_DISMISS_DIALOG:
((DialogInterface) msg.obj).dismiss();
}
}
}
The above messages and handler are handled by AlertController. the other callback listeners, are handled by Dialog. which is AlertDialog's super class.
these callbacks are also wrapped by messages, and send to another handler ListenersHandler Notice that DialogInterface.OnClickListener & DialogInterface.onCancelListener will trigger DialogInterface.OnDismissListener
Preference Activity and Fragments
Settings App is perfect for looking into how perference is working.
Both PreferenceActivity and PreferenceFragment implements the PreferenceManager.OnPreferenceTreeClickListener, they will set themselves as the listener of such event when they are created.
//PreferenceFragment.java
@Override
public void onStart() {
super.onStart();
mPreferenceManager.setOnPreferenceTreeClickListener(this);
}
//Old behavior PreferenceActivity also do such operation.
} else {
// If there are no headers, we are in the old "just show a screen
// of preferences" mode.
setContentView(com.android.internal.R.layout.preference_list_content_single);
mListFooter = (FrameLayout) findViewById(com.android.internal.R.id.list_footer);
mPrefsContainer = (ViewGroup) findViewById(com.android.internal.R.id.prefs);
mPreferenceManager = new PreferenceManager(this, FIRST_REQUEST_CODE);
mPreferenceManager.setOnPreferenceTreeClickListener(this);
}
While each Preference gets triggered, performClick is called.
public void performClick(PreferenceScreen preferenceScreen) {
if (!isEnabled()) {
return;
}
onClick(); // call the onchangelistener on preference
if (mOnClickListener != null && mOnClickListener.onPreferenceClick(this)) { // the the onclicklistener on pereference.
return;
}
PreferenceManager preferenceManager = getPreferenceManager();
if (preferenceManager != null) {
PreferenceManager.OnPreferenceTreeClickListener listener = preferenceManager
.getOnPreferenceTreeClickListener();
if (preferenceScreen != null && listener != null
&& listener.onPreferenceTreeClick(preferenceScreen, this)) {
return;
}
}
if (mIntent != null) {
Context context = getContext();
context.startActivity(mIntent);
}
}
The listener here is the calling PreferenceFragment, so the logic here is depends on the return value from onPreferenceTreeClick:
true : nothing, happens, both fragment and intent from preference are ignored. false: fragment get no way to executed, intent is executed if there is any. super.onPreferenceTreeClick: start fragment first, if no fragment/onPreferenceStartFragment return false, intent is executed instead.
public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen,
Preference preference) {
if (preference.getFragment() != null &&
getActivity() instanceof OnPreferenceStartFragmentCallback) {
return ((OnPreferenceStartFragmentCallback)getActivity()).onPreferenceStartFragment(
this, preference);
}
return false;
}