I want to be able to load animated gifs into a Textview between text, this is what i've come up with:
I use Html.fromHtml
Since one gif can occur multiple times i make an array of all the different gifs that are loaded so that i can just pass the reference back (though in this tester that isn't used)
this is what i've got so far:
public class MainActivity extends Activity implements ImageGetter {
private TextView mTv;
private Map<String, LevelListDrawable> gifs;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
gifs = new HashMap<>();
String imgs="<p><img alt=\"\" src=\"http://lonelytraveller.comoj.com/qff/tjatja.gif\" style=\"height:50px; width:100px\" />Test Article, Test Article, Test Article, Test Article,Test Article,Test Article,Test Article,Test Article,Test Article,Test Article,Test Article,Test Article,Test Article,Test Article,Test Article,Test Article,Test Article,Test Article,Test Article,Test Article,Test Article,Test Article,Test Article,v</p>";
Spanned spanned = Html.fromHtml(imgs, this, null);
mTv = (TextView) findViewById(R.id.tv);
mTv.setText(spanned);
}
@Override
public Drawable getDrawable(String source) {
if(gifs.get(source.split("\\Q/\\E")[source.split("\\Q/\\E").length-1]) != null){
return gifs.get(source.split("\\Q/\\E")[source.split("\\Q/\\E").length-1]);
}else {
LevelListDrawable d = new LevelListDrawable();
Drawable empty = ContextCompat.getDrawable(this, R.drawable.save);
d.addLevel(0, 0, empty);
d.setBounds(0, 0, empty.getIntrinsicWidth(), empty.getIntrinsicHeight());
new LoadImage().execute(source, d);
return d;
}
}
class LoadImage extends AsyncTask<Object, Void, byte[]> {
private LevelListDrawable mDrawable;
private String key;
@Override
protected byte[] doInBackground(Object... params) {
String source = (String) params[0];
key = source.split("\\Q/\\E")[source.split("\\Q/\\E").length-1];
mDrawable = (LevelListDrawable) params[1];
try {
InputStream is = new URL(source).openStream();
return IOUtils.toByteArray(is);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
@Override
protected void onPostExecute(byte[] bytes) {
if(bytes != null) {
GifDecoder decoder = new GifDecoder();
decoder.read(bytes);
ArrayList<Long> alist = new ArrayList<>();
for (int i = 0; i < decoder.getFrameCount(); i++) {
decoder.advance();
Bitmap bitmap = decoder.getNextFrame();
BitmapDrawable d = new BitmapDrawable(getResources(), bitmap);
int i2 = i+1;
mDrawable.addLevel(i2, i2, d);
mDrawable.setBounds(0, 0, bitmap.getWidth(), bitmap.getHeight());
alist.add((long) decoder.getNextDelay());
}
gifs.put(key, mDrawable);
animateGif(decoder.getFrameCount(), mDrawable, alist);
}
}
}
public void animateGif(int length, LevelListDrawable d, ArrayList<Long> delays){
for(int i = 1; i<(length+1); i++){
d.setLevel(i);
CharSequence t = mTv.getText();
mTv.setText(t);
long sleep = delays.get(i-1);
try {
Thread.sleep(sleep);
} catch (InterruptedException e) {
e.printStackTrace();
}
if(i == length) i=1;
}
}
}
I use this GifDecoder: https://gist.github.com/devunwired/4479231
With the code i posted above, i only get the empty drawable (level 0) if i put a log in animateGif function i can see he does do the infinite loop, but it just doesn't work it stays at the empty drawable image;
If i change the onPostExecute function's content with:
if(bytes != null) {
GifDecoder decoder = new GifDecoder();
decoder.read(bytes);
decoder.advance();
Bitmap bitmap = decoder.getNextFrame();
BitmapDrawable d = new BitmapDrawable(getResources(), bitmap);
mDrawable.addLevel(1, 1, d);
mDrawable.setBounds(0, 0, bitmap.getWidth(), bitmap.getHeight());
mDrawable.setLevel(1);
CharSequence t = mTv.getText();
mTv.setText(t);
}
It does change the empty image into the first frame of the gif file. I just can't see why this wouldn't work, can anyone help me?
I solved it thanks to some help from jawatio at android-dev irc..
By adding this dependancy to the build.gradle file:
compile 'pl.droidsonroids.gif:android-gif-drawable:1.2.6'
Which is from: https://github.com/koral--/android-gif-drawable
And then doing something like this:
public class test extends Activity implements Drawable.Callback {
public TextView tv;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.test);
tv = (TextView) findViewById(R.id.testtext);
new LoadImage().execute("http://lonelytraveller.comoj.com/qff/tjatja.gif");
}
@Override
public void invalidateDrawable(Drawable who) {
tv.invalidate();
}
@Override
public void scheduleDrawable(Drawable who, Runnable what, long when) {
tv.postDelayed(what, when);
}
@Override
public void unscheduleDrawable(Drawable who, Runnable what) {
tv.removeCallbacks(what);
}
class LoadImage extends AsyncTask<Object, Void, byte[]> {
private String key;
@Override
protected byte[] doInBackground(Object... params) {
String source = (String) params[0];
//key = source.split("\\Q/\\E")[source.split("\\Q/\\E").length-1];
try {
InputStream is = new URL(source).openStream();
return IOUtils.toByteArray(is);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
@Override
protected void onPostExecute(byte[] b) {
SpannableStringBuilder ssb = new SpannableStringBuilder("test");
GifDrawable gd = null;
try {
gd = new GifDrawable(b);
} catch (IOException e) {
e.printStackTrace();
}
if (gd != null) {
gd.setBounds(0, 0, gd.getIntrinsicWidth(), gd.getIntrinsicHeight());
gd.setCallback(test.this);
ssb.setSpan(new ImageSpan(gd), 1, 2, 0);
tv.setText(ssb);
}
}
}
}