I'm using PreferenceFragmentCompat to display and set SharedPreferences. This all works fine. However, I keep getting "W/InputEventReceiver: Attempted to finish an input event but the input event receiver has already been disposed." in my logs, because the standard dialog used by PreferencesFragmentCompat does not seem to use the .setCancelable(false) in its showDialog method. I guess I could build my own custom dialog, but that seems a bit of an overkill just to solve this one small problem. Is there any way to simply overwrite the method?
Update:
It was enough to add this to my PreferencesFragmet (removed MultiSelectListPreferenceDialogFragmentCompat, as I don't use it)
#Override
public void onDisplayPreferenceDialog(Preference pref) {
DialogFragment dialogFragment = null;
String DIALOG_FRAGMENT_TAG = "androidx.preference.PreferenceFragment.DIALOG";
if (pref instanceof EditTextPreference) {
dialogFragment = EditTextPreferenceDialogFragmentCompat.newInstance(pref.getKey());
} else if (pref instanceof ListPreference) {
dialogFragment = ListPreferenceDialogFragmentCompat.newInstance(pref.getKey());
}
if (dialogFragment != null) {
dialogFragment.setTargetFragment(this, 0);
dialogFragment.setCancelable(false); //adding this!
if (this.getFragmentManager() != null) {
dialogFragment.show(this.getFragmentManager(), DIALOG_FRAGMENT_TAG);
}
} else {
super.onDisplayPreferenceDialog(pref);
}
}
I sorted though PreferenceFramgnetCompat source code to solve this issue.
Unfortunately, you can't execute '.setCancelable(false)' to dialog without callback or override.
I'll explain it with callback.
You should implement 'PreferenceFragmentCompat.OnPreferenceDisplayDialogCallback' interface on activity which contains PreferenceFragmentCompat fragment.
When user press a preference one of EditTextPreference, ListPreference or AbstractMultiSelectListPreference, the onPreferenceDisplayDialog method will be executed.
When onPreferenceDisplayDialog method is executed, you should open dialog.
Fortunately, there are three type dialog and Google provide it by public so you don't need to make a custom dialog for them.
Just create instance of dialog and call setCancelable(false) and show it!
Please refer below codes.
class SettingsActivity : FragmentActivity(), PreferenceFragmentCompat.OnPreferenceDisplayDialogCallback {
private val DIALOG_FRAGMENT_TAG = "android.support.v7.preference.PreferenceFragment.DIALOG"
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
supportFragmentManager.beginTransaction()
.replace(android.R.id.content, SettingsFragment(), "setting_fragment").commit()
}
override fun onPreferenceDisplayDialog(caller: PreferenceFragmentCompat, preference: Preference?): Boolean {
// check if dialog is already showing
if (supportFragmentManager!!.findFragmentByTag(DIALOG_FRAGMENT_TAG) != null) {
return true
}
val f: DialogFragment
if (preference is EditTextPreference) {
f = EditTextPreferenceDialogFragmentCompat.newInstance(preference.getKey())
} else if (preference is ListPreference) {
f = ListPreferenceDialogFragmentCompat.newInstance(preference.getKey())
} else if (preference is AbstractMultiSelectListPreference) {
f = MultiSelectListPreferenceDialogFragmentCompat.newInstance(preference.getKey())
} else {
throw IllegalArgumentException("Tried to display dialog for unknown " + "preference type. Did you forget to override onDisplayPreferenceDialog()?")
}
f.setTargetFragment(supportFragmentManager.findFragmentByTag("setting_fragment"), 0)
f.isCancelable = false // !! HERE !!
f.show(supportFragmentManager!!, DIALOG_FRAGMENT_TAG)
return true
}
}
Related
This is code of button:
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
button.setEnabled(false);
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
button.setEnabled(true);
}
},120000);
}
});
I know that i need to create a sharedpreferences, but I didn't understand how to save condition of button which have a timer, because i know how to save without ussing handler.
How can i do this?
You'll have to use shared preference to save the state. Then, while creating the view of you fragment or activity, you should check the value you saved with shared preference and set the button state accordingly.
Permit me, please, to answer in Kotlin, maybe you or your IDE can do the translation.
To save your button state to shared preference, define this function;
fun setButtonState(context: Context, buttonEnabled: Boolean) {
PreferenceManager.getDefaultSharedPreference(context).edit()
.putBoolean("button", buttonEnabled).apply()
}
Then to get your saved button state from shared preference, define this function;
fun getButtonState(context: Context): Boolean {
return PreferenceManager.getDefaultSharedPreference(context)
.getBoolean("button", false)
}
In your onCreateView set the button state in accordance to your saved value.
val buttonEnabled = getButtonState(requireContext())
button = view.findViewById(R.id.button)
button.isEnabled = buttonEnabled
Then toggle the saved state in shared preference like so:
button.setOnClickListener {
button.isEnabled = false
setButtonState(requireContext(), false)
Handler(Looper.getMainLooper()).postDelayed({
button.isEnabled = true
setButtonState(requireContext(), true)
}, 120000)
}
I hope this helps. :)
I have a class called AlertDialogFragment that will be used to create an alert dialog when needed throughout my program. The fragment that creates the dialog will call a function if the positive button is clicked or nothing if the negative button is clicked. Im fairly new to android development and any tips or help is appreciated.
Here is my AlertDialogFragment:
class AlertDialogFragment : DialogFragment() {
companion object {
private val TAG = "AlertDialogFragment"
fun newInstance(message: String, positiveBtnText: String, negativeBtnText: String): AlertDialogFragment {
val fragment = AlertDialogFragment()
fragment.isCancelable = false
val args = Bundle()
args.putString("aMessage", message)
args.putString("aPositiveBtnText", positiveBtnText)
args.putString("aNegativeBtnText", negativeBtnText)
fragment.arguments = args
return fragment
}
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
Log.d(TAG, "onCreateDialog called")
super.onCreateDialog(savedInstanceState)
return activity?.let {
val builder = AlertDialog.Builder(it)
builder.setMessage(arguments?.getString("aMessage"))
.setPositiveButton(arguments?.getString("aPositiveBtnText"), DialogInterface.OnClickListener { dialog, id ->
Log.d(TAG, "Yes!")
})
.setNegativeButton(arguments?.getString("aNegativeBtnText"), DialogInterface.OnClickListener { dialog, id ->
Log.d(TAG, "Dismiss!")
})
Log.d(TAG, "onCreateDialog ending")
builder.create()
} ?: throw IllegalStateException("Activity can not be null")
}
}
Here is my attempt to initialize the alert dialog and set the target fragment:
try {
AlertDialogFragment alertDialogFragment = new AlertDialogFragment().Companion.newInstance(
"Would you like to continue?",
"Yes",
"Dismiss");
alertDialogFragment.setTargetFragment(this, TARGET_FRAGMENT_REQUEST_CODE);
alertDialogFragment.show(getActivity().getSupportFragmentManager(), "dialog");
}catch (Exception e){
e.printStackTrace();
}
Thanks in advance for any help!
EDIT: I am using kotlin for the alert dialog and the fragment that initializes it, is in java.
You can retrieve the target fragment and request code you passed in and then use that to call onActivityResult:
targetFragment?.let { fragment ->
fragment.onActivityResult(fragment.targetRequestCode, Activity.RESULT_OK, null)
}
and in your function:
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
Log.d(TAG, "onCreateDialog called")
super.onCreateDialog(savedInstanceState)
return activity?.let {
val builder = AlertDialog.Builder(it)
builder.setMessage(arguments?.getString("aMessage"))
.setPositiveButton(arguments?.getString("aPositiveBtnText"), DialogInterface.OnClickListener { dialog, id ->
Log.d(TAG, "Yes!")
targetFragment?.let { fragment ->
fragment.onActivityResult(fragment.targetRequestCode, Activity.RESULT_OK, null)
}
})
.setNegativeButton(arguments?.getString("aNegativeBtnText"), DialogInterface.OnClickListener { dialog, id ->
Log.d(TAG, "Dismiss!")
})
Log.d(TAG, "onCreateDialog ending")
builder.create()
} ?: throw IllegalStateException("Activity can not be null")
}
In your launching fragment you override onActivityResult and handle the returned value.
Note that if your fragment is recreated, you will have to re-assign the target fragment.
I want to know how to add multiple click events to buttons defined in XML, as previously, in Java, we implemented View.onClickListener interface and did the rest of the work in onClick method.
Example:
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.oneButton:
// do your code
break;
case R.id.twoButton:
// do your code
break;
case R.id.threeButton:
// do your code
break;
default:
break;
}
}
I'm making a basic calculator app with the new Kotlin but it seems Kotlin has no such provisions, instead my code looks too long and verbose, as I'm attaching events to all buttons individually.
Can someone tell me how to do the same way in Kotlin? Thanks
For multiple onClickListeners in kotlin (version:1.1.60), the following helped me. Hope it'll be useful to someone else too.
Implement OnClickListener to activity like:
class YourActivity : AppCompatActivity(), View.OnClickListener
set your button in onCreate():
val button = findViewById<Button>(R.id.buttonId)
and assign onclick to the button in onCreate():
button.setOnClickListener { onClick(button) }
and in the override method of onClick() :
override fun onClick(v: View) {
when (v.id) {
R.id.buttonId -> { //your code }
..
..
..
else -> { //your code }
}
}
Yes, in Kotlin you can do it like this:
view.setOnClickListener(object : View.OnClickListener {
override fun onClick(v: View?) {
when(v?.id) {
R.id.imgBack -> {/* do your code */}
R.id.twoButton -> {/* do your code */}
R.id.threeButton -> {/* do your code */}
else -> {/* do your code */}
}
}
}
You can try this following code:
class Testing:AppCompatActivity(), View.OnClickListener {
private val mButton1:Button
private val mButton2:Button
protected fun onCreate(savedInstanceState:Bundle) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_testing)
mButton1 = findViewById(R.id.btn_click) as Button
mButton2 = findViewById(R.id.btn_click1) as Button
mButton1.setOnClickListener(this)
mButton2.setOnClickListener(this)
}
fun onClick(view:View) {
when (view.getId()) {
R.id.btn_click -> {
Toast.makeText(this, "button 1", Toast.LENGTH_SHORT).show()
}
R.id.btn_click1 -> {
Toast.makeText(this, "button 2", Toast.LENGTH_SHORT).show()
}
else -> {}
}
}
}
I hope this is help you.
First of all implement OnClickListener in your Activity, like
class MainActivity : Activity , OnClickListener
then override its implementation like
func onClick(v:View) {
//use when here like
case R.id.youview -> {
// do your work on click of view
}
Don't forgot to set clicklistener on your View.
yourView.setOnClickListener(this)
Or for better understanding go step by step -
Implement OnClickListener in your Activity.
Compiler will ask you to implement overrided methods. Implement those.
Copy paste your java code which you wrote inside onClick method, that can be converted by kotlin itself or write down when conditions.
This code worked for me:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
imgBack.setOnClickListener(this)
twoButton.setOnClickListener(this)
threeButton.setOnClickListener(this)
}
override fun onClick(view:View) {
when (view.id) {
R.id.imgBack -> {
Toast.makeText(this, "imgBack", Toast.LENGTH_SHORT).show()
}
R.id.twoButton -> {
Toast.makeText(this, "twoButton", Toast.LENGTH_SHORT).show()
}
else -> {}
}
}
Don't forget implement View.OnClickListener in your class.
you can create anonymous object from an inteface View.ClickListener and pass it to setOnClickListener function
private val clickListener = View.OnClickListener { p0 ->
when (p0.id) {
....
}
}
... setOnClickListener(clickListener)
Try below like this.
public class MainActivity extends Activity implements View.OnClickListener{
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Button xyz = (Button) findViewById(R.id.xyz);
xyz.setOnClickListener(this);
}
#Override
public void onClick(View v) {
}}
More detailed information at https://androidacademic.blogspot.in/2016/12/multiple-buttons-onclicklistener-android.html
So I am currently working on a simple Dropbox Gallery App as described here.
When I click the button I have to choose the Dropbox Account I want to use.
When I've chosen one Dropbox loads briefly and I return back to the previous screen, where I originally pressed the "Dropbox-Button".
When I click the Button again I get my gallery as I desired.
Now I want to get rid of that extra click - So the user clicks the Dropbox button and after a short time (the login time?) the user can see the requested image gallery.
The following class is the one that is used for the Authentication and I don't know how I can implement some kind of "onSuccess" functionality for it:
public class Auth {
public static void startOAuth2Authentication(Context context, String appKey) {
if (!AuthActivity.checkAppBeforeAuth(context, appKey, true /*alertUser*/)) {
return;
}
// Start Dropbox auth activity.
String apiType = "1";
String webHost = "www.dropbox.com";
Intent intent = AuthActivity.makeIntent(context, appKey, webHost, apiType);
if (!(context instanceof Activity)) {
// If starting the intent outside of an Activity, must include
// this. See startActivity(). Otherwise, we prefer to stay in
// the same task.
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
}
context.startActivity(intent);
}
public static String getOAuth2Token() {
Intent data = AuthActivity.result;
if (data == null) {
return null;
}
String token = data.getStringExtra(AuthActivity.EXTRA_ACCESS_TOKEN);
String secret = data.getStringExtra(AuthActivity.EXTRA_ACCESS_SECRET);
String uid = data.getStringExtra(AuthActivity.EXTRA_UID);
if (token != null && !token.equals("") &&
secret != null && !secret.equals("") &&
uid != null && !uid.equals("")) {
return secret;
}
return null;
}
}
Thank you in advance.
You can catch the successful app authorization event in onResume, as shown in the Dropbox API v2 Java SDK Android example app here:
https://github.com/dropbox/dropbox-sdk-java/blob/7ecc15cf0f51d6ae2ba5cdb334aac2c2f3474b87/examples/android/src/main/java/com/dropbox/core/examples/android/DropboxActivity.java#L16
That's where you should call getOAuth2Token to get the access token from the app authorization.
Okay, I solved my problem with a repetitive Runnable like this:
public class MyActiviry extends BaseActivity {
// ...
private Handler handler;
private Context context;
// ...
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
context = this;
handler = new Handler();
// ...
}
// ...
public void selectFromDropBox(DropboxImageProvider dropboxImageProvider) {
final DropboxImageProvider provider;
showLoadingOverlay();
if (dropboxImageProvider == null) {
provider = DropboxImageProvider.getInstance(/* ... */);
} else {
provider = dropboxImageProvider;
}
handler.post(new Runnable() {
#Override
public void run() {
if (provider.isLoggedIn()) {
provider.requestThumbnails((Activity) context);
} else {
handler.postDelayed(this, 3000L);
}
}
});
}
// ...
}
It might not be the most beautiful solution but it works for me.
What is different between removeDialog() and dismiss() and dismissDialog()? because I'm able to use them together without any problem.
And is it matter when implementing DialogInterface.OnClickListener or AlertDialog.OnClickListener?
I searched a lot but couldn't find anything useful.
EDIT:
I'm developing for Android 2.3.
Example code:
public final class OptionsPreference extends PreferenceActivity implements DialogInterface.OnClickListener
{
private AlertDialog noInternetDialog = null;
//...
#Override
protected void onPause()
{
if (this.noInternetDialog != null)
{
Log.d(LOG_TAG, "Destroying noInternetDialog...");
this.noInternetDialog.dismiss(); // X?
removeDialog(DIALOG_NOINTERNET); // X?
dismissDialog(DIALOG_NOINTERNET); // X?
this.noInternetDialog = null;
}
super.onPause();
}
#Override
protected final Dialog onCreateDialog(final int id)
{
switch (id)
{
case DIALOG_NOINTERNET:
{
final AlertDialog.Builder _builder = new AlertDialog.Builder(this).setIcon(android.R.drawable.ic_dialog_info).setMessage(R.string.str_nointernet);
_builder.setCancelable(false);
_builder.setPositiveButton(R.string.str_wifisettings, this);
_builder.setNeutralButton(R.string.str_ok, this);
this.noInternetDialog = _builder.create();
if (!isFinishing())
{
this.noInternetDialog.show();
}
return this.noInternetDialog;
}
// ...
}
dismissDialog(int id) : Dismisses the dialog with the specified id. It only hides the dialog but still keeps the internal references by the Activity which contains this dialog so that it can be restored in future.Deprecated in API 13.
removeDialog(int id) : It also dismisses the dialog with the specified id. Means it hides that particular dialog and in addition cleans up all the references by the Activity and hence cannot be restored in future. Deprecated in API 13.
dismiss() : This method operates on a particular dialog because it is a method of Dialog class. It also dismisses the dialog. You have to own a valid dialog in order to dismiss it else you'll get exception.