Android中五大字符串总结(String、StringBuffer、StringBuilder、SpannableString、SpannableStringBuilder)

String、StringBuffer、StringBuilder来自JDK
SpannableString、SpannableStringBuilder来自Android的API

先简单分析一下来自JDK的三个字符串的区别:

String:“字符串常量”(即定义字符串过后,就不能改变对象本身)

StringBuffer : “字符串变量”,线性安全

StringBuilder : “字符串变量”,线性不安全

我们再来分析一下Android中的API的字符串:

SpannableString : “字符串常量”,可与TextView搭配改变显示样式的字符串

SpannableStringBuilder : “字符串变量”,可与TextView搭配改变显示样式的字符串

具体分析:

来一段String的代码:

String str = "Hello World";
str = str+"!";
System.out.print(str);// result : Hello World!

这儿的str对象就改变了,不是说str是“字符串常量”,不是不能改变吗?但是上面说的是不能改变对象本身,这儿str的改变相当于是新建一个字符串对象,然后将新建的字符串对象赋值给str,也就说str已经不再是原来的str了

String与StringBuffer的对比

String str = "Hello " + "World" + "!";
StringBuffer strBuffer= new StringBuffer("Hello ").append("World").append("!");

上面的代码你会发现String的创建速度很快,StringBuffer根本不占什么优势,那是因为String的创建相当于直接是String str = “Hello World!”,如果你改成下面这段代码,你就知道他们巨大的差别了

String str2 = "Hello "
String str3 = "World";
String str4 = "!";
String str1 = str2 +str3 + str4;
StringBuffer strBuffer= new StringBuffer("Hello ");
strBuffer.append("World")
strBuffer.append("!");

这时你会发现String与StringBuffer有很大的创建时间差别,String因为每次都需创建一个字符串对象,它的时间就会比StringBuffer耗时更久!

StringBuffer与StringBuilder的区别在于StringBuffer是线性安全的,StringBuilder是线性不安全的,什么是线性安全?线性安全是当程序中多个线程对同一个字符串操作时,StringBuilder无法保证在同一时刻只有一个线程对字符串操作,而StringBuffer它就能够保证线性安全,当然在耗时上StringBuffer要比StringBuilder耗时更久一点,但平时我们一般都在单线程中操作字符串,所以一般建议我们使用StringBuilder

SpannableString、SpannableStringBuilder和String的对比:

先来张图:

Android中五大字符串总结(String、StringBuffer、StringBuilder、SpannableString、SpannableStringBuilder)_第1张图片

这张图的代码实现并不是通过组合控件的方式实现的,其中只用了TextView,那为什么TextView会实现这么多功能,我们来看看代码:

MainActivity:

public class MainActivity extends AppCompatActivity {

