update UI from AsyncTask - android

I created a custom TextView to show and images on it. I have to download the images and then show them on the textview. So I thought that I can do my job with a AsyncTask class. On the doInBackground I download and save the image on the Internal storage (for offline mode), and on the onPostExecute I call a method which shows the images on the textview. But it doesn't work. I mean instead of showing the images it shows the img tags.
I also tried to get the status from the AsyncTask class on the onPostExecute method and it's RUNNING. Isn't that weird? I thought that it will be FINISHED. Am I missing something about AsyncTask class?
Below is addImages method, where I find the img tags from the text and store the data on a List, and call the DownLoadImage class which extends the AsyncTask.
private boolean add(final Context context, final Spannable spannable) {
path = context.getFilesDir();
Pattern refImgPattern = Pattern.compile("<img .+?\\/>");
hasChanges = false;
refImgMatcher = refImgPattern.matcher(spannable);
while (refImgMatcher.find()) {
set = true;
for (ImageSpan span : spannable.getSpans(refImgMatcher.start(), refImgMatcher.end(), ImageSpan.class)) {
if (spannable.getSpanStart(span) >= refImgMatcher.start()
&& spannable.getSpanEnd(span) <= refImgMatcher.end()
) {
spannable.removeSpan(span);
} else {
set = false;
break;
}
}
String imageUrl = spannable.subSequence(refImgMatcher.start(0), refImgMatcher.end(0)).toString().trim();
width = 0;
Pattern widthPattern = Pattern.compile("width=\"[0-9]+?\"");
Matcher widthMatcher = widthPattern.matcher(imageUrl);
if (widthMatcher.find()) {
String w = widthMatcher.group(0);
w = w.replaceAll("width=", "");
w = w.replaceAll("\"", "");
width = Integer.valueOf(w);
}
height = 0;
Pattern heightPattern = Pattern.compile("height=\"[0-9]+?\"");
Matcher heightMatcher = heightPattern.matcher(imageUrl);
if (heightMatcher.find()) {
String h = heightMatcher.group(0);
h = h.replaceAll("height=", "");
h = h.replaceAll("\"", "");
height = Integer.valueOf(h);
}
Pattern urlPattern = Pattern.compile("(http|ftp|https):\\/\\/([\\w_-]+(?:(?:\\.[\\w_ -]+)+))([\\w.,#?^=%&:\\/~+#-]*[\\w#?^=%&\\/~+#-])?");
Matcher urlMatcher = urlPattern.matcher(imageUrl);
if (urlMatcher.find())
imageUrl = urlMatcher.group(0);
imageName = siteData.getId() + "_" + imageUrl.substring(imageUrl.lastIndexOf("/") + 1, imageUrl.length());
images.add(new Image(imageUrl, imageName, width, height, refImgMatcher.start(0), refImgMatcher.end(0)));
}
if (images.size() > 0) {
for (final Image img : images) {
image = new File(path, img.name);
if (!image.exists()) {
new DownLoadImage(context, spannable, img).execute();
} else
addImages(spannable, context, img);
}
}
return hasChanges;
}
This is the addImages method where I replace the tags with images
private void addImages(Spannable spannable, Context context, Image im) {
image = new File(path, im.name);
BitmapFactory.Options bmOptions = new BitmapFactory.Options();
bitmap = BitmapFactory.decodeFile(image.getAbsolutePath(), bmOptions);
if (im.width > 0 && im.height > 0)
bitmap = Bitmap.createScaledBitmap(bitmap, im.width * 3, im.height * 3, true);
if (set) {
hasChanges = true;
spannable.setSpan(new ImageSpan(context, bitmap),
im.startIndex,
im.endIndex,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
);
}
}
and the DownLoadImage class
private class DownLoadImage extends AsyncTask<Void, Void, Void> {
private Connection connection = Connection.getInstance();
private Context context;
private Spannable spannable;
private Image image;
public DownLoadImage(Context context, Spannable spannable, Image image) {
this.spannable = spannable;
this.context = context;
this.image = image;
}
#Override
protected Void doInBackground(Void... params) {
try {
connection.openConnection(image.path, ConnectionType.GET, false, false, null);
Integer status = connection.getResponseCode();
if (status >= 200 && status < 300) {
InputStream inputStream = new BufferedInputStream(connection.getInputStream());
Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
Actions.saveImage(context, bitmap, image.name);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
connection.closeConnection();
}
return null;
}
#Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
Log.i("status", this.getStatus().toString());
addImages(spannable, context, image);
}
}
***** EDIT *****
the getTextWithImages where I call the add method
private Spannable getTextWithImages(Context context, CharSequence text) {
images = new ArrayList<>();
Spannable spannable = spannableFactory.newSpannable(text);
add(context, spannable);
return spannable;
}
and the setText method where I call the getTextWithImages
#Override
public void setText(CharSequence text, BufferType type) {
Spannable s = getTextWithImages(getContext(), text);
super.setText(s, BufferType.SPANNABLE);
}

