Joel Butler
Joel Butler

Reputation: 280

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

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.

Upvotes: 6

Views: 6312

Answers (3)

M.Ed
M.Ed

Reputation: 1348

This issue was caused due to incorrect formatting in non-Latin languages (especially languages like Arabic or Hebrew that start from left to right).

The IDE might incorrectly display %s as s%, so you might be actually seeing s% due to the IDE encoding when in reality it's s% which is causing this crash.

Using String format:

binding.reconnectionAttempt?.text = String.format(getString(R.string.reconnecting), remainingTries)

English locale strings.xml file:

<string name="reconnecting">Reconnecting ... %s</string>

Arabic locale string.xml file with faulty string formatting (again, due to the IDE's text encoding it might show as %s when in reality it's s%):

<string name="reconnecting">معاودة المحاولة ...s%</string>

So I changed the Arabic locale string.xml file to this and it was resolved:

<string name="reconnecting">معاودة المحاولة ... %s</string>

Try copy-pasting the string to other text editors or websites to make sure that you're actually using %s and not s%. Don't trust what shows up on your IDE.

Upvotes: 0

Joel Butler
Joel Butler

Reputation: 280

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.

Upvotes: 6

Avinash Jadaun
Avinash Jadaun

Reputation: 1912

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>

Upvotes: 0

Related Questions