Created
December 29, 2014 16:09
-
-
Save slightfoot/fce61d28cdf4eb7042f7 to your computer and use it in GitHub Desktop.
Example of reusing spannables.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.example.test; | |
import java.util.ArrayList; | |
import java.util.EmptyStackException; | |
import java.util.HashMap; | |
import java.util.Random; | |
import java.util.Stack; | |
import android.content.Context; | |
import android.graphics.Typeface; | |
import android.os.Bundle; | |
import android.support.v7.app.ActionBarActivity; | |
import android.text.SpannableString; | |
import android.text.Spanned; | |
import android.text.style.StyleSpan; | |
import android.util.AttributeSet; | |
import android.view.Gravity; | |
import android.view.View; | |
import android.view.ViewGroup; | |
import android.widget.BaseAdapter; | |
import android.widget.ListView; | |
import android.widget.TextView; | |
public class SpanReuseExampleActivity extends ActionBarActivity | |
{ | |
@Override | |
protected void onCreate(Bundle savedInstanceState) | |
{ | |
super.onCreate(savedInstanceState); | |
Random rand = new Random(); | |
ArrayList<Message> data = new ArrayList<Message>(500); | |
for(int i = 0; i < 500; i++){ | |
Message item = new Message(); | |
item.message = "This is the " + (i + 1) + " test message to be displayed."; | |
final int len = item.message.length(); | |
item.start = rand.nextInt(len); | |
item.end = item.start + rand.nextInt(len - item.start); | |
data.add(item); | |
} | |
ListView listView = new ListView(this); | |
listView.setAdapter(new MessageAdapter(this, data)); | |
setContentView(listView); | |
} | |
public static class Message | |
{ | |
public String message; | |
public int start; | |
public int end; | |
} | |
public static class BoldSpan extends StyleSpan | |
{ | |
public BoldSpan() | |
{ | |
super(Typeface.BOLD); | |
} | |
} | |
public static class MessageAdapter extends BaseAdapter | |
{ | |
private ArrayList<Message> mData; | |
public MessageAdapter(Context context, ArrayList<Message> data) | |
{ | |
mData = data; | |
} | |
@Override | |
public View getView(int position, View convertView, ViewGroup parent) | |
{ | |
SpanReuseTextView view; | |
if(convertView == null){ | |
final Context context = parent.getContext(); | |
view = new SpanReuseTextView(context); | |
view.setMinimumHeight((int)(48.0f * context.getResources() | |
.getDisplayMetrics().density)); | |
view.setTextAppearance(context, android.R.style.TextAppearance); | |
view.setGravity(Gravity.CENTER); | |
} | |
else{ | |
view = (SpanReuseTextView)convertView; | |
} | |
final Message item = mData.get(position); | |
SpannableString spannable = new SpannableString(item.message); | |
spannable.setSpan(SpanReuseCache.getInstance().get(BoldSpan.class), | |
item.start, item.end, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); | |
view.setText(spannable); | |
return view; | |
} | |
@Override | |
public Message getItem(int position) | |
{ | |
return mData.get(position); | |
} | |
@Override | |
public long getItemId(int position) | |
{ | |
return position; | |
} | |
@Override | |
public boolean hasStableIds() | |
{ | |
return true; | |
} | |
@Override | |
public int getCount() | |
{ | |
return mData.size(); | |
} | |
} | |
public static class SpanReuseTextView extends TextView | |
{ | |
public SpanReuseTextView(Context context) | |
{ | |
this(context, null); | |
} | |
public SpanReuseTextView(Context context, AttributeSet attrs) | |
{ | |
this(context, attrs, android.R.attr.textViewStyle); | |
} | |
public SpanReuseTextView(Context context, AttributeSet attrs, int defStyleAttr) | |
{ | |
super(context, attrs, defStyleAttr); | |
} | |
@Override | |
public void setText(CharSequence text, BufferType type) | |
{ | |
final CharSequence oldText = getText(); | |
super.setText(text, type); | |
if(oldText != null && oldText != text){ | |
if(oldText instanceof Spanned){ | |
SpanReuseCache cache = SpanReuseCache.getInstance(); | |
for(Object span : ((Spanned)oldText).getSpans(0, oldText.length(), Object.class)){ | |
cache.put(span); | |
} | |
} | |
} | |
} | |
} | |
static class SpanReuseCache | |
{ | |
private static HashMap<String, Stack<Object>> sCache = new HashMap<String, Stack<Object>>(); | |
private static class Singleton { | |
private static final SpanReuseCache INSTANCE = new SpanReuseCache(); | |
} | |
public static SpanReuseCache getInstance() | |
{ | |
return Singleton.INSTANCE; | |
} | |
public Object get(Class<?> clazz) | |
{ | |
synchronized(SpanReuseCache.class){ | |
final String key = clazz.getCanonicalName().intern(); | |
final Stack<Object> stack = sCache.get(key); | |
if(stack != null){ | |
try{ | |
return stack.pop(); | |
} | |
catch(EmptyStackException e){ | |
// fall through to default constructor | |
} | |
} | |
} | |
try{ | |
return clazz.getConstructor().newInstance(); | |
} | |
catch(Exception e){ | |
throw new RuntimeException(e); | |
} | |
} | |
public void put(Object object) | |
{ | |
synchronized(SpanReuseCache.class){ | |
final String key = object.getClass().getCanonicalName().intern(); | |
Stack<Object> stack = sCache.get(key); | |
if(stack == null){ | |
stack = new Stack<Object>(); | |
sCache.put(key, stack); | |
} | |
stack.push(object); | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment