7

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.

8
  • can you provide more details, or better to post full class file and in string file how you are creating string some thing like this <string name="test">test.</string> and in which line you are getting exception Commented May 8, 2020 at 7:13
  • class file and XML string definition added Commented May 8, 2020 at 7:45
  • I have a doubt when you call getString it let's you to set parameters what if you format the string that is returned? I think that would be a valid solution Commented May 8, 2020 at 8:05
  • @Alex Rivas I'm not sure I follow your suggestion but this set of code only generates the error/rejection infrequently...maybe a few hundred times out of millions. But when you say "format the string that is retrurned" are you referring to the result of the getString? Commented May 8, 2020 at 8:17
  • I inherited this code and when I look at the getString of app_name_timestamp there are copies in the strings file for each language...but they are all exactly the same..."%s ・ %s" I could just hard code it. But I'd still like to know what the error means... Commented May 8, 2020 at 8:21

3 Answers 3

6

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.

Sign up to request clarification or add additional context in comments.

Comments

1

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.

Comments

0

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>

1 Comment

It seems with the first suggestion you are thinking there is some timing problem? And as for both of your ideas -- do you know what the message "End of String" means?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.