    private TextView mContent_1;
    private TextView mContent_2;
    private TextView mContent_3;
    private TextView mContent_4;
    private TextView mContent_5;
    private TextView mContent_6;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
    }

    private void initView() {
        mContent_1 = (TextView) findViewById(R.id.activity_main_content_1);
        mContent_2 = (TextView) findViewById(R.id.activity_main_content_2);
        mContent_3 = (TextView) findViewById(R.id.activity_main_content_3);
        mContent_4 = (TextView) findViewById(R.id.activity_main_content_4);
        mContent_5 = (TextView) findViewById(R.id.activity_main_content_5);
        mContent_6 = (TextView) findViewById(R.id.activity_main_content_6);
        //设置字体颜色
        SpannableString spannableString = new SpannableString("地心真的有外星人?");
        ForegroundColorSpan colorSpan = new ForegroundColorSpan(Color.parseColor("#0000FF"));
        spannableString.setSpan(colorSpan, 0, 4, Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
        mContent_1.setText(spannableString);
        //设置字体背景颜色
        SpannableStringBuilder stringBuilder = new SpannableStringBuilder("我相信机器人的发展会统治地球!");
        BackgroundColorSpan backgroundColorSpan = new BackgroundColorSpan(Color.parseColor("#FF0000"));
        stringBuilder.setSpan(backgroundColorSpan, 2, 5, Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
        mContent_2.setText(stringBuilder);
        //设置字体的大小
        stringBuilder.append("真的吗?");
        AbsoluteSizeSpan sizeSpan = new AbsoluteSizeSpan(20);
        stringBuilder.setSpan(sizeSpan, 3, 6, Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
        mContent_3.setText(stringBuilder);
        //设置图片代替字体
        ImageSpan imageSpan = new ImageSpan(this, R.mipmap.ic_launcher);
        stringBuilder.setSpan(imageSpan, 3, 6, Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
        mContent_4.setText(stringBuilder);
        //设置点击事件
        ClickableSpan clickableSpan = new ClickableSpan() {
            @Override
            public void onClick(View view) {
                Toast.makeText(MainActivity.this, "不要点我,嘤嘤嘤", Toast.LENGTH_SHORT).show();
            }
        };
        stringBuilder.setSpan(clickableSpan, 0, 1, Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
        mContent_5.setText(stringBuilder);
        //代码中的index为0的字为可点击文本,其他区域不可点击
        mContent_5.setMovementMethod(LinkMovementMethod.getInstance());
        //再写个设置下划线
        spannableString = new SpannableString("你相信有人会一直做某个连续的梦吗?");
        UnderlineSpan underlineSpan = new UnderlineSpan();
        spannableString.setSpan(underlineSpan, 11, 15, Spanned.SPAN_EXCLUSIVE_INCLUSIVE);
        mContent_6.setText(spannableString);
    }
}

activity_main.xml:
(使用了一个ConstraintLayout布局,大家有可能更多的知道他是可以实现手拖控件的布局,但是你也可以自己写它里面的xml属性,并且它的功能比以前的五大布局都厉害, 而且使用它几乎不再需要布局嵌套了,大大节省了手机CPU渲染的时间,大家有时间可以去了解了解)


<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.leezp.xingyun.strtype.MainActivity">

    <TextView
        android:id="@+id/activity_main_content_1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        android:layout_marginTop="20dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/activity_main_content_2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="love is foam"
        android:layout_marginTop="20dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@id/activity_main_content_1"/>

    <TextView
        android:id="@+id/activity_main_content_3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="One's mind settles as still water"
        android:layout_marginTop="20dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@id/activity_main_content_2"/>

    <TextView
        android:id="@+id/activity_main_content_4"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Eat without words and sleep without words"
        android:layout_marginTop="20dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@id/activity_main_content_3"/>

    <TextView
        android:id="@+id/activity_main_content_5"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="When the mountains are high, the mountains are small"
        android:layout_marginTop="20dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@id/activity_main_content_4"/>

    <TextView
        android:id="@+id/activity_main_content_6"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Jungle law"
        android:layout_marginTop="20dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@id/activity_main_content_5"/>


android.support.constraint.ConstraintLayout>

最后听说低版本的Android系统在TextView设置ClickableSpan与OnClickListener时,会出现两个事件会被同时触发,所以这儿给了个参考解决办法

SpannableString与SpannableStringBuilder设置样式的主要的方法:

通过使用setSpan(Object what, int start, int end, int flags)改变文本样式。

对应的参数:

start: 指定Span的开始位置
end: 指定Span的结束位置,并不包括这个位置。
flags:取值有如下四个
Spannable. SPAN_INCLUSIVE_EXCLUSIVE:前面包括,后面不包括,即在文本前插入新的文本会应用该样式,而在文本后插入新文本不会应用该样式
Spannable. SPAN_INCLUSIVE_INCLUSIVE:前面包括,后面包括,即在文本前插入新的文本会应用该样式,而在文本后插入新文本也会应用该样式
Spannable. SPAN_EXCLUSIVE_EXCLUSIVE:前面不包括,后面不包括
Spannable. SPAN_EXCLUSIVE_INCLUSIVE:前面不包括,后面包括
what: 对应的各种Span,不同的Span对应不同的样式。已知的可用类有:
BackgroundColorSpan : 文本背景色
ForegroundColorSpan : 文本颜色
MaskFilterSpan : 修饰效果,如模糊(BlurMaskFilter)浮雕
RasterizerSpan : 光栅效果
StrikethroughSpan : 删除线
SuggestionSpan : 相当于占位符
UnderlineSpan : 下划线
AbsoluteSizeSpan : 文本字体(绝对大小)
DynamicDrawableSpan : 设置图片,基于文本基线或底部对齐。
ImageSpan : 图片
RelativeSizeSpan : 相对大小(文本字体)
ScaleXSpan : 基于x轴缩放
StyleSpan : 字体样式:粗体、斜体等
SubscriptSpan : 下标(数学公式会用到)
SuperscriptSpan : 上标(数学公式会用到)
TextAppearanceSpan : 文本外貌(包括字体、大小、样式和颜色)
TypefaceSpan : 文本字体
URLSpan : 文本超链接
ClickableSpan : 点击事件

参考资料

String、StringBuffer与StringBuilder之间区别
【Android】强大的SpannableStringBuilder
Android项目实战(一): SpannableString与SpannableStringBuilder

你可能感兴趣的:(Android)