DatePicker se bloquea en mi dispositivo cuando se hace clic (con una aplicación personal)
Edit: Comprobé que el problema sólo aparece cuando el teléfono está configurado con el idioma "francés".
Actualmente estoy creando mi propia aplicación y tengo un problema al usar el widget DatePicker en mi teléfono (teléfono con modo de depuración: Samsung S5).
- ¿Cómo resolver el mensaje "Esperando el depurador"?
- ¿Cómo en realidad BOND un dispositivo?
- Android Studio: ¿qué está causando los logs de la fuente de alimentación de la batería logcat?
- Android: Configuración de AVD para Galaxy S3-Like AVD
- Diferencia entre las API de destino de Google y el objetivo de Android
El error recopilado es: java.util.IllegalFormatConversionException
Añado más detalles sobre el problema reunido en logcat:
02-20 10:37:18.255 13029-13029/avappmobile.mytasks E/AndroidRuntime﹕ FATAL EXCEPTION: main Process: avappmobile.mytasks, PID: 13029 java.util.IllegalFormatConversionException: %d can't format java.lang.String arguments at java.util.Formatter.badArgumentType(Formatter.java:1489) at java.util.Formatter.transformFromInteger(Formatter.java:1689) at java.util.Formatter.transform(Formatter.java:1461) at java.util.Formatter.doFormat(Formatter.java:1081) at java.util.Formatter.format(Formatter.java:1042) at java.util.Formatter.format(Formatter.java:1011) at java.lang.String.format(String.java:1803) at android.content.res.Resources.getString(Resources.java:1453) at android.content.Context.getString(Context.java:397) at android.widget.SimpleMonthView$MonthViewTouchHelper.getItemDescription(SimpleMonthView.java:684) at android.widget.SimpleMonthView$MonthViewTouchHelper.onPopulateNodeForVirtualView(SimpleMonthView.java:628) at com.android.internal.widget.ExploreByTouchHelper.createNodeForChild(ExploreByTouchHelper.java:377) at com.android.internal.widget.ExploreByTouchHelper.createNode(ExploreByTouchHelper.java:316) at com.android.internal.widget.ExploreByTouchHelper.access$100(ExploreByTouchHelper.java:50) at com.android.internal.widget.ExploreByTouchHelper$ExploreByTouchNodeProvider.createAccessibilityNodeInfo(ExploreByTouchHelper.java:711) at android.view.AccessibilityInteractionController$AccessibilityNodePrefetcher.prefetchDescendantsOfVirtualNode(AccessibilityInteractionController.java:1179) at android.view.AccessibilityInteractionController$AccessibilityNodePrefetcher.prefetchDescendantsOfRealNode(AccessibilityInteractionController.java:1091) at android.view.AccessibilityInteractionController$AccessibilityNodePrefetcher.prefetchDescendantsOfRealNode(AccessibilityInteractionController.java:1087) at android.view.AccessibilityInteractionController$AccessibilityNodePrefetcher.prefetchDescendantsOfRealNode(AccessibilityInteractionController.java:1087) at android.view.AccessibilityInteractionController$AccessibilityNodePrefetcher.prefetchDescendantsOfRealNode(AccessibilityInteractionController.java:1087) at android.view.AccessibilityInteractionController$AccessibilityNodePrefetcher.prefetchDescendantsOfRealNode(AccessibilityInteractionController.java:1087) at android.view.AccessibilityInteractionController$AccessibilityNodePrefetcher.prefetchDescendantsOfRealNode(AccessibilityInteractionController.java:1087) at android.view.AccessibilityInteractionController$AccessibilityNodePrefetcher.prefetchDescendantsOfRealNode(AccessibilityInteractionController.java:1087) at android.view.AccessibilityInteractionController$AccessibilityNodePrefetcher.prefetchDescendantsOfRealNode(AccessibilityInteractionController.java:1087) at android.view.AccessibilityInteractionController$AccessibilityNodePrefetcher.prefetchDescendantsOfRealNode(AccessibilityInteractionController.java:1087) at android.view.AccessibilityInteractionController$AccessibilityNodePrefetcher.prefetchDescendantsOfRealNode(AccessibilityInteractionController.java:1087) at android.view.AccessibilityInteractionController$AccessibilityNodePrefetcher.prefetchAccessibilityNodeInfos(AccessibilityInteractionController.java:888) at android.view.AccessibilityInteractionController.findAccessibilityNodeInfoByAccessibilityIdUiThread(AccessibilityInteractionController.java:155) at android.view.AccessibilityInteractionController.access$400(AccessibilityInteractionController.java:53) at android.view.AccessibilityInteractionController$PrivateHandler.handleMessage(AccessibilityInteractionController.java:1236) at android.os.Handler.dispatchMessage(Handler.java:102) at android.os.Looper.loop(Looper.java:145) at android.app.ActivityThread.main(ActivityThread.java:5834) at java.lang.reflect.Method.invoke(Native Method) at java.lang.reflect.Method.invoke(Method.java:372) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1388) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1183)
Aquí está mi código DialogFragment:
public class DatePFragment extends DialogFragment implements DatePickerDialog.OnDateSetListener { DatePicker dp; OnDatePickedListener mCallback; Integer mLayoutId = null; // Interface definition public interface OnDatePickedListener { public void onDatePicked(int textId, int year, int month, int day); } // make sure the Activity implement the OnDatePickedListener public void onAttach(Activity activity) { super.onAttach(activity); try { mCallback = (OnDatePickedListener)activity; } catch (final ClassCastException e) { throw new ClassCastException(activity.toString() + " must implement OnDatePickedListener"); } } @Override public Dialog onCreateDialog(Bundle savedInstanceState){ mCallback = (OnDatePickedListener)getActivity(); Calendar cal = Calendar.getInstance(); Bundle bundle = this.getArguments(); mLayoutId = bundle.getInt("layoutId"); int year = cal.get(Calendar.YEAR); int month = cal.get(Calendar.MONTH); int day = cal.get(Calendar.DAY_OF_MONTH); View view = getActivity().getLayoutInflater().inflate(R.layout.datepfragment, null); dp = (DatePicker) view.findViewById(R.id.datePicker); // Create a new instance of DatePickerDialog and return it return new DatePickerDialog(getActivity(),this,year, month, day); } @Override public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth) { if (mCallback != null) { // Use the date chosen by the user. mCallback.onDatePicked(mLayoutId, year, monthOfYear+1, dayOfMonth); } } }
Y aquí está el diseño xml asociado:
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/txtDPTitle" android:id="@+id/txtDPTitle" android:layout_gravity="center_horizontal" android:gravity="center" android:layout_alignParentTop="true" android:layout_alignParentStart="true" android:layout_marginTop="35dp" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/btnDPValidate" android:id="@+id/btnDPValidate" android:layout_alignParentBottom="true" android:layout_centerHorizontal="true" android:layout_marginBottom="35dp" /> <DatePicker android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/datePicker" android:layout_gravity="center_horizontal" android:layout_marginLeft="0dp" android:datePickerMode="spinner" android:calendarViewShown="false" android:layout_centerVertical="true" android:layout_centerHorizontal="true" /> </RelativeLayout>
El hecho es que tenía dos tipos de problemas (que conducen a la caída de la aplicación de todos modos):
- Cuando entro mi aplicación y veo directamente al widget de DatePicker, el calendario se muestra correctamente y tan pronto como selecciono un día (digo un día, porque no hay ningún problema cambiando el año por ejemplo), la aplicación se bloquea.
- Si voy en otra función el clic para mostrar el DatePicker, se bloquea directamente.
Vi otros hilos como: DatePicker accidente en samsung con android 5.0
En este hilo no obtengo suficiente información, ya que la solución dada permite mostrar sólo la vista de hilandero del calendario y además el hilador mostrado no está centrado y presentado como el mío (puesto directamente en la parte superior de la pantalla).
Si necesita más detalles por favor pregúnteme.
Gracias. Alex.
- Cordova no instala realmente la aplicación en el dispositivo Android
- JNetPcap en Android: problema con el método findAllDevs!
- ¿Restringir las ventas de una aplicación por dispositivos específicos?
- Dispositivo Android de ADB no autorizado
- ¿Cómo conectar el dispositivo a Eclipse?
- ¿Hay alguna solución para Android studio mantener desconectar el dispositivo de prueba en Macbook Pro?
- Desarrollo de controladores de dispositivos Android - Punto de entrada
- Google Nexus 5 no se detecta por computadora / no aparece en el administrador de dispositivos
Es un fallo de Samsung en su implementación de Lollipop UI. Afecta a Galaxy S4, S5, Nota 3 y probablemente más dispositivos. Para nosotros ocurre en los lenguajes de_DE y de_AT, pero parece ser un problema que afecta a varios idiomas.
Lo arreglé forzando a los dispositivos Samsung a usar el tema Holo para el selector de fechas. En nuestro DatePickerFragment:
@NonNull @Override public Dialog onCreateDialog(Bundle savedInstanceState) { /* calendar code here */ Context context = getActivity(); if (isBrokenSamsungDevice()) { context = new ContextThemeWrapper(getActivity(), android.R.style.Theme_Holo_Light_Dialog); } return new DatePickerDialog(context, this, year, month, day); } private static boolean isBrokenSamsungDevice() { return (Build.MANUFACTURER.equalsIgnoreCase("samsung") && isBetweenAndroidVersions( Build.VERSION_CODES.LOLLIPOP, Build.VERSION_CODES.LOLLIPOP_MR1)); } private static boolean isBetweenAndroidVersions(int min, int max) { return Build.VERSION.SDK_INT >= min && Build.VERSION.SDK_INT <= max; }
Gracias a Samsung, sus usuarios no obtendrán el selector de fechas diseñado por el material.
Tengo un FIX PATCH posible que permitirá al usuario seguir usando la librería Lollipop.
Sólo podía reproducir el bloqueo al permitir TalkBack en un S4 con Android 5.0.1 francés, parece que Samsung está pasando toda la fecha a la cadena de selección de elementos utilizados para accesibilidad en lugar del número de día.
Basándonos en la solución @mreichelt de envolver el contexto, podemos anular la función getString (id, args) y realmente solucionar el problema.
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; } };
Por lo tanto, si proporcionamos este contexto al constructor DatePickerDialog, se solucionará el problema.
UPDATE: Este problema también aparece en webview cuando las páginas contienen campos de entrada de fecha, la mejor manera que encontré que resolver ambos problemas (diálogo y webview) es anular la función de getResources de actividad como este:
@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); } } }; }
Nota: La solución incluye recursos almacenados en caché, lo que significa que si tiene eventos en la aplicación que cambian los recursos (como el cambio de idioma) que necesite para actualizar los recursos almacenados en caché.
Encuentro una solución, jugando con las variables de configuración y de la configuración regional.
Solo modifico el idioma si detecto que es un idioma francés ("fr") y lo reemplazo con un idioma inglés ("en"), luego vuelvo a ponerlo en normal una vez fuera del 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)); }
Y una vez que salgo
@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); }
Olvídate del selector de fechas incorporado. IMHO conmutación de la configuración regional no es una solución, porque quiero tener el selector en la configuración actual. Sólo hay una manera de deshacerse del accidente: utilice una biblioteca que proporcione una implementación independiente.
Para un fragmento de selector de fechas: https://github.com/flavienlaurent/datetimepicker
Para un widget selector de fechas: https://github.com/SingleCycleKing/CustomTimePicker (esto es más un punto de partida que una solución lista para usar)
Observé un problema menor con la solución de @mreichelt. El diálogo se mostró sin que el título mostrara la fecha seleccionada (incluido el día de la semana). Definir explícitamente el título, e inmediatamente ajustar la fecha de nuevo resuelto ese problema para mí.
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;
Basado en mreichelts respuesta he creado un SupportDatePickerDialog.java que envuelve aroudn DatePickerDialog
y corrige automáticamente el contexto de android 5.0 y 5.1.
Ver el esencial
- ViewPager FragmentPagerAdapter Nullpointer
- ¿Puedo probar las notificaciones de la barra de estado utilizando el marco de pruebas de Android?