You could create an interface that invokes a callback to the UI thread, instead of using the context. For example, in your AsyncTask:
private class DownLoadImage extends AsyncTask<Void, Void, Void> {
private Connection connection = Connection.getInstance();
private Context context;
private Spannable spannable;
private Image image;
private OnImageDownloadedListener mOnImageDownloadedListener;
...
#Override
protected Void doInBackground(Void... params) {
...
...
}
// Interface the task will use to communicate with your activity method.
public interface OnImageDownloadedListener {
void onImageDownloaded(Spannable spannable, Image image); // No need for context.
}
#Override
protected void onPostExecute(Void aVoid) {
if (mOnImageDownloadedListener != null) {
// If we set a listener, invoke it.
mOnImageDownloadedListener.onImageDownloaded(spannable, image);
}
}
// Setter.
public setOnImageDownloadedListener(OnImageDownloadedListener listener) {
mOnImageDownloadedListener = listener;
}
}
Then when you create your task try:
if (!image.exists()) {
// Create the task.
DownloadImage downloadTask = new DownLoadImage(context, spannable, img);
// Set your listener.
downloadTask.setOnImageDownloadedListener(new OnImageLoadedListener() {
#Override
public void onImageDownloaded(Spannable spannable, Image image) {
// Add the images.
addImages(spannable, **YourContextHere(Activity/etc)**.this, image)
}
});
// Execute.
downloadTask.execute();
} else
addImages(spannable, context, img);
Hope this helps.

Related

Universal Image Loader: Why are loaded Images limiting the vertical size of a Textview

