简体   繁体   English

如何获取与TextView关联的字符串资源的ID?

[英]How to get the id of a string resource associated with a TextView?

I can access the TextView instance, get it's resource ID and get it's resource name via getResources().getResourceEntryName() , but I can't seem to find a way to get the id of the string associated with it. 我可以访问TextView实例,获取它的资源ID并通过getResources().getResourceEntryName()获得它的资源名称,但是我似乎找不到找到与之关联的字符串ID的方法。

How can I dynamically get the id of the string resource associated with a TextView ? 如何动态获取与TextView关联的字符串资源的ID?

You can't. 你不能 A TextView doesn't store the id of the String resources if you call setText(int resid) . 如果调用setText(int resid)TextView不会存储String资源的ID。 All this overloaded method does is get the String from the resources and call the setText(CharSequence text) method. 所有这些重载方法所做的就是从资源中获取String并调用setText(CharSequence text)方法。

The only workaround I could was to match the +id of the TextView instances in the layout xml with the name of the string, then use Resources to get pair the two: 我唯一的解决方法是将布局xml中TextView实例的+id与字符串name进行匹配,然后使用Resources将两者配对:

/**
     * finds a string id matching a text view id name and returns the value
     * @param textView - text view
     * @param context  - the context
     * @param locale   - the locale string
     * @return  String - resource string if found, empty string otherwise
     */
    public  static String getTextViewStringFromResources(TextView textView,Context context,String locale){
        String result = "";
        final int textViewID = textView.getId();

        if(textViewID <= 0){
            Log.e(TAG,"invalid id for textView " + textView + " text = " + textView.getText());
            result = textView.getText().toString();
            return result;
        }
        //get resources (re-usable)
        final Resources resources = getLocalizedResources(context,locale);
        // get textViews id
        final String entryName = resources.getResourceEntryName(textView.getId());
        // get the string id !! must match the textview id !!
        final int stringID = resources.getIdentifier(entryName,"string",context.getPackageName());
        //return string value for string id found by textview id
        try{
            result = resources.getString(stringID);
        }catch (Resources.NotFoundException e){
            Log.e(TAG,"couldn't find a string id for " + entryName);
            Log.e(TAG,e.getMessage());
        }
        return result;
    }

//!! requires minSDK 17
    @NonNull
    public static Resources getLocalizedResources(Context context, String locale) {
        Locale desiredLocale = new Locale(locale);
        Configuration conf = context.getResources().getConfiguration();
        conf.setLocale(desiredLocale);
        Context localizedContext = context.createConfigurationContext(conf);
        return localizedContext.getResources();
    }

The swapping is partially based on Gunhan Sancar's method of swapping text field. 交换部分基于Gunhan Sancar的交换文本字段的方法

This works but it pretty much a hack. 这行得通,但几乎是个hack。

Eventually I needed to also change the Google Handwriting Input language programmatically and for that Juuso's ADB Change Language app came in super handy. 最终,我还需要以编程方式更改Google手写输入语言,因此Juuso的ADB更改语言应用程序非常方便。

For reference, here's a function using Juuso's approach: 作为参考,这是一个使用Juuso方法的函数:

final String TAG = "ChangeLanguage"
//change language utils "kindly borrowed" from net.sanapeli.adbchangelanguage: brilliant little app!

    /**
     * updates a Configuration with a list of Locales
     * @param configuration - a configuration to updated
     * @param arrayList - an ArrayList of Locale instances
     * @return the updated configuration
     */
    @TargetApi(24)
    public static Configuration addLocalesToConfiguration(Configuration configuration, ArrayList<Locale> arrayList) {
        configuration.setLocales(new LocaleList((Locale[]) arrayList.toArray(new Locale[arrayList.size()])));
        return configuration;
    }

    /**
     * Change the system language
     * @param lanaguageList - a list of Locale instances to change to
     */
    public static void changeLanguages(ArrayList<Locale> lanaguageList){
        try {
            Class cls = Class.forName("android.app.ActivityManagerNative");
            Method method = cls.getMethod("getDefault", new Class[0]);
            method.setAccessible(true);
            Object invoke = method.invoke(cls, new Object[0]);
            method = cls.getMethod("getConfiguration", new Class[0]);
            method.setAccessible(true);
            Configuration configuration = (Configuration) method.invoke(invoke, new Object[0]);
            configuration.getClass().getField("userSetLocale").setBoolean(configuration, true);
            if (VERSION.SDK_INT >= 24) {
                configuration = addLocalesToConfiguration(configuration, lanaguageList);
            } else {
                configuration.locale = (Locale) lanaguageList.get(0);
            }
            Method method2 = cls.getMethod("updateConfiguration", new Class[]{Configuration.class});
            method2.setAccessible(true);
            method2.invoke(invoke, new Object[]{configuration});
            Log.d(TAG,"locale updated to" + lanaguageList.get(0).toString());
        } catch (Exception e) {
            Log.e(TAG,"error changing locale (double check you're granted permissions to the app first: pm grant your.app.package.here android.permission.CHANGE_CONFIGURATION )");
            e.printStackTrace();
        }
    }

Remember to grant CHANGE_CONFIGURATION to your app. 请记住将CHANGE_CONFIGURATION授予您的应用。

This is tested with Android 7.1.1 but bare in mind that it will fail on Android 8.0 (and potentially upwards) as getConfiguration is not found (the API is different) under certain build conditions. 这已在Android 7.1.1上进行了测试,但是请记住,由于在某些构建条件下未找到getConfiguration (API不同),因此它将在Android 8.0(或更高版本)上失败。

The method expects an ArrayList of Locale objects with the language you want to change to on top: eg 该方法期望使用您要更改为顶部语言的Locale对象的ArrayList:例如

ArrayList<Locale> fr = new ArrayList<Locale>();
fr.add(new Locale("fr"));
fr.add(new Locale("en"));

ArrayList<Locale> en = new ArrayList<Locale>();
en.add(new Locale("en"));
en.add(new Locale("fr"));

Make sure the Languages are installed on the devices as well. 确保在设备上也安装了语言。

If you have other improvement suggestions I'd be more than happy to update the answer 如果您还有其他改进建议,我很乐意更新答案

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM