DatePicker crashes on my device when clicked (with personal app)

前端 未结 7 2007
长发绾君心
长发绾君心 2020-12-12 13:46

Edit : I checked that the issue only appears when the phone is set with \"French\" language.

I\'m currently building my own app and I have an issue

相关标签:
7条回答
  • 2020-12-12 14:21

    this also happens when you programatically define a min date further than the max date

    datePicker.getDatePicker().setMaxDate(15000000);
    
    datePicker.getDatePicker().setMinDate(16000000);
    
    0 讨论(0)
  • 2020-12-12 14:25

    Forget about the built-in date picker. IMHO switching the locale is not a solution, because I want to have the picker in the current locale. There's only one way to get rid of the crash: use a library that provides an independent implementation.

    For a date picker fragment: https://github.com/flavienlaurent/datetimepicker

    For a date picker widget: https://github.com/SingleCycleKing/CustomTimePicker (this is more a starting point than a ready-to-use-solution)

    0 讨论(0)
  • 2020-12-12 14:34

    I have a possible FIX PATCH that will actually let the user continue using the Lollipop library.

    I could only reproduce the crash by enabling TalkBack on an S4 with Android 5.0.1 French, it seems that Samsung is passing the entire date to the item selection string used for accessability instead of the day number.

    Building on @mreichelt solution of wrapping the context we can override the getString(id,args) function and actually fix the issue.

    context = new ContextWrapper(getActivity()) {
    
        private Resources wrappedResources;
    
        @Override
        public Resources getResources() {
            Resources r = super.getResources();
            if(wrappedResources == null) {
                wrappedResources = new Resources(r.getAssets(), r.getDisplayMetrics(), r.getConfiguration()) {
                    @NonNull
                    @Override
                    public String getString(int id, Object... formatArgs) throws NotFoundException {
                        try {
                            return super.getString(id, formatArgs);
                        } catch (IllegalFormatConversionException ifce) {
                            Log.e("DatePickerDialogFix", "IllegalFormatConversionException Fixed!", ifce);
                            String template = super.getString(id);
                            template = template.replaceAll("%" + ifce.getConversion(), "%s");
                            return String.format(getConfiguration().locale, template, formatArgs);
                        }
                    }
                };
            }
            return wrappedResources;
        }
    };
    

    So if we provide this context to the DatePickerDialog constructor, it will fix the issue.

    UPDATE: This issue also appears in webview when pages contain date input fields, the best way I found that solve both issues (dialog and webview) is to override the Activity getResources function like this:

    @Override
    public Resources getResources() {
        if (wrappedResources == null) {
            wrappedResources = wrapResourcesFixDateDialogCrash(super.getResources());
        }
        return wrappedResources;
    }
    
    public Resources wrapResourcesFixDateDialogCrash(Resources r) {
        return new Resources(r.getAssets(), r.getDisplayMetrics(), r.getConfiguration()) {
            @NonNull
            @Override
            public String getString(int id, Object... formatArgs) throws NotFoundException {
                try {
                    return super.getString(id, formatArgs);
                } catch (IllegalFormatConversionException ifce) {
                    Log.i("DatePickerDialogFix", "IllegalFormatConversionException Fixed!", ifce);
                    String template = super.getString(id);
                    template = template.replaceAll("%" + ifce.getConversion(), "%s");
                    return String.format(getConfiguration().locale, template, formatArgs);
                }
            }
        };
    }
    

    Note: The solution includes a cached resources - which means if you have events in the app changing the resources (like language change) than you might need to update the cached resources.

    0 讨论(0)
  • 2020-12-12 14:35

    I find a workaround, playing with configuration and Locale variables.

    I juste modify the language if I detect it's a french ("fr") language and replace it with an english ("en") language, then put back to normal once out of the DatePicker DialogFragment.

    public void showDatePickerDialog(int layoutId) {
            Integer year = cal.get(Calendar.YEAR);
            Integer month = cal.get(Calendar.MONTH);
            Integer day = cal.get(Calendar.DAY_OF_MONTH);
    
            // Due to an issue with DatePicker and fr language (locale), if locale language is french, this is changed to us to make the DatePicker working
            if(Locale.getDefault().getLanguage().toString().equals(FR_LANG_CONTEXT)){
                Configuration config = new Configuration();
                config.locale = new Locale(US_LANG_CONTEXT);
                getApplicationContext().getResources().updateConfiguration(config, null);
            }
    
            Bundle bundle = createDatePickerBundle(layoutId, year, month, day);
            DialogFragment newFragment = new DatePFragment();
            newFragment.setArguments(bundle);
            newFragment.show(fm, Integer.toString(layoutId));
        }
    

    And once I'm out

    @Override
        public void onDatePicked(int LayoutId, int year, int month, int day){
            // Once out from the DatePicker, if we were working on a fr language, we update back the configuration with fr language.
            if(Locale.getDefault().getLanguage().toString().equals(FR_LANG_CONTEXT)){
                Configuration config = new Configuration();
                config.locale = new Locale(FR_LANG_CONTEXT);
                getApplicationContext().getResources().updateConfiguration(config, null);
            }
    
            String date = day + "/" + month + "/" + year;
            txtTaskDate.setText(date);
        }
    
    0 讨论(0)
  • 2020-12-12 14:35

    Based on mreichelts answer I created a SupportDatePickerDialog.java which wraps aroudn DatePickerDialog and automatically fixes the context for android 5.0 and 5.1.

    See gist

    0 讨论(0)
  • 2020-12-12 14:38

    I observed one minor problem with @mreichelt's solution. The dialog was rendered without the title showing the currently selected date (including the day of the week). Explicitly setting the title, and immediately setting the date again solved that problem for me.

    Context context = getActivity();
    if (isBrokenSamsungDevice()) {
        context = new ContextThemeWrapper(getActivity(), android.R.style.Theme_Holo_Light_Dialog);
    }
    DatePickerDialog datePickerDialog = new DatePickerDialog(context, this, year, month, day);
    if (isBrokenSamsungDevice()) {
        datePickerDialog.setTitle("");
        datePickerDialog.updateDate(year, month, day);
    }
    return datePickerDialog;
    
    0 讨论(0)
提交回复
热议问题