If I have an ArrayList<DialogFragment> containing DialogFragments of unknown size, how can I programmatically cue up each one so that once the first one is dismissed, the next one is shown, and so on?
for (int i = 0; i < tutorialViews.size(); i++) {
final int current = i;
DialogFragment someDialogFragment = dialogFragmentList.get(i);
if (i == 0) {
someDialogFragment .show(activity.get().getSupportFragmentManager(), "some_dialog_fragment");
}
if (i + 1 != dialogFragmentList.size() - 1) {
someDialogFragment.getDialog().setOnCancelListener(new OnCancelListener() {
#Override
public void onCancel(DialogInterface arg0) {
dialogFragmentList.get(current + 1).show(activity.get().getSupportFragmentManager(), "more_dialog_fragments");
}
});
}
}
Unforunately this doesn't work since the dialog object within a dialogFragment isn't instantiated yet, giving a nullPointerException for the getDialog() call
Create your own interface to callback when the fragmentdialog is closed.
OnDialogFragHide mListener;
public interface OnDialogFragHide {
public void onFragmentDismissed();
}
public void setOnFragDismissedListener(OnDialogFragHide listener) {
mListener = listener;
}
Register the interface in the for loop
if (i == 0) {
tutorial.show(activity.get().getSupportFragmentManager(), "smoking_hawt");
}
if (i != tutorialViews.size() - 1) {
tutorial.setOnFragDismissedListener(new OnDialogFragHide() {
#Override
public void onFragmentDismissed() {
tutorialViews.get(current + 1).show(activity.get().getSupportFragmentManager(), "some_tag");
}
});
}
Call upon the listener whenever the fragment is closed (i.e. in the FragmentDialog's onDismiss() and onCancel() methods, NOT the DIALOG's onDismiss / onCancel listeners.
#Override
public void onDismiss(DialogInterface dialog) {
if (mListener != null && !dismissed) {
dismissed = true;
mListener.onFragmentDismissed();
} else {
Log.e(TAG, "DialogFragmentDismissed not set");
}
super.onDismiss(dialog);
}
#Override
public void onCancel(DialogInterface dialog) {
if (mListener != null && dismissed) {
dismissed = true;
mListener.onFragmentDismissed();
} else {
Log.e(TAG, "DialogFragmentDismissed not set");
}
super.onCancel(dialog);
}
the dismissed boolean is for good measure to make the listener isn't called twice.
Related
I'm trying to catch onMeetingStatusChanged event. But for my case, the onMeetingStatusChanged is sometimes invoked, not all the time. Below is my implemented code:
#Override
protected void onCreate(Bundle savedInstanceState) {
registerListener();
InitAuthSDKHelper.getInstance().initSDK(this, new InitAuthSDKCallback() {
#Override
public void onZoomSDKInitializeResult(int i, int i1) {
}
#Override
public void onZoomAuthIdentityExpired() {
}
});
}
private void registerListener() {
ZoomSDK zoomSDK = ZoomSDK.getInstance();
MeetingService meetingService = zoomSDK.getMeetingService();
if (meetingService != null) {
meetingService.addListener(this);
}
}
#Override
public void onMeetingStatusChanged(MeetingStatus meetingStatus,
int errorCode,
int internalErrorCode) {
LogD.d(TAG, String.valueOf(meetingStatus));
if (meetingStatus == MeetingStatus.MEETING_STATUS_IDLE) {
layout_zoom_loading.setVisibility(View.VISIBLE);
} else {
layout_zoom_loading.setVisibility(View.GONE);
}
if(meetingStatus == MeetingStatus.MEETING_STATUS_FAILED
&& errorCode == MeetingError.MEETING_ERROR_CLIENT_INCOMPATIBLE) {
Toast.makeText(this, "Version of ZoomSDK is too low!", Toast.LENGTH_LONG).show();
}
}
public void joinMeeting(String meetingNo, String meetingPassword) {
ZoomSDK zoomSDK = ZoomSDK.getInstance();
if (!zoomSDK.isInitialized()) {
Toast.makeText(this, getString(R.string.msg_zoom_init_fail), Toast.LENGTH_LONG).show();
return;
}
JoinMeetingHelper.getInstance().joinMeetingWithNumber(this, meetingNo, meetingPassword);
}
I see the cause of this problem. We need to separate the initSDK method to BaseActivity class. So when user forward into the next Activity which runs Zoom meeting, onMeetingStatusChanged always be invoked.
I have an alert dialog reference that I want to dismiss. I have an issue is that I can't just dismiss the reference it to from my dialog, here is the code from my Fragment so you can understand why -
#OnClick(R.id.verification_button_got_it)
void onBtnGotItClicked(View view) {
if (!checkBoxAge.isChecked()) {
checkBoxAge.setTextColor(ContextCompat.getColor(checkBoxAge.getContext(), R.color.accent_red));
return;
}
showProgressDialog();
if (getContext() instanceof VerificationPageListener) {
((VerificationPageListener) getContext()).onPageAgreed();
}
}
private void showProgressDialog(){
if (mBuilder == null) {
mBuilder = new AlertDialog.Builder(App.getAppContext());
}
mBuilder.setCancelable(false);
mBuilder.setView(R.layout.custom_proggress_dialog);
mDialog = mBuilder.create();
mDialog.show();
}
At the point that you see "onPageAgreed()" is the point where the data is being sent to the server to verify the device IMEI for verification purpose, so if I dismiss the dialog at that point than the dialog will not show at all because it will be immediate.
As I said, this is a Fragment that sits on top of activity, so the activity handles the entire checking through the DB thing. Here is the code of the activity handling the database checking and moving the results to the presenter -
#Override
public void onPageAgreed() {
// current page is accepted, move to next
int cur = viewPager.getCurrentItem();
if (cur == adapter.getCount() - 1) {
// ask for permission
requestPhoneState();
} else {
// move to next
viewPager.setCurrentItem(cur + 1, true);
}
}
private void requestPhoneState() {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_PHONE_STATE)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_PHONE_STATE}, RC_PERMISSION_READ_STATE);
} else {
// retrieve IMEI
accessDeviceIdAndVerifyDB(this);
}
}
#Override
protected void onRequestPermissionsResultPostResume(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
super.onRequestPermissionsResultPostResume(requestCode, permissions, grantResults);
if (requestCode == RC_PERMISSION_READ_STATE
&& permissions.length > 0 && StringUtils.equals(permissions[0], Manifest.permission.READ_PHONE_STATE)
&& grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// granted, read IMEI
accessDeviceIdAndVerifyDB(this);
} else {
// failed
onErrorDeviceIdNotGrantedPermission();
}
}
private void accessDeviceIdAndVerifyDB(Activity activity) {
if (ActivityCompat.checkSelfPermission(activity, Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_GRANTED) {
TelephonyManager telephonyManager = (TelephonyManager) activity.getSystemService(Context.TELEPHONY_SERVICE);
if (telephonyManager != null) {
#SuppressLint("HardwareIds") String deviceId = telephonyManager.getDeviceId();
if (StringUtils.isNotBlank(deviceId)) {
checkDeviceIdWithDB(deviceId);
}
}
}
}
private void checkDeviceIdWithDB(String deviceId) {
presenter.onDeviceIdReceived(deviceId);
}
It seems like I am stuck in a loop where I have to move a reference of my dialog all over a few classes just in order to cancel it, which seems really broken. How can I cancel my dialog more easily?
edit -
I have added this code before the point where the activity is being finished -
#Override
public void sendDeviceIdResult(String deviceId, boolean isAlreadyExist) {
int currentItem = viewPager.getCurrentItem();
Fragment item = adapter.getItem(currentItem);
if (item instanceof PhoneStateAndAgeVerificationFragment) {
Dialog dialog = ((PhoneStateAndAgeVerificationFragment) item).getProgressDialog();
if (dialog != null && dialog.isShowing()) {
dialog.dismiss();
}
}
Intent intent = new Intent();
intent.putExtra(KEY_DEVICE_ID, deviceId);
intent.putExtra(KEY_IS_SUCCESS, !isAlreadyExist);
setResult(RESULT_OK, intent);
finish();
}
but at this point my dialog is always null and I can't figure out if at this point it will be always null and the check is redundant or I am doing something total wrong?
You can close your dialog that is in your frament from your activity using interfaces.
In activity create an interface like following.
public class YourActivity extends AppCompactActivity{
public interface onSomeEventListener {
public void closeDialog();
}
onSomeEventListener someEventListener;
//.............
#Override
public void onPageAgreed() {
// current page is accepted, move to next
int cur = viewPager.getCurrentItem();
if (cur == adapter.getCount() - 1) {
// ask for permission
requestPhoneState();
} else {
// move to next
viewPager.setCurrentItem(cur + 1, true);
}
//you can add below line in your activity from where you can close your dialog.
someEventListener.closeDialog();
}
In your fragment you have to implement that interface like below
public class YourFragment extends Fragment implements onSomeEventListener{
#Override
public void closeDialog() {
// here you can close your dialog
if (mDialog != null && mDialog.isShowing()) {
mDialog.dismiss();
}
}
}
UPDATE
In your sendDeviceIdResult() you can simplify the code using the above interface like below.
#Override
public void sendDeviceIdResult(String deviceId, boolean isAlreadyExist) {
int currentItem = viewPager.getCurrentItem();
Fragment item = adapter.getItem(currentItem);
if (item instanceof PhoneStateAndAgeVerificationFragment) {
someEventListener = item; // initialize your interface here instead of onCreate()
someEventListener.closeDialog();
}
Intent intent = new Intent();
intent.putExtra(KEY_DEVICE_ID, deviceId);
intent.putExtra(KEY_IS_SUCCESS, !isAlreadyExist);
setResult(RESULT_OK, intent);
finish();
}
this is recyclerview where I am selecting the option and saving in activity but I want to select
only one option but it is selecting multiple this is the problem, and how to apply mainIndex I am handling in activity and then notify adapter.
#Override
public void onBindViewHolder(#NonNull final ExamQuestionViewHolder holder, int i) {
final ExamQuestionsOptionsItem item = itemList.get(i);
if (!TextUtils.isEmpty(item.getOption()) && item.getOption() != null){
holder.tvOption.setText(item.getOption());
}else {
holder.tvOption.setText("");
}
holder.rlMain.setSelected(item.isSelected());
holder.rlMain.setBackground(ContextCompat.getDrawable(context,
item.isSelected() ? R.drawable.preference_bg_selected : R.drawable.rect_box_white));
holder.rlMain.setAlpha(0.6f);
holder.tvOption.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
holder.rlMain.performClick();
}
});
holder.tvOption.setTextColor(ContextCompat.getColor(context,
item.isSelected() ? R.color.colorPrimary : R.color.font_color));
selecting options
holder.rlMain.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (!isClickable)return;
holder.rlMain.setAlpha(0.6f);
item.setSelected(!item.isSelected());
holder.tvOption.setTextColor(ContextCompat.getColor(context,
item.isSelected() ? R.color.colorPrimary : R.color.font_color));
holder.rlMain.setBackground(ContextCompat.getDrawable(context,
item.isSelected() ? R.drawable.preference_bg_selected :
R.drawable.rect_box_white));
if (item.isSelected()){
selectedOptionList.add(item.getOptionId());
}else {
if (selectedOptionList != null)
selectedOptionList.remove(item.getOptionId());
}
if (selectedOptionList != null)
selectedOptionListner.selectedOptionList(selectedOptionList);
}
});
}
activity calling questions, answer options are appearing in recyclerview and question is in activity textview
protected void fetchQuestions() {
viewsDisable();
Call<ExamQuestionResponse> call =
ApiClient.getInstance().getMainApi().getExamQuestions(Util.getHeaderMap(token), examId);
call.enqueue(new Callback<ExamQuestionResponse>() {
#Override
public void onResponse(Call<ExamQuestionResponse> call, Response<ExamQuestionResponse>
response) {
viewsEnable();
if (response.body() != null) {
ExamQuestionResponse mResponse = response.body();
if (mResponse.isStatus()) {
questionList = mResponse.getData();
if (questionList != null && questionList.size() > 0) {
binding.tvQuestion.setText(questionList.get(mainIndex).getQuestion());
adapter = new ExamQuestionAdapter(ExamQuestionsActivity.this, optionList,
new ExamQuestionAdapter.RecyclerViewClickListener() {
#Override
public void recyclerViewListClicked(View v, int position) {
//adapter.notifyDataSetChanged();
}
}, new ExamQuestionAdapter.SelectedOptionList() {
#Override
public void selectedOptionList(ArrayList<String> list) {
selectedOptionList = list;
}
});
binding.recyclerview.setAdapter(adapter);
} else {
dataNotFound();
}
} else {
dataNotFound();
}
} else {
dataNotFound();
}
}
#Override
public void onFailure(Call<ExamQuestionResponse> call, Throwable t) {
viewsEnable();
}
});
}
// next button in activity, question is updating because i have mainIndex but option are in
// recyclerview they are not updating
binding.tvNext.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mainIndex++;
binding.tvQuestion.setText("");
binding.tvQuestion.setText(questionList.get(mainIndex).getQuestion());
adapter.notifyDataSetChanged();
}
});
I have solved the question I was not using proper indexes to move the index on button click.
I have used index++ or index-- on next and previous button click.
protected void showNextQuestion() {
boolean isAnyItemSelect = false;
List<ExamQuestionsOptionsItem> optionsItems =
examQuestionDataItemList.get(currentIndex).getOptions();
prefConfig.saveOptionsItem(optionsItems);
for (int i = 0; i < optionsItems.size(); i++) {
if (optionsItems.get(i).isSelected()) {
isAnyItemSelect = true;
break;
}
}
if (!isAnyItemSelect) {
Toast.makeText(this, "Please select any answer before proceeding",
Toast.LENGTH_SHORT).show();
return;
}
if (currentIndex == questionListSize - 1) {
showFinishAlert(this.getString(R.string.exam_going_to_finish));
} else {
currentIndex++;
prefConfig.writeRecoverIndex(currentIndex);
if(isReview && !examQuestionDataItemList.get(currentIndex).isReview() )
{
showNextQuestion();
return;
}
setQuestions();
}
}
I am working on an app and I am using a custom dialog which extends DialogFragment. This dialog will contain certain field that I want to pass to the parent activity. I tried implementing OnDismissListener but the parameter is a Dialog Interface.
Any Idea?
parent Activity:
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
BreakCreator mDialog = new BreakCreator();
mDialog.show(getSupportFragmentManager(), "start break Creator");
}
});
listener:
#Override
public void onDismiss(DialogInterface dialog) {
Log.d("debug", "in onDismiss");
BreakCreator mBreakCreator = BreakCreator.class.cast(dialog);// This MIGHT not work
//TODO cast and shit
if(!mBreakCreator.isCancelled() ){
int startMinute = mBreakCreator.getStartMinute();
int startHour = mBreakCreator.getStartHour();
int endMinute = mBreakCreator.getEndMinute();
int endHour = mBreakCreator.getEndHour();
String day = mBreakCreator.getDay();
Break mBreak = new Break(new ultramirinc.champs_mood.Time(startHour, startMinute),
new ultramirinc.champs_mood.Time(endHour, endMinute), day);
breakList.add(mBreak);
Log.d("created", "break added");
recyclerView.invalidate();
}else{
Log.d("debug", "is not cancelled");
}
}
Dialog Class:
public void onDismiss(final DialogInterface dialog) {
super.onDismiss(dialog);
final Activity activity = getActivity();
if (activity instanceof DialogInterface.OnDismissListener) {
((DialogInterface.OnDismissListener) activity).onDismiss(dialog);
}
}
Use a custom listener, below is an example on how this could be implemented. This is also explained in the Android Developer Guide.
public class CustomDialog extends DialogFragment {
public interface CustomListener{
void onMyCustomAction(CustomObject co);
}
private CustomListener mListener;
public void setMyCustomListener(CustomListener listener){
mListener = listener;
}
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
...
Code to create dialog
...
}
#Override
public void onDismiss(DialogInterface dialog) {
if(mListener != null){
CustomObject o = new CustomObject();
mListener.onMyCustomAction(o);
}
super.onDismiss();
}
}
And when the custom dialog is created, set the listener.
CustomDialog awesomeDialog = new CustomDialog();
awesomeDialog.setMyCustomListener(new CustomDialog.CustomListener() {
#Override
public void onMyCustomAction(CustomObject o){
Log.i("TAG",o.toString());
}
});
I have a problem with my Android app coding as follows:
I use dismiss() to hide a dialog, but dialog just does not disappear as expected. Dialog remains in activity interface while dismiss() is actually called.
It feels like get stucked or something else. Hardware back button does not work either. App just gets stuck in there.
Can anyone help me out
Thanks in advance.
Example pic
And there are some related code. I use MVP architect.
#Override
public void editAllNum(Context context, int num, List<ShopCar.GoodListBean> goodList) {
Subscription s = Observable.just(num)
.filter(integer -> goodList.size() != 0) //the goodList of size is never equal to 0.
.subscribeOn(Schedulers.io())
.compose(TransformerUtil.showLoadingDialog(mView)) //call show dialog.
.flatMap(new Func1<Integer, Observable<List<ShopCar.GoodListBean>>>() {
#Override
public Observable<List<ShopCar.GoodListBean>> call(Integer num) {
List<ShopCar.GoodListBean> list = new ArrayList<ShopCar.GoodListBean>();
for ( ShopCar.GoodListBean item : goodList ) {
if ( item.getRemainNum() != 0 ) {
if ( item.getRemainNum() > num ) {
if ( item.getLimit() != 0 ) {
item = editNum(item, num); //editNum is not important
} else {
item.setNum(num);
}
} else {
if ( item.getLimit() != 0 ) {
item = editNum(item, num);
} else {
item.setNum(item.getRemainNum());
}
}
}
list.add(item);
}
return Observable.just(list);
}
})
.flatMap(new Func1<List<ShopCar.GoodListBean>, Observable<List<ShopCar.GoodListBean>>>() {
#Override
public Observable<List<ShopCar.GoodListBean>> call(List<ShopCar.GoodListBean> temp) {
return mPaymentImpl.updateGoodsNumAndQuery(context, temp); //operate databases update some data.
}
})
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<List<ShopCar.GoodListBean>>() {
#Override
public void onCompleted() {
}
#Override
public void onError(Throwable e) {
mView.dismissLoadingDialog();
}
#Override
public void onNext(List<ShopCar.GoodListBean> list) {
mView.dismissLoadingDialog();// call dismiss dialog.
mView.setShopCarFromDB(list);
}
});
addSubscription(s);
}
#Override
public void showLoadingDialog() {
if ( mLoadingDialog == null ) {
mLoadingDialog = new LoadingDialog(getContext());
LogUtils.e(" show loading dialog = " + mLoadingDialog);
}
mLoadingDialog.show();
}
#Override
public void dismissLoadingDialog() {
if ( mLoadingDialog != null ) {
LogUtils.e(" dismiss loading dialog ");
mLoadingDialog.dismiss();
}
}
some code of Dialog.
public class LoadingDialog extends Dialog {
public LoadingDialog(Context context) {
super(context, android.R.style.Theme_Translucent);
}
#Override
protected void onCreate(Bundle savedInstanceState) {
requestWindowFeature(Window.FEATURE_NO_TITLE);
super.onCreate(savedInstanceState);
setContentView(R.layout.widget_loading_dialog);
setCanceledOnTouchOutside(true);
setCancelable(true);
}
}
//XML
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:background="#drawable/loading_dialog_bg"
>
<ProgressBar
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
/>
</RelativeLayout>
</RelativeLayout>
Finally, sorry my English.
Check if the value of mLoadingDialog is null first. Maybe somehow the value is null. ie. the dialog u see on the screen might not be that mLoadingDialog. By change the function below, what did you see in logcat?
#Override
public void dismissLoadingDialog() {
if ( mLoadingDialog != null ) {
LogUtils.e(" dismiss loading dialog ");
mLoadingDialog.dismiss();
}else{
LogUtils.e("mLoadingDialog is null skip dismiss loading dialog ");
}
}