Fatal Exception: java.util.UnknownFormatConversionException Conversion = 'End of String'

Viewed 2474

Trying to display in the app information about notifications and occasionally get the error:

Fatal Exception: java.util.UnknownFormatConversionException Conversion = 'End of String'

This is a puzzle but I feel if I can understand what is meant by 'End of String' I'll be on my way. Here is the code that throws the error

class NotificationsListItemViewHolder(
        itemView: View,
        private val appNameAndTime: String,
        private val listener: (NotificationInfo, Int, Boolean, Boolean) -> Unit) : RecyclerView.ViewHolder(itemView) {


    var notificationInfo: NotificationInfo? = null

    fun bind(notification: NotificationInfo) {

        if(isIncludedPackage(notification.packageName))
        {
            applyAlternateTheme(itemView)
        }else {
            applyTheme(itemView)
        }
        notificationInfo = notification

        itemView.apply {
            appNameTime.text = String.format(appNameAndTime, notification.appName, getTimeAgo(System.currentTimeMillis(), notification.timestamp))
            title.text = notification.title
            body.text = notification.bodyText
            if (notification.smallIconPath != null) {
                Glide.with(this).load(notification.smallIconPath).into(appIcon)
                /*
                if (ThemeManager.currentTheme.dark) {
                    appIcon.setColorFilter(Color.WHITE)
                } else {
                    appIcon.setColorFilter(Color.BLACK)
                }

The following line (from above code) is where the Fatal Exception occurs (well, actually within the Java code)

appNameTime.text = String.format(appNameAndTime, notification.appName, getTimeAgo(System.currentTimeMillis(), notification.timestamp))

Here is where the format string is created

<string name="app_name_timestamp" formatted="false">%s ・ %s</string>

...and that XML definition of app_name_timestamp is brought into execution by the following class:

class NotificationsAdapter(
        val data: MutableList<NotificationInfo> = mutableListOf(),
        private val listener: (NotificationInfo, Int, Boolean, Boolean) -> Unit
) : RecyclerView.Adapter<NotificationsListItemViewHolder>() {


    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): NotificationsListItemViewHolder {
        val itemView = LayoutInflater.from(parent.context).inflate(R.layout.view_notification, parent, false)
        return NotificationsListItemViewHolder(itemView, parent.context.resources.getString(R.string.app_name_timestamp)) {notificationInfo, position, longClick, dismiss ->
            listener(notificationInfo, position, longClick, dismiss)
        }
    }

The template for the String.format is the first parameter (passed into the function in as appNameAndTime) is always: "%s ・ %s" and except for some rare crashes is meant to format the other two parameters to look like this when displayed: "Twitter ・ 20m"

Again, I'm trying to decipher the error. I've done various tests like hard coding empty strings in the second and third parameters but nothing so far has produced the same error.

As an answer I'd accept -- "here's where you can get specific information about this exception". A pointer on where to look.

2 Answers

I found the answer to this and it is totally developer error (but there is something to be learned here). A short explanation: in Android you have multiple string xml files for each language -- and in one of them the string "%s ・ %s" was broken in the translation process and became "%s ・ %" -- so in the field the app would only show this error for the affected translations. The learning is that in the String.format if you don't have a matching number of string templates then you get the "End of string" exception.

it seems appNameAndTime string you are not initialising. you have to do something like

appNameAndTime = getString(R.string.app_name_timestamp)

and try this also by removing formatted attribute from this string

<string name="app_name_timestamp" formatted="false">%s ・ %s</string>
Related