I am fetching data from JSON with volley. In the data displayed in bookContent, there are <img> tags in varying positions.
I'm using Universal Image Loader to Load the images in the <img> tags.
This is my Activity.
BookDetails
public class BookDetails extends AppCompatActivity{
private final String TAG = "BookDetails";
private JSONObject bookData;
protected com.nostra13.universalimageloader.core.ImageLoader mImageLoader;
TextView bookTitle, bookAuthorDate, bookContent;
View firstView, secView;
CircularNetworkImageView authorImg;
ImageLoader AuthImgLoader;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_book_details);
showDialog();
bookTitle = (TextView) findViewById(R.id.dbook_title);
bookAuthorDate = (TextView) findViewById(R.id.author_date);
bookContent = (TextView) findViewById(R.id.dbook_content);
authorImg = (CircularNetworkImageView) findViewById(R.id.author_img);
firstView = findViewById(R.id.dviewtop);
secView = findViewById(R.id.dviewbottom);
DisplayImageOptions defaultoptions = new DisplayImageOptions.Builder()
.cacheInMemory(true)
.cacheOnDisk(true)
.build();
ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(getApplicationContext())
.defaultDisplayImageOptions(defaultoptions)
.writeDebugLogs()
.build();
mImageLoader = com.nostra13.universalimageloader.core.ImageLoader.getInstance();
mImageLoader.init(config);
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
actionBar.setDisplayHomeAsUpEnabled(true);
}
if (savedInstanceState != null) {
try {
String bookDataStr = savedInstanceState.getString("bookData");
bookData = new JSONObject(bookDataStr);
parseBook(bookData);
} catch (JSONException e) {
e.printStackTrace();
}
} else {
if (NetworkCheck.isAvailableAndConnected(this)) {
//Calling method to load books
loadBook();
} else {
internetDialog.show();
}
}
}
private void loadBook() {
Log.d(TAG, "loadBook called");
final ProgressBar progressBar;
progressBar = (ProgressBar) findViewById(R.id.progress_circle);
progressBar.setVisibility(View.VISIBLE);
int news_id = getIntent().getIntExtra("BookId", -1);
Log.d(TAG, "You clicked book id " + book_id);
final JsonObjectRequest jsonObjReq = new JsonObjectRequest( DetailConfig.GET_DURL + book_id, null,
new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
Log.d("Debug", response.toString());
//Dismissing progressbar;
if (progressBar != null) {
progressBar.setVisibility(View.GONE);
}
bookData = response;
//Calling method to parse json array
parseBook(response);
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
VolleyLog.d("", "Error: " + error.getMessage());
if (progressBar != null) {
progressBar.setVisibility(View.GONE);
}
}
});
//Creating request queue
RequestQueue requestQueue = Volley.newRequestQueue(this);
//Adding request to queue
requestQueue.add(jsonObjReq);
}
//This method will parse json data of book
private void parseBook(JSONObject jsonObject) {
Log.d(TAG, "Parsing book array");
try {
String title = jsonObject.getString(DetailConfig.TAG_DPOST_TITLE);
bookTitle.setText(Html.fromHtml(title));
JSONObject pAuthor = jsonObject.getJSONObject("author");
String author = pAuthor.getString("name");
String authorimg = pAuthor.getString("avatar");
AuthImgLoader = VolleyRequest.getInstance(getApplicationContext()).getImageLoader();
AuthImgLoader.get(authorimg, ImageLoader.getImageListener(authorImg, R.drawable.ic_author, R.drawable.ic_author));
authorImg.setImageUrl(authorimg, AuthImgLoader);
String content = jsonObject.getString(DetailConfig.TAG_DPOST_CONTENT);
Spanned spanned = Html.fromHtml(content, new UILImageGetter(bookContent, this), null);
bookContent.setText(spanned);
} catch (JSONException w) {
w.printStackTrace();
}
//Unhiding views
bookTitle.setVisibility(View.VISIBLE);
bookAuthorDate.setVisibility(View.VISIBLE);
bookContent.setVisibility(View.VISIBLE);
authorImg.setVisibility(View.VISIBLE);
firstView.setVisibility(View.VISIBLE);
secView.setVisibility(View.VISIBLE);
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString("bookData", bookData.toString());
}
}
Below, I use this piece of code I got from the accepted answer in this question to load the images in bookContent.
This class uses Universal Image Loader.
UILImageGetter
public class UILImageGetter implements Html.ImageGetter{
Context c;
TextView conatiner;
UrlImageDownloader urlDrawable;
public UILImageGetter(View textView, Context context) {
this.c = context;
this.conatiner = (TextView) textView;
}
#Override
public Drawable getDrawable(String source) {
urlDrawable = new UrlImageDownloader(c.getResources(), source);
if (Build.VERSION.SDK_INT >= 21) {
urlDrawable.mDrawable = c.getResources().getDrawable(R.drawable.default_thumb,null);
} else {
urlDrawable.mDrawable = c.getResources().getDrawable(R.drawable.default_thumb);
}
ImageLoader.getInstance().loadImage(source, new SimpleListener(urlDrawable));
return urlDrawable;
}
private class SimpleListener extends SimpleImageLoadingListener {
UrlImageDownloader mUrlImageDownloader;
public SimpleListener(UrlImageDownloader downloader) {
super();
mUrlImageDownloader= downloader;
}
#Override
public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
int width = loadedImage.getWidth();
int height = loadedImage.getHeight();
int newWidth = width;
int newHeight = height;
if (width > conatiner.getWidth()) {
newWidth = conatiner.getWidth();
newHeight = (newWidth * height) / width;
}
if (view != null) {
view.getLayoutParams().width = newWidth;
view.getLayoutParams().height = newHeight;
}
Drawable result = new BitmapDrawable(c.getResources(), loadedImage);
result.setBounds(0, 0, newWidth, newHeight);
mUrlImageDownloader.setBounds(0, 0, newWidth, newHeight);
mUrlImageDownloader.mDrawable = result;
conatiner.setHeight((conatiner.getHeight() + result.getIntrinsicHeight()));
conatiner.invalidate();
}
}
private class UrlImageDownloader extends BitmapDrawable {
public Drawable mDrawable;
public UrlImageDownloader(Resources resources, String filepath) {
super(resources, filepath);
mDrawable = new BitmapDrawable(resources, filepath);
}
#Override
public void draw(Canvas canvas) {
if (mDrawable != null) {
mDrawable.draw(canvas);
}
}
}
}
Everything works fine, the JSON is properly parsed and displayed, the images are loaded but there is a problem.
The loaded images are affecting the vertical lines that are displayed in bookContent. If there are many vertical lines, some part of it is cut off.
And if the bookContent has very few vertical lines, a large empty space is left at the bottom of the TextView.
However, if I don't load the images, the bookContent appears fine, no cut-offs, no extra space.
Please, how do I fix it?
I go the answer to this problem from dcow's comment in this question. What I did is that I removed
conatiner.setHeight((conatiner.getHeight() + result.getIntrinsicHeight()));
and wrote
container.setText(container.getText()); under
container.setText(container.getText());.

How can resolve: The content of the adapter has changed but ListView did not receive a notification

I have this exception on my APP... I don't know why happen it.
java.lang.IllegalStateException:
The content of the adapter has changed but ListView did not receive a notification. Make sure the content of your adapter is not modified from a background thread, but only from the UI thread.
In ListView(2131492879), class android.widget.ListView with Adapter class com.agencialanave.AdaptadorListaApps
I have tried many options but I have not managed to fix it.
Class: Apps.java
public class Apps
{
public Bitmap Colorbanda;
public Bitmap Logo;
public Bitmap LogoBasura;
public String NombreAPP;
public float MemoriaUsada;
public String NombrePaquete;
public File Apk;
public Apps(Bitmap colorbanda, Bitmap logo,String nombreAPP, float memoriaUsada, Bitmap logoBasura, String nombrePaquete, File apk)
{
super();
Colorbanda = colorbanda;
Logo = logo;
LogoBasura = logoBasura;
NombreAPP = nombreAPP;
MemoriaUsada = memoriaUsada;
NombrePaquete = nombrePaquete;
Apk = apk;
}
public Apps(Bitmap colorbanda, Bitmap logo,String nombreAPP, float memoriaUsada, Bitmap logoBasura, String nombrePaquete)
{
super();
Colorbanda = colorbanda;
Logo = logo;
LogoBasura = logoBasura;
NombreAPP = nombreAPP;
MemoriaUsada = memoriaUsada;
NombrePaquete = nombrePaquete;
}
public Bitmap getColorbanda() {
return Colorbanda;
}
public void setColorbanda(Bitmap colorbanda) {
Colorbanda = colorbanda;
}
public Bitmap getLogo() {
return Logo;
}
public void setLogo(Bitmap logo) {
Logo = logo;
}
public Bitmap getLogoBasura() {
return LogoBasura;
}
public void setLogoBasura(Bitmap logoBasura) {
LogoBasura = logoBasura;
}
public String getNombreAPP() {
return NombreAPP;
}
public void setNombreAPP(String nombreAPP) {
NombreAPP = nombreAPP;
}
public float getMemoriaUsada() {
return MemoriaUsada;
}
public void setMemoriaUsada(float memoriaUsada) {
MemoriaUsada = memoriaUsada;
}
public String getNombrePaquete() {
return NombrePaquete;
}
public void setNombrePaquete(String nombrePaquete) {
NombrePaquete = nombrePaquete;
}
public File getApk() {
return Apk;
}
public void setApk(File apk) {
Apk = apk;
}
}
Class: AdaptadorListaApps.java
public class AdaptadorListaApps extends ArrayAdapter<Apps>
{
private static Activity Context;
ArrayList<Apps> listaApps;
public AdaptadorListaApps(Activity context, ArrayList<Apps> lista)
{
super(context, R.layout.layout_list, lista);
Context = context;
listaApps = lista;
}
class ViewHolder
{
ImageView fotoBandaColor,fotoLogoApp,fotoDelete;
TextView nombreApp, memoriaUsada;
}
#Override
public View getView(int position, View convertView, ViewGroup parent)
{
View item =convertView;
ViewHolder holder;
if (item == null)
{
LayoutInflater inflater = Context.getLayoutInflater();
item = inflater.inflate(R.layout.layout_list, null);
holder = new ViewHolder();
holder.fotoBandaColor = (ImageView)item.findViewById(R.id.bandaColor);
holder.fotoLogoApp = (ImageView)item.findViewById(R.id.logoApp);
holder.fotoDelete = (ImageView)item.findViewById(R.id.borrarApp);
holder.nombreApp = (TextView)item.findViewById(R.id.nombreApp);
holder.memoriaUsada = (TextView)item.findViewById(R.id.memoriaUsada);
item.setTag(holder);
}
else
{
holder=(ViewHolder) item.getTag();
}
holder.fotoBandaColor.setImageBitmap(listaApps.get(position).getColorbanda());
holder.fotoLogoApp.setImageBitmap(listaApps.get(position).getLogo());
holder.fotoDelete.setImageBitmap(listaApps.get(position).getLogoBasura());
holder.memoriaUsada.setText(TamaƱoAppEnRam(listaApps.get(position).getMemoriaUsada()) + " MB ( " + PorcentageMemoria(listaApps.get(position).getMemoriaUsada())+"% )");
if(listaApps.get(position).getMemoriaUsada() < 4)
{
holder.memoriaUsada.setTextColor(Color.parseColor("#56E000"));
}
else if(listaApps.get(position).getMemoriaUsada() > 7)
{
holder.memoriaUsada.setTextColor(Color.RED);
}
else
{
holder.memoriaUsada.setTextColor(Color.parseColor("#FF8000"));
}
holder.nombreApp.setText(listaApps.get(position).getNombreAPP());
return item;
}
}
Code where update listview
private class GetRunningApps extends AsyncTask<String, ArrayList<Apps>, String>
{
#Override
protected String doInBackground(String... params) throws IllegalStateException
{
listaapps.clear();
listaapps = new ArrayList<Apps>();
cont = 0;
ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningAppProcessInfo> runningTasks = activityManager.getRunningAppProcesses();
PackageManager pm = context.getPackageManager();
Drawable icon;
Bitmap logo;
float memoria = 0;
String nombrePaquete;
MB = 0;
int pids[] = new int[1];
adaptadorLista = new AdaptadorListaApps(activity,listaapps);
for (RunningAppProcessInfo appInfo : runningTasks)
{
try
{
if(appInfo.importance == RunningAppProcessInfo.IMPORTANCE_SERVICE || appInfo.importance == RunningAppProcessInfo.IMPORTANCE_BACKGROUND)
{
icon = pm.getApplicationIcon(appInfo.processName);
logo = ((BitmapDrawable) icon).getBitmap();
CharSequence c = pm.getApplicationLabel
(
pm.getApplicationInfo(appInfo.processName,PackageManager.GET_META_DATA)
);
pids[0] = appInfo.pid;
nombrePaquete = appInfo.processName;
android.os.Debug.MemoryInfo[] memoryInfoArray = activityManager.getProcessMemoryInfo(pids);
for(android.os.Debug.MemoryInfo pidMemoryInfo: memoryInfoArray)
{
memoria = (float)pidMemoryInfo.getTotalPss()/1024;
if(pidMemoryInfo.getTotalPss()/1024 <= 3)
{
listaapps.add(new Apps(bandaVerde, logo , c.toString() , memoria ,logoDelete, nombrePaquete, new File(getActivity().getPackageManager().getApplicationInfo(nombrePaquete, PackageManager.GET_META_DATA).publicSourceDir)));
}
else if((pidMemoryInfo.getTotalPss()/1024 >= 7))
{
listaapps.add(new Apps(bandaRoja, logo , c.toString() , memoria ,logoDelete,nombrePaquete, new File(getActivity().getPackageManager().getApplicationInfo(nombrePaquete, PackageManager.GET_META_DATA).publicSourceDir)));
}
else if((pidMemoryInfo.getTotalPss()/1024 > 3 && pidMemoryInfo.getTotalPss()/1024 < 7))
{
listaapps.add(new Apps(bandaNaranja, logo , c.toString() , memoria ,logoDelete,nombrePaquete, new File(getActivity().getPackageManager().getApplicationInfo(nombrePaquete, PackageManager.GET_META_DATA).publicSourceDir)));
}
}
cont++;
MB += memoria;
if(cont % 2 == 0)
{
try
{
publishProgress();
}
catch(IllegalStateException e){}
}
}
}
catch (Exception e) {}
}
cont = 0;
return null;
}
#Override
protected void onProgressUpdate(ArrayList<Apps>... values)
{
try
{
adaptadorLista = new AdaptadorListaApps(activity,listaapps);
listaAplicaciones.setAdapter(adaptadorLista);
adaptadorLista.notifyDataSetChanged();
}
catch(IllegalStateException e){}
}
#Override
protected void onPostExecute(String result)
{
adaptadorLista = new AdaptadorListaApps(activity,listaapps);
adaptadorLista.sort(new OrderList());
listaAplicaciones.setAdapter(adaptadorLista);
}
}
Please, help me... Thanks
You should never change the properties of a view or any of its underlying datasource on a background thread.
Do not manipulate the variable listaaps in your onBackground. Only change it in your onPostExecute or onProgressUpdate.
Do not manipulate the variable adaptorLista in your onBackground. Only change it in your onPostExecute or onProgressUpdate.

Android ListView wrong images

I'm developing an Android app but I'm a newbie and I got stuck...
My ListView single element has an ImageView and some TextViews, but sometimes (when I scroll the page and there are more than 7-8 elements) it doesn't display the right image in the right row.
I'm using a custom Image Loader to manage the downloaded images.
Here's my Adapter:
public class AddVideogameActivityAdapter extends BaseAdapter {
private ArrayList<Videogame> videogames;
private Typeface typefaceMedium;
private Typeface typefaceLight;
private ImageLoader loader;
private LayoutInflater mInflater;
public AddVideogameActivityAdapter(Context context, ArrayList<Videogame> results) {
videogames = results;
mInflater = LayoutInflater.from(context);
typefaceMedium = Typeface.createFromAsset(context.getAssets(), "Roboto-Medium.ttf");
typefaceLight = Typeface.createFromAsset(context.getAssets(), "Roboto-Light.ttf");
loader = new ImageLoader(context);
}
public int getCount() {
return videogames.size();
}
public Object getItem(int position) {
return videogames.get(position);
}
public long getItemId(int position) {
return position;
}
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
convertView = mInflater.inflate(R.layout.list_element,null);
holder = new ViewHolder();
holder.imgView = (ImageView) convertView.findViewById(R.id.thumbView);
holder.txtName = (TextView) convertView.findViewById(R.id.elementView);
holder.txtPlatform = (TextView) convertView.findViewById(R.id.elementView2);
convertView.setTag(holder);
}
else {
holder = (ViewHolder) convertView.getTag();
}
try {
Videogame vgame = (Videogame) videogames.get(position);
holder.txtName.setText(vgame.getTitle());
holder.txtName.setTypeface(typefaceMedium);
holder.txtPlatform.setText(videogames.get(position).getPlatform());
holder.txtPlatform.setTypeface(typefaceLight);
holder.imgUrl = videogames.get(position).getImage();
loader.display(holder.imgUrl, holder.imgView, R.drawable.youtube_icon);
}
catch (Exception e) {
e.printStackTrace();
Log.e(com.example.ludos2_0.MainActivity.TAG,
"Exception: " + e.getLocalizedMessage());
}
return convertView;
}
static class ViewHolder {
TextView txtName;
TextView txtPlatform;
public String imgUrl;
ImageView imgView;
}
}
Sorry for my english and thank you for your help!
EDIT:
Here's also the Loader:
public class ImageLoader implements ComponentCallbacks2 {
private TCLruCache cache;
public ImageLoader(Context context) {
ActivityManager am = (ActivityManager) context.getSystemService(
Context.ACTIVITY_SERVICE);
int memoryClass = am.getMemoryClass() * 1024 * 1024;
cache = new TCLruCache(memoryClass);
}
public void display(String url, ImageView imageview, int defaultresource) {
imageview.setImageResource(defaultresource);
Bitmap image = cache.get(url);
if (image != null) {
imageview.setImageBitmap(image);
}
else {
new SetImageTask(imageview).execute(url);
}
}
private class TCLruCache extends LruCache<String, Bitmap> {
public TCLruCache(int maxSize) {
super(maxSize);
}
}
private class SetImageTask extends AsyncTask<String, Void, Integer> {
private ImageView imageview;
private Bitmap bmp;
public SetImageTask(ImageView imageview) {
this.imageview = imageview;
}
#Override
protected Integer doInBackground(String... params) {
String url = params[0];
try {
bmp = getBitmapFromURL(url);
if (bmp != null) {
cache.put(url, bmp);
}
else {
return 0;
}
} catch (Exception e) {
e.printStackTrace();
return 0;
}
return 1;
}
#Override
protected void onPostExecute(Integer result) {
if (result == 1) {
imageview.setImageBitmap(bmp);
}
super.onPostExecute(result);
}
private Bitmap getBitmapFromURL(String src) {
try {
URL url = new URL(src);
HttpURLConnection connection
= (HttpURLConnection) url.openConnection();
connection.setDoInput(true);
connection.connect();
InputStream input = connection.getInputStream();
Bitmap myBitmap = BitmapFactory.decodeStream(input);
return myBitmap;
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
}
}
RE-EDIT
Activity code:
public class AddVideogameActivity extends ListActivity {
private TextView searchField = null;
private final Handler handler = new Handler();
private ArrayList<Videogame> videogamesList = null;
private static AddVideogameActivity mContext = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_add_book);
mContext = this;
searchField = (TextView) findViewById(R.id.searchField);
searchField.setMaxLines(1);
searchField.setOnFocusChangeListener(new OnFocusChangeListener() {
#Override
public void onFocusChange(View v, boolean hasFocus) {
searchField.setHint("");
}
});
// Setup the list view and its listener
getListView().setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
Log.d(MainActivity.TAG,
"AddBookActivity ---> AddButton:onClick()");
// Sets typefaces for TextView
String videogameId = videogamesList.get(position).getId();
String videogameName = videogamesList.get(position).getTitle();
String thumbnail = videogamesList.get(position).getThumbnail();
String description = videogamesList.get(position)
.getDescription();
String image = videogamesList.get(position).getImage();
String platform = videogamesList.get(position).getPlatform();
if (videogameName != null && videogameName.length() > 0
&& thumbnail != null && thumbnail.length() > 0
&& description != null && description.length() > 0
&& image != null && image.length() > 0
&& platform != null && platform.length() > 0) {
if (ListsManager.getInstance().addVideogame(
new Videogame(videogameId, videogameName,
thumbnail, image, description, platform)) == 0) {
Log.d(MainActivity.TAG,
"AddBookActivity --> Videogame:[" + videogameId
+ "#" + videogameName + "]");
Toast toast = Toast.makeText(mContext, "["
+ videogameName + "] Saved !",
Toast.LENGTH_LONG);
toast.show();
} else {
Log.e(MainActivity.TAG,
"AddBookActivity --> Error ! Videogame already in the list ! ");
Toast toast = Toast.makeText(mContext,
"Error! Videogame already in the list!",
Toast.LENGTH_LONG);
toast.show();
}
} else {
Log.e(MainActivity.TAG,
"AddBookActivity --> Error ! Invalid Videogame Name or Thumbnail or Id or Deck");
Toast toast = Toast
.makeText(
mContext,
"Error ! Invalid Videogame Name or Thumbnail or Id or Deck",
Toast.LENGTH_LONG);
toast.show();
}
Intent newIntent = new Intent(getApplicationContext(),
MainActivity.class);
startActivity(newIntent);
}
});
// Setup the search button and its listener
Button searchButton = (Button) findViewById(R.id.searchButton);
searchButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Log.d(com.example.ludos2_0.MainActivity.TAG, "Search Game ...");
String searchInputString = searchField.getText().toString();
if (searchInputString != null && searchInputString.length() > 0) {
try {
String requestURL = ("http://www.giantbomb.com/api/search/?api_key=fcf60d6d67b98b0d17b3905d1a90b3fd31ed1e8e&format=json&query="
+ Uri.encode(searchInputString) + "&resources=game");
// String requestURL =
// String.format("https://gdata.youtube.com/feeds/api/videos?v=2&alt=jsonc&category=Music&orderby=relevance&q=%s",Uri.encode(searchInputString));
Log.d(com.example.ludos2_0.MainActivity.TAG, requestURL);
DownloadGiantBombJSONData giantbombAsyncTask = new DownloadGiantBombJSONData();
giantbombAsyncTask.execute(new String[] { requestURL });
} catch (Exception e) {
e.printStackTrace();
}
}
}
});
if (videogamesList == null)
videogamesList = new ArrayList<Videogame>();
else
updateVideogamesListView(videogamesList);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.add_book, menu);
return true;
}
#Override
protected void onResume() {
super.onResume();
}
#Override
protected void onPause() {
super.onPause();
}
public void updateVideogamesListView(ArrayList<Videogame> values) {
AddVideogameActivityAdapter adapter = new AddVideogameActivityAdapter(this, values);
setListAdapter(adapter);
}
#Override
protected void onDestroy() {
super.onDestroy();
}
}
The other classes involved in building the ListView are the REST classes and the AsyncTask class that downloads and parses the JSon files.
What does your ListView look like, does it look like this:
<ListView android:id="#id/android:list"
android:layout_weight="1"
android:layout_width="match_parent"
android:layout_height="0dip" ></ListView>
Especially the id of the ListView. Check your layout file, probably the bug exists there.

