Skip to content

Instantly share code, notes, and snippets.

@wakwak3125
Last active November 14, 2016 15:34
Show Gist options
  • Save wakwak3125/96e1992ee2a68b9b91af66b5695461b9 to your computer and use it in GitHub Desktop.
Save wakwak3125/96e1992ee2a68b9b91af66b5695461b9 to your computer and use it in GitHub Desktop.
LocaleListのコードを読んでみました。 m_android_fcr 2016_11_10

LocaleList読むぞ

LocaleListのコンストラクタを見てみます。

  • LocaleList(Locale...)で同じLocaleいれるとIAEでおちる。
    • たとえばLocale.JAPANEとLocale.JAPANとか。
    • Locale.JAPANとLocale.JAPANESEなら落ちない。これで大丈夫なんかな…?
/**
151     * Creates a new {@link LocaleList}.
152     *
153     * <p>For empty lists of {@link Locale} items it is better to use {@link #getEmptyLocaleList()},
154     * which returns a pre-constructed empty list.</p>
155     *
156     * @throws NullPointerException if any of the input locales is <code>null</code>.
157     * @throws IllegalArgumentException if any of the input locales repeat.
158     */
159    public LocaleList(@NonNull Locale... list) {
160        if (list.length == 0) {
161            mList = sEmptyList;
162            mStringRepresentation = "";
163        } else {
164            final Locale[] localeList = new Locale[list.length];
165            final HashSet<Locale> seenLocales = new HashSet<Locale>();
166            final StringBuilder sb = new StringBuilder();
167            for (int i = 0; i < list.length; i++) {
168                final Locale l = list[i];
169                if (l == null) {
170                    throw new NullPointerException("list[" + i + "] is null");
171                } else if (seenLocales.contains(l)) {
172                    throw new IllegalArgumentException("list[" + i + "] is a repetition");
173                } else {
174                    final Locale localeClone = (Locale) l.clone();
175                    localeList[i] = localeClone;
176                    sb.append(localeClone.toLanguageTag());
177                    if (i < list.length - 1) {
178                        sb.append(',');
179                    }
180                    seenLocales.add(localeClone);
181                }
182            }
183            mList = localeList;
184            mStringRepresentation = sb.toString();
185        }
186    }

これで、重複するLanguageTagならどうなんだろう?

  • IllegalArgumentExceptionでました。そりゃそうですよね。
/**
259     * Generates a new LocaleList with the given language tags.
260     *
261     * @param list The language tags to be included as a single {@link String} separated by commas.
262     * @return A new instance with the {@link Locale} items identified by the given tags.
263     */
264    @NonNull
265    public static LocaleList forLanguageTags(@Nullable String list) {
266        if (list == null || list.equals("")) {
267            return getEmptyLocaleList();
268        } else {
269            final String[] tags = list.split(",");
270            final Locale[] localeArray = new Locale[tags.length];
271            for (int i = 0; i < localeArray.length; i++) {
272                localeArray[i] = Locale.forLanguageTag(tags[i]);
273            }
274            return new LocaleList(localeArray);
275        }
276    }

LocaleList、じゃあだれがどんなふうに使ってるんでしょうか

  • ぱっと目についたTextViewが使っていましたので、一旦TextViewがどんなふうに使ってるかサクッと読んでみます。

TextView(1/2)

  • いま表示されているTextViewからLocaleListを取得したり
2877    /**
2878     * Get the default {@link LocaleList} of the text in this TextView.
2879     * @return the default {@link LocaleList} of the text in this TextView.
2880     */
2881    @NonNull @Size(min=1)
2882    public LocaleList getTextLocales() {
2883        return mTextPaint.getTextLocales();
2884    }

TextView(2/2)

  • TextViewに対して、Drawする際のLocaleListを指定できたりする模様。
  • PaintクラスでもsetTextLocalesを読んでいるので、そちらにまで行ってみます。
/**
2905     * Set the default {@link LocaleList} of the text in this TextView to the given value.
2906     *
2907     * This value is used to choose appropriate typefaces for ambiguous characters (typically used
2908     * for CJK locales to disambiguate Hanzi/Kanji/Hanja characters). It also affects
2909     * other aspects of text display, including line breaking.
2910     *
2911     * @param locales the {@link LocaleList} for drawing text, must not be null or empty.
2912     *
2913     * @see Paint#setTextLocales
2914     */
2915    public void setTextLocales(@NonNull @Size(min=1) LocaleList locales) {
2916        mLocalesChanged = true;
2917        mTextPaint.setTextLocales(locales);
2918        if (mLayout != null) {
2919            nullLayouts();
2920            requestLayout();
2921            invalidate();
2922        }
2923    }
2924
2925    @Override
2926    protected void onConfigurationChanged(Configuration newConfig) {
2927        super.onConfigurationChanged(newConfig);
2928        if (!mLocalesChanged) {
2929            mTextPaint.setTextLocales(LocaleList.getDefault());
2930            if (mLayout != null) {
2931                nullLayouts();
2932                requestLayout();
2933                invalidate();
2934            }
2935        }
2936    }
2937

Paint

  • LocaleListに中国語が含まれていたら、中華フォントでレンダリングすると。
  • 日本語が含まれていたら、日本語でレンダリングすると。
  • どっちもあったらその順番でどっちのフォントでレンダリングするか決めると。
/**
1331     * Set the text locale list.
1332     *
1333     * The text locale list affects how the text is drawn for some languages.
1334     *
1335     * For example, if the locale list contains {@link Locale#CHINESE} or {@link Locale#CHINA},
1336     * then the text renderer will prefer to draw text using a Chinese font. Likewise,
1337     * if the locale list contains {@link Locale#JAPANESE} or {@link Locale#JAPAN}, then the text
1338     * renderer will prefer to draw text using a Japanese font. If the locale list contains both,
1339     * the order those locales appear in the list is considered for deciding the font.
1340     *
1341     * This distinction is important because Chinese and Japanese text both use many
1342     * of the same Unicode code points but their appearance is subtly different for
1343     * each language.
1344     *
1345     * By default, the text locale list is initialized to a one-member list just containing the
1346     * system locales. This assumes that the text to be rendered will most likely be in the user's
1347     * preferred language.
1348     *
1349     * If the actual language or languages of the text is/are known, then they can be provided to
1350     * the text renderer using this method. The text renderer may attempt to guess the
1351     * language script based on the contents of the text to be drawn independent of
1352     * the text locale here. Specifying the text locales just helps it do a better
1353     * job in certain ambiguous cases.
1354     *
1355     * @param locales the paint's locale list for drawing text, must not be null or empty.
1356     */
1357    public void setTextLocales(@NonNull @Size(min=1) LocaleList locales) {
1358        if (locales == null || locales.isEmpty()) {
1359            throw new IllegalArgumentException("locales cannot be null or empty");
1360        }
1361        if (locales.equals(mLocales)) return;
1362        mLocales = locales;
1363        syncTextLocalesWithMinikin();
1364    }
1365
1366    private void syncTextLocalesWithMinikin() {
1367        final String languageTags = mLocales.toLanguageTags();
1368        final Integer minikinLangListId;
1369        synchronized (sCacheLock) {
1370            minikinLangListId = sMinikinLangListIdCache.get(languageTags);
1371            if (minikinLangListId == null) {
1372                final int newID = nSetTextLocales(mNativePaint, languageTags);
1373                sMinikinLangListIdCache.put(languageTags, newID);
1374                return;
1375            }
1376        }
1377        nSetTextLocalesByMinikinLangListId(mNativePaint, minikinLangListId.intValue());
1378    }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment