I picked someone android project up and I'm working on updating it and adding some new features for a future rerelease on the Play Store.
My issue right now is with dialogs. When the app was done three years ago, the guy who coded it used already deprecated methods. I've been able to fix them all except for one... here:
#Override
protected void onPrepareDialog(int id, Dialog dialog) {
super.onPrepareDialog(id, dialog); // call super
switch (id) {
case DATE_DIALOG_ID:
((DatePickerDialog) dialog).setOnDismissListener(new OnDismissListener() {
#Override
public void onDismiss(DialogInterface dialog) {
dialog.dismiss();
}
});
break;
case TIME_DIALOG_ID:
((TimePickerDialog) dialog).setOnDismissListener(new OnDismissListener() {
#Override
public void onDismiss(DialogInterface dialog) {
dialog.dismiss();
}
});
break;
}
}
problem is onPrepareDialog is deprecated and I want to fix it without having to change the whole class and its parents. Do you have any idea? I know that I need to use DialogFragment but I can't figure out how to do it efficiently without, like I said, doing the whole class again.
The class containing the code I posted extends a class that extends Activity. It also implements OnCheckedChangeListener.
Thanks
Related
So I'm trying to call a dialogFragment, it works perfectly until I call the onDismiss function from the activity to make an action...
I got a dialog fragment in the hangman game which says if you won or loose, there is a button in the dialog which says if "try again" or "next word", in case you won or loose,
it looks like this:
When the client clicks one of these buttons the dialog will disappear and a new word should appear and reset everything except the word if won...
So I've tried to set onDismiss listener to the dialogFragment inside the activity where the current game is running, but instead of setting dismiss listener, the app crashes with this error:
java.lang.IllegalStateException: Fragment already added: WonDialogFragment{db6bbec}
here is the code where I call the dialogFragment:
// in case the user won
if (isWon) {
// Disable all the buttons immediately.
setEnabledToEachButton(false);
// check if there is already a dialog.
if (!dialogFragment.isAdded() && !dialogFragment.isVisible()) {
// show the dialog
dialogFragment.show(getSupportFragmentManager(), WonDialogFragment.WON_TAG);
dialogFragment.onDismiss(new DialogInterface() {
#Override
public void cancel() {
}
#Override
public void dismiss() {
currentIndex++;
nextWordOrTryAgain();
updateTextView();
}
});
}
}
if I should provide more information to solve my problem let me know...
thank you for your time.
onDismiss is a lifecycle method of DialogFragment. You are not supposed to call it.
You have 2 options,
Try to use the OnDismissListener:
dialogFragment.getDialog().setOnDismissListener(new DialogInterface.OnDismissListener() {
#Override
public void onDismiss(DialogInterface dialogInterface) {
currentIndex++;
nextWordOrTryAgain();
updateTextView();
}
}
Or to Create a custom listener interface:
public interface DialogDismissed {
void onDialogDismissed();
}
Inside you dialog, have a setter and keep the listener interface:
public void setListener(DialogDismissed listener) {
mListener = listener;
}
When you call dismiss() inside you dialog use:
if (mListener != null) {
mListener.onDialogDismissed()
}
And when creating the Dialog, set the listener:
dialogFragment.setListener(new DialogDismissed {
#Override
void onDialogDismissed() {
currentIndex++;
nextWordOrTryAgain();
updateTextView();
}
});
My question may seem special but I need your help with how I create dialog boxes for each element of a recyclerview.
Indeed my fragment contains a recycle view with X elements, and I want that, when the user presses one of the elements for a long time, a dialog box opens and asks him "Are you sure you want to delete this element?" and two buttons "Yes" and "Cancel".
I have succeeded in doing so, but I especially want to know if my way of doing it is the right way, in order to avoid acquiring bad programming reflexes.
#Override
public void onBindViewHolder(#NonNull RecyclerView.ViewHolder holder, int position) {
PlaceViewHolder Pholder =(PlaceViewHolder) holder;
Glide.with(mContext)
.load(mPhotoList.get(position))
.fitCenter()
.into(((PlaceViewHolder) holder).mPlace);
Pholder.mPlace.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View v){
switchContext(mPhotoList.get(position));
}
});
Pholder.mPlace.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View view) {
new MaterialAlertDialogBuilder(mContext)
.setTitle(R.string.profile_photos_dialog_box_title)
.setMessage(R.string.profile_photos_dialog_box_message)
// Specifying a listener allows you to take an action before dismissing the dialog.
// The dialog is automatically dismissed when a dialog button is clicked.
.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
// Continue with delete operation
}
})
// A null listener allows the button to dismiss the dialog and take no further action.
.setNegativeButton(android.R.string.no, null)
.setIcon(android.R.drawable.ic_dialog_alert)
.show();
return true;
}
});
}
As you can see, every time I call onBindViewHolder I add an onClick listen and it is in this last one that I create the dialog box
Moreover, since my message is always the same, should I turn to a contextmenu, even if I find the format of this menu not very adapted to the choices and possible action?
I'm honestly not sure what the "best practice" may be, but I've done this before. How I've done it is, instead of creating the dialog and performing the action inside the longclick handler within onBindViewHolder, I create a custom listener interface so I can pass
relevant data back to the caller. Like this:
MyListListener
public interface MyListListener {
// Where "index" can be the index of the item, or the object represented by the list item at "index"
void onItemLongPressed(int index);
}
I'll pass that into the constructor of my custom RecyclerView.Adapter like this:
MyAdapter
public class MyAdapter extends ... {
private MyListListener listener;
public MyAdapter(MyListListener listener) {
this.listener = listener;
}
}
Then inside onBindViewHolder
MyAdapter / ViewHolder onBindViewHolder
Pholder.mPlace.setOnLongClickListener(new
View.OnLongClickListener() {
#Override
public boolean onLongClick(View view) {
listener.onItemLongPressed(position);
}
});
And then my fragment or activity will implement the listener interface:
MyActivity
public class MyActivity extends ... implements MyListListener {
#Override
public void onItemLongPressed(int index) {
// Show the dialog and do things
}
}
I personally like this because it means my adapters are more isolated. They don't do much outside of showing a list of things. The logic behind those "things" ultimately lives elsewhere. It's easier to unit test this way as well, because you can mock the listener interface.
This is the method to access Android's Back button.
#Override
public void onBackPressed() {
// do something on back.
return;
}
I want to do something similar for the Recent Apps button (the right most one)
You can really change the functionality of the AppButton programatically except if you are creating your own custom launcher but you can still detect if the AppButton is pressed in your app.
sample:
#Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if(!hasFocus)
Log.d("APP BUTTON", "APP BUTTON");
}
I would like to create a CustomEventBanner but have some questions. Im not sure if I do the right things at the right place. Where should I add the Banner to my layout? Do I have to call every method of the CustomEventBannerListener? Which are those which are absolutly necessary? How do I know if there is no Ad to display (no anouncer)??
I actually can display Ad with admob but not using my CustomAd :(
Here is my code:
public class CustomAd implements CustomEventBanner, AdResponseHandler {
private CustomEventBannerListener bannerListener;
protected SASBannerView mBannerView;
#Override
public void requestBannerAd(final CustomEventBannerListener listener,
final Activity activity, String label, String serverParameter,
AdSize adSize, MediationAdRequest mediationAdRequest, Object extra) {
// Keep the custom event listener for use later.
this.bannerListener = listener;
// Determine the best ad format to use given the adSize. If the adSize
// isn't appropriate for any format, an ad will not fill.
// Create banner instance
mBannerView = new SASBannerView(activity);
// Set the listener to register for events.
this.mBannerView.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
try {
listener.onClick();
} catch (Throwable t) {
}
}
});
// Load the ad with the ad request giving an AdResponseHandler
mBannerView.loadAd(42295, "286177", 18008, true, "", this);
}
#Override
public void destroy() { // The destroy method gets called when the mediation
// framework refreshes
// and removes the custom event. Perform any necessary cleanup here.
if (this.mBannerView != null) {
this.mBannerView.onDestroy();
}
}
#Override
public void adLoadingCompleted(SASAdElement arg0) {
this.bannerListener.onReceivedAd(this.mBannerView);
}
#Override
public void adLoadingFailed(Exception arg0) {
this.bannerListener.onFailedToReceiveAd();
}
}
The code looks pretty good. Though your banner doesn't seem to be doing anything on click other than notifying onClick(). If you're banner ends up hitting an external web browser or the play store, you can also call onPresentScreen() and onLeaveApplication() in the onClickListener.
Note that this is just the Custom Event component of your app to implement the SAS network. Your main activity still needs to create an AdView (with a mediation ID set up to target your custom event) and load an ad into it.
Only the onReceivedAd and onFailedToReceiveAd are absolutely necessary for mediation to run. The others are useful so that your main AdView's AdListener can listen for these events.
I'm trying to implement the LVL (Licensing Verification Library for Android), but running into a problem when the license check fails. I pop up a Dialog which explains that the license check failed and presents them with two buttons. One button is "Retry" which I want to immediately do another check or "Purchase App" which redirects them to buy the app on the App Market.
When I tap the Retry button, I can see from logging messages that my licensing check is called, I receive another "dont allow" callback and I try to show the above failure dialog again (I see onPrepareDialog() get called again).
The problem is the second dialog doesn't actually show. So the user can use the app even though the license check failed. Why isn't the dialog popping up again and again?
I believe this is all of the relevant code:
private void checkLicense() {
Log.d(TAG, "Checking License...");
this.licenseChecker.checkAccess(this.licenseCheckerCallback);
}
private class MyLicenseCheckerCallback implements LicenseCheckerCallback {
public void allow() { }
public void dontAllow() {
Log.d(TAG, "License resposne: Don't Allow");
if (isFinishing())
return; // Don't update UI if Activity is finishing.
// Should not allow access. In most cases, the app should assume
// the user has access unless it encounters this. If it does,
// the app should inform the user of their unlicensed ways
// and then either shut down the app or limit the user to a
// restricted set of features.
// In this example, we show a dialog that takes the user to Market.
Log.d(TAG, "Showing No License Dialog");
showDialog(DIALOG_NO_LICENSE_ID);
}
public void applicationError(ApplicationErrorCode errorCode) {
if (isFinishing())
return; // Don't update UI if Activity is finishing.
// This is a polite way of saying the developer made a mistake
// while setting up or calling the license checker library.
showDialog(DIALOG_APPLICATION_ERROR_ID);
}
}
protected Dialog onCreateDialog(int id) {
Log.d(TAG, "Creating Dialog "+id);
switch(id) {
case DIALOG_NO_LICENSE_ID:
return this.makeRetryPurchaseDialog(getString(R.string.no_license));
case DIALOG_APPLICATION_ERROR_ID:
return this.makeRetryPurchaseDialog(this.applicationErrorMessageForDialog);
}
return null;
}
private Dialog makeRetryPurchaseDialog(String message) {
AlertDialog.Builder builder = new AlertDialog.Builder(CalculatorTabActivity.this);
builder.setMessage(message).setCancelable(false)
.setPositiveButton("Retry", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
CalculatorTabActivity.this.checkLicense();
}
}).setNegativeButton("Purchase App", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
CalculatorTabActivity.this.openAppMarket();
}
});
return builder.create();
}
Just as an idea, try to explicitly call for dialog dismissing:
...
.setPositiveButton("Retry", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
dissmissDialog(DIALOG_NO_LICENSE_ID);
CalculatorTabActivity.this.checkLicense();
}
})
Also, if that will not work, try using removeDialog(DIALOG_NO_LICENSE_ID) instead of dissmissDialog(DIALOG_NO_LICENSE_ID).
Finally what code (if at all) do you have in onPrepareDialog() ?