How to cancel an Async task in gallery View in android using position index?

i have an galleyview which loads images from server album. but my album has many images [more than 500]. so once i scroll the galleyview more fast the number of background task is getting high so the app is getting crashed.so i am planning to kill [cancel] some old tasks based on the position in the galleryview. so please suggest some solution.The source code is provided below.
Task invoking:
DownloadImageTask downloadTask = new DownloadImageTask(
ShowGallery.this, view,position);
// cancel some task to avoid the crash - need to implement
// cancelPotentialDownload(position);
downloadTask.execute( THUMB_PREFIX + picture.getFileName(),
picture.getForceExtension(), thumbUrl,albumName, bitmapsCache, position, picture,null);
private static boolean cancelPotentialDownload(int position) {
// need to implement.
}
Downloadimage task
public class DownloadImageTask extends AsyncTask<Object, Void, Bitmap> {
Context activity;
private ImageView view;
public int position;
public DownloadImageTask(Context context, ImageView imageView, int imagePosition) {
super();
activity = context;
view = imageView;
position = imagePosition;
}
#Override
protected Bitmap doInBackground(Object... parameters) {
String fileName = (String) parameters[0];
String extension = (String) parameters[1];
String thumbUrl = (String) parameters[2];
Integer currentAlbumName = (Integer) parameters[3];
Map<Integer, Bitmap> bitmapsCache = (Map<Integer, Bitmap>) parameters[4];
Integer position = (Integer) parameters[5];
Picture picture = (Picture) parameters[6];
Album album = (Album) parameters[7];
Bitmap downloadImage = null;
File imageFileOnExternalDirectory = null;
try {
imageFileOnExternalDirectory = FileUtils.getInstance()
.getFileFromGallery(activity, fileName, extension,
thumbUrl, true, currentAlbumName);
downloadImage = BitmapFactory
.decodeFile(imageFileOnExternalDirectory.getPath());
if (picture != null) {
// only for showgallery activity
picture.setThumbImageCachePath(imageFileOnExternalDirectory
.getPath());
bitmapsCache.put(position, downloadImage);
} else if (album != null) {
// only for albumadapter
album.setAlbumCoverCachePath(imageFileOnExternalDirectory
.getPath());
}
} catch (GalleryConnectionException e) {
// Log.v(TAG, e.getMessage());
} catch (FileHandlingException e) {
// Log.v(TAG, e.getMessage());
}
return downloadImage;
}
#Override
protected void onPostExecute(Bitmap downloadImage) {
if (downloadImage != null) {
view.setImageBitmap(downloadImage);
}
}
}
Look at the example on this link. You are not downloading images from the web, so just replace this functionality with reading the image from gallery

notifyDataSetChanged not refreshing listview

Initially I get list of data from server and set it to listview.
When scrolling down the listview, I am getting collection of data from server and calling notifydatasetchanged of my custom adapter.
At getView() method of custom adapter, I am downloading an image from server by asyntask. When it is downloaded successfully and storing it locally. Then just trying to refresh list view at onPostExecute of that asyntask. But its not getting refresh.
The log at onPostExecute is printing but listview is not getting refresh.
public void loadBitmap(MainActivity mainActivity, String imageKey,ImageView imageView, boolean isScrolling)
{
final Bitmap bitmap = getBitmapFromCache(imageKey);
if (bitmap != null) {
imageView.setImageBitmap(bitmap);
} else {
imageView.setImageResource(R.drawable.ic_launcher);
if (!isScrolling && !mCurrentTasks.contains(imageKey)
&& mainActivity.internetIsAvailable()) {
BitmapLoaderTask task = new BitmapLoaderTask(imageKey,
mainActivity.getAdapter());
task.execute();
}
}
}
private class BitmapLoaderTask extends AsyncTask<Void, Void, Bitmap> {
private ListAdapter mListAdapter;
private String mImageKey;
public BitmapLoaderTask(String imageKey, ListAdapter adapter) {
mListAdapter = adapter;
mImageKey = imageKey;
}
#Override
protected void onPreExecute() {
mCurrentTasks.add(mImageKey);
}
#Override
protected Bitmap doInBackground(Void... params) {
Bitmap b = null;
try {
URL url = new URL(mImageKey);
HttpURLConnection connection = (HttpURLConnection) url
.openConnection();
connection.connect();
b = BitmapFactory.decodeStream(connection.getInputStream());
if (b != null) {
int width = b.getWidth();
int height = b.getHeight();
if (width >= mMaxWidth || height >= mMaxHeight) {
while (true) {
if (width <= mMaxWidth || height <= mMaxHeight) {
break;
}
width /= 2;
height /= 2;
}
b = Bitmap.createScaledBitmap(b, width, height, false);
}
connection.disconnect();
addBitmapToCache(mImageKey, b);
return b;
}
return null;
} catch (IOException e) {
if (e != null) {
e.printStackTrace();
}
return null;
}
}
#Override
protected void onPostExecute(Bitmap param) {
mCurrentTasks.remove(mImageKey);
if (param != null) {
mListAdapter.notifyDataSetChanged();
}
}
}
your code looks right.. but i think what may be the issue is mainActivity.getAdapter() i think you should declare adapter globally like.
private AdapterYourCustomAdapter adapter;
and then in onCreate()
adapter = new AdapterYourCustomAdapter(context,arraylist(whatever constructor is));
and then pass that call it like:
if (bitmap != null) {
imageView.setImageBitmap(bitmap);
} else {
imageView.setImageResource(R.drawable.ic_launcher);
if (!isScrolling && !mCurrentTasks.contains(imageKey)
&& mainActivity.internetIsAvailable()) {
new BitmapLoaderTask( imageKey, adapter ).execute();
}
}
Try passing the ImageView for each bitmap into the BitmapLoaderTask at construction and hold onto that ImageView as a member variable inside. When you finish loading your bitmap, use the onPostExecute method to assign that bitmap as the ImageView drawable.
private class BitmapLoaderTask extends AsyncTask<Void, Void, Bitmap> {
private String mImageKey;
private ImageView mImageView;
public BitmapLoaderTask(ImageView imageView, String imageKey) {
mImageView = imageView;
mImageKey = imageKey;
}
protected void onPreExecute() {
/* Pre execute stuff */
}
protected Bitmap doInBackground(Void... params) {
/* Your bitmap processing */
return bitmap;
}
protected void onPostExecute(Bitmap param) {
if(param != null) {
mImageView.setImageBitmap(param);
}
}
}
This is a perfect example of what AsyncTask was built to do. The doInBackground() method is run on a background thread and thus does not interfere with UI processing, but android permissions dictate that such background threads are not allowed to touch UI elements. That's what the onProgressUpdate() and onPostExecute() are for, they run quick UI updates on the main UI thread whenever doInBackground has reached an update-worthy milestone. In this case, you're using them to notify your ImageView objects when their corresponding bitmaps are ready.

Categories

Resources