I'm attempting parse a JSON payload and place the information in Relative Layout View.
I use this STANDARD asynchronous download routine to obtain the bitmaps to be placed in the appropriate ImageView:
public class AsyncDownloadImage extends AsyncTask<String,Void,Bitmap>{
ImageView bmImage;
public AsyncDownloadImage(ImageView bmImage){
this.bmImage = bmImage;
}
#Override
protected Bitmap doInBackground(String... urls) {
String urldisplay = null;
urldisplay = urls[0];
Bitmap merchViewBitMap = Bitmap.createBitmap(90,90,Bitmap.Config.ARGB_8888);
try{
InputStream in = new URL(urldisplay).openStream();
merchViewBitMap = BitmapFactory.decodeStream(in);
in.close();
}catch(Exception e){
System.out.println(String.format("Image Download Exception ==> %s", e.toString()));
}
return merchViewBitMap;
}
#Override
protected void onPostExecute(Bitmap result) {
super.onPostExecute(result);
bmImage.setImageBitmap(result);
}
}
It's called this way in the getView method of the Adapter class:
String imageUrl = String.format("https://www.xxxxxx.com/va/public/render_image?image_id=%s", currentMerchItem.getMt_image_id());
new AsyncDownloadImage(viewHolder.imageview).execute(imageUrl);
The images are downloaded and the ImageView(s) are set, but they are downloaded repeatedly and infinitely. Multiple images seem to be in an ImageView and when scrolled through they change as each is gif.
How do I stop this after the last image in the list is downloaded?!
-TU
The adapters getView method will be called each time the view of the adapter (listview for example) needs to refresh item's view. When you scroll for example you will get many calls to the getview method (depends on the list length ofcourse). At least you need to manage which images are already being loaded from the net in your case. You also have a lot of open source code for lazy loading exactly for cases like yours.
You can also check this thread, it may help you:
Lazy load of images in ListView
Related
I have implemented a video calling feature in our app. There is a button which captures the screenshot of specific view. On video call there a two views Local View and Remote View. These are actually Relative and Frame layouts. In this case i want take screenshot of remote view but it's just giving me a blank image. I think somehow agora video calling not allowing it but there should be any settings or something to disable this but that i have not found yet. here is the code:
Setting up remote video:
mRemoteContainer is a RelativeLayout and mRemoteVideo is VideoCanvas by agora.io
Similarly mLocalContainer is FrameLayout.
private void setupRemoteVideo(int uid) {
ViewGroup parent = mRemoteContainer;
if (parent.indexOfChild(mLocalVideo.view) > -1) {
parent = mLocalContainer;
}
if (mRemoteVideo != null) {
return;
}
SurfaceView view = RtcEngine.CreateRendererView(getBaseContext());
view.setZOrderMediaOverlay(parent == mLocalContainer);
parent.addView(view);
mRemoteVideo = new VideoCanvas(view, VideoCanvas.RENDER_MODE_HIDDEN, uid);
mRemoteVideo.view.setWillNotDraw(false);
mRtcEngine.setupRemoteVideo(mRemoteVideo);
}
This function used to get bitmap from the view
private Bitmap getScreenShotFromView(View v) {
Bitmap screeShoot = null;
try {
screeShoot = Bitmap.createBitmap(v.getMeasuredWidth(), v.getMeasuredHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(screeShoot);
v.draw(canvas);
} catch (Exception e) {
Log.e("GFG", "Failed to capture screenshot because:" + e.getMessage());
}
return screeShoot;
}
I tried function call with both view but getting black or blank image
Bitmap bitmap = getScreenShotFromView(mRemoteVideo.view);
Bitmap bitmap = getScreenShotFromView(mRemoteContainer);
Your help will be really appreciated for me as i stuck on this issue.
By the way I used the same view capturing technique on iOS with swift
and Its working fine.
I was writing an android application which contains a RecyclerView inside my ActivityMain. Each rows has an imageButton and a textLabel. In onBindViewHolder() method, I download an image from an URL and after using setImageDrawable method, I change the image with the one that I just downloaded.
#Override
public void onBindViewHolder(#NonNull final MyViewHolder holder, final int position) {
holder.textAuthor.setText(posts.get(position).getAuthorName());
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
try {
// Get URL Image from my ArrayList Posts(which contains imageButton and textLabel)
URL url = new URL(posts.get(position).getImageView());
// Get inputStream from URL
InputStream inputStream = (InputStream) url.getContent();
// Create a drawable which contains my downloaded image
Drawable drawable = Drawable.createFromStream(inputStream, null);
// Change the image with the new one
holder.imageButton.setImageDrawable(drawable);
} catch (Exception e) {
e.printStackTrace();
}
}
});
thread.start();
}
All my ImageButton change image correctly downloading from their URL, but the problem is that they have wrong size until I scroll down and after a while I scroll up inside of my RecyclerView using my finger. It sounds like if I have to refresh my View but I don't know how to do this.
Note: all images have different size
I let you some images to explain better my problem:
When I open my application and it starts to download image from URL
When the download is completed the images have wrong size
If I scroll down and after I scroll up I get the images with the correct size
The rest of my codes is here: MainActivty MyAdapter PostClass
XML File which contains ImageButton: my row of RecyclerView
Hope you can help me as always, thank you a lot!
EDIT: I have fixed downloading image using Glide!
Try the following code it worked for me
<ImageButton
android:id="#+id/imageButton2"
android:layout_width="25dp"
android:layout_height="25dp"
app:srcCompat="#drawable/about" />
give your image button fixed height and width then it will work
I have a big problem with loading images from cache on the getView of my Listadapter.
For image-loading we are using Picasso, and there I build a construct for loading images from cache and if there are no available images, THEN the images should be load from an online-URI.
(Here is a method, which is called inside of my getView of my Adapter)
#Override
protected void loadImages(final VehicleResultListItem inCurrentItem) {
// Try to load async the images from local path
Picasso.with(mContext)
.load(new File(mContext.getExternalFilesDir(null),
inCurrentItem.getVehicleId()))
.placeholder(inCurrentItem.getServiceType().getPlaceholderId())
.noFade()
.into(new Target() {
#Override
public void onBitmapLoaded(final Bitmap bitmap,
final Picasso.LoadedFrom from) {
mThumbnailImgView.setImageBitmap(bitmap);
}
#Override
public void onBitmapFailed(final Drawable errorDrawable) {
// If the local-path-loading fails, try to grab the images online.
Picasso.with(mContext)
.load(inCurrentItem.getImageURIs().get(0).getImageUriSizeM())
.placeholder(inCurrentItem.getServiceType().getPlaceholderId())
.into(new Target() {
#Override
public void onBitmapLoaded(final Bitmap bitmap,
final Picasso.LoadedFrom from) {
// On succesfully online-loading of the images, store and show them
mThumbnailImgView.setImageBitmap(bitmap);
saveToInternalSorage(bitmap, inCurrentItem);
}
#Override
public void onBitmapFailed(final Drawable errorDrawable) {
// NO interaction
}
#Override
public void onPrepareLoad(final Drawable placeHolderDrawable) {
// No interaction
}
});
}
#Override
public void onPrepareLoad(final Drawable placeHolderDrawable) {
mThumbnailImgView.setImageDrawable(placeHolderDrawable);
}
});
}
The problem is, that the image is loading correctly, but the imageView is not updating after image is loaded. In the OnImageLoaded, I am not in the UI-Thread, so ofc it does not update the view. So i tried anything:
Runnable
AsyncTask
Androids solution from (http://developer.android.com/training/displaying-bitmaps/process-bitmap.html#concurrency)
It looks like the Threads are getting confused or something like that.
Maybe there is a problem in calling Picasso inside of a Picasso-Target?
Do u have any suggestion?
Greetz and thx
Target must not be an anonymous class. Picasso keeps a WeakReference on Target that will most likely get gc'ed by the time the request completes.
Javadoc clearly states that.
Make your View implement Target instead and use that as the target or keep a reference to your target instances.
Also Picasso handles disk caching for you automatically, unless you've shipped the assets with your app, I would recommend you simply download them and then let Picasso manage the disk/memory cache for you.
I'm trying to create a simple app that loading photos from a website (like 9gag). I'm using jSoup and asyncTask. The problem is when I'm running the app it shows me only the urls of the images.. what can I do in order to display the image in the listView and not the urls.
XML Prob? Help :-/
![Screen Shot]https://www.dropbox.com/s/moybisjrbdgzjre/Screenshot_2013-04-29-20-09-13.png
here's my LoadImages class:
public LoadImages(ArrayList list, ArrayAdapter adapter)
{
this.list = list;
this.adapter = adapter;
}
#Override
protected Elements doInBackground(String... params) {
org.jsoup.nodes.Document doc = null;
try
{
doc =Jsoup.connect("http://mongol.co.il/").get();
return doc.select("img");
}
catch (IOException e1)
{
e1.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(Elements result) {
super.onPostExecute(result);
int flag=0;
//Bitmap bitmap = null;
for ( org.jsoup.nodes.Element div : result )
{
String bla = div.absUrl("src");
list.add(bla);
flag++;
if(flag==3)
break;
}
adapter.notifyDataSetChanged();
}
Here's also my .xml file:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<ListView
android:id="#+id/listview"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</ListView>
</LinearLayout>
Thanks In advance!
You're only fetching the URLs at this point. You need to fetch the actual Bitmap data in order to show images. There are two ways to do this:
Download all the images, then show the list after everything is fetched
Show the list immediately with image placeholders, the fetch the images as they're
needed
In general, it's a better experience to respond quickly by showing what you have as you get it (option #2). A ListView is really conducive to this model. In the getView() method of the adapter you'll show the placeholder image while firing off an AsyncTask to get the bitmap. You'll then set Image in onPostExecute. Unfortunately things get messy with View recycling. This basic implementation will result in the wrong image being shown in many cases and a totally unresponsive device if the user scrolls back and forth quickly.
Fortunately, these are problems that others have solved. In fact, there is an excellent set of tutorials along with sample code on Android Developer website.
I have done something like this:
I have a DB with ID, image URL, image URI
image URI is something like file:////mnt/sdcard/<your package>/images/image1.png
I have a place Holder image for each row and in my Arraylist i have put image URI in Arraylist. then in getView method check if that URI file exists or not if not then send a broadcast to download that image(with ID). In downloader I fetch images with corresponding URL.
How to check URI exists: create a file object with URI and call isExists()
How to send broadcast: create an intent put ID in extras then call sendBroadcast(intent)
Now how to refresh list after image has been download: Send another broadcast from onPostExecute() to refresh list and catch that broadcast in your activity and call list.notifyDatasetChanged().
You are adding String to the list
String bla = div.absUrl("src");
list.add(bla);
You need to create custom adapter (for the ListView), which will take that String bla and download the image.
Try this tutorial
I use an BaseAdapter to display a list of objects. This objects are fetched from a server. The getView() method of the BaseAdapter is the following:
/* (non-Javadoc)
* #see android.widget.Adapter#getView(int, android.view.View, android.view.ViewGroup)
*/
#Override
public View getView(int position, View convertView, ViewGroup parent) {
LinearLayout content = (LinearLayout) View.inflate(lexs, R.layout.favorite_item, null);
LinearLayout paragraphView = new LinearLayout(lexs);
paragraphView.setBackgroundColor(Color.RED);
paragraphView.setGravity(Gravity.CENTER_VERTICAL);
paragraphView.setOrientation(LinearLayout.HORIZONTAL);
ImageView img = new ImageView(lexs);
img.setImageResource(R.drawable.down);
paragraphView.addView(img);
img.setPadding(0, 0, 5, 0);
img.setOnClickListener(new WorkspaceOnClickListener(position));
TextView text = new TextView(lexs);
text.setTextColor(Color.WHITE);
text.setText(favorites.get(position).getParentChapter().getBook().getName() + ": §" + favorites.get(position).getName());
text.setOnClickListener(new ParagraphOnClickListener(position));
DisplayMetrics metrics = new DisplayMetrics();
lexs.getWindowManager().getDefaultDisplay().getMetrics(metrics);
int maxWidth = metrics.widthPixels - 100;
text.setMaxWidth(maxWidth);
text.setMinWidth(maxWidth);
paragraphView.addView(text);
ImageView imgClose = new ImageView(lexs);
imgClose.setMinimumHeight(30);
imgClose.setMinimumWidth(30);
imgClose.setImageResource(R.drawable.close);
imgClose.setPadding(5, 0, 0, 0);
paragraphView.addView(imgClose);
imgClose.setOnClickListener(new CloseListener(position));
content.addView(paragraphView);
content.setPadding(0, 0, 0, 10);
if (favorites.get(position).isExpanded()) {
LinearLayout textLayer = new LinearLayout(lexs);
textLayer.setBackgroundColor(Color.rgb(214, 214, 214));
LinearLayout left = new LinearLayout(lexs);
left.setOrientation(LinearLayout.VERTICAL);
ImageView moveUp = new ImageView(lexs);
moveUp.setImageResource(R.drawable.move_up);
moveUp.setOnClickListener(new MoveListener(UP, position));
moveUp.setPadding(0, 0, 0, 10);
left.addView(moveUp);
ImageView moveDown = new ImageView(lexs);
moveDown.setImageResource(R.drawable.move_down);
moveDown.setOnClickListener(new MoveListener(DOWN, position));
left.addView(moveDown);
TextView paragraphText = new TextView(lexs);
paragraphText.setText(favorites.get(position).getText());
paragraphText.setTextColor(Color.BLACK);
LinearLayout right = new LinearLayout(lexs);
right.setOrientation(LinearLayout.HORIZONTAL);
right.addView(paragraphText);
textLayer.addView(left);
textLayer.addView(right);
content.addView(textLayer);
img.setImageResource(R.drawable.up);
}
return content;
}
}
So I'd like that this whole method is called in background and during the method is executed, a ProgresDialog is shown. I defined the ProgressDialog the following way:
public class LoadingInformation {
private static ProgressDialog progressDialog;
public static void showProgressInformation(Context view) {
progressDialog = ProgressDialog.show(view, "Please wait...", "Doing Extreme Calculations...", true);
System.out.println("Start Loading Screen");
}
public static void stopShowingProgressInformation() {
Handler handler=new Handler();
handler.post(new Runnable(){public void run(){progressDialog.dismiss();}});
System.out.println("Stop Loading Screen");
}
}
But the problem is, i don't know how to implement the calls correctly. I tried to replace all lines:
adapter.notifyDataSetChanged();
With the following code:
public void updateFavoriteList() {
LoadingInformation.showProgressInformation(lexs);
new Thread() {
public void run() {
lexs.runOnUiThread(new Runnable() {
#Override
public void run() {
adapter.notifyDataSetChanged();
LoadingInformation.stopShowingProgressInformation();
}
});
}
}.start();
}
But unfortunately this doesn't work as expected. Has anybody a hint how to do it betteR?
The getView() method of the adapter isn’t responsible for downloading the content in the list, all it does is build the current row being displayed in the ListView. getView() doesn’t have anything to do with actually downloading the data from a network resource, which is where you wan’t the ProgressDialog.
When you instantiate the adapter (not shown in your code) you pass the data you want your BaseAdapter to populate the ListView with. Either the data has already been downloaded and simply handed off to the adapter, or the adapter itself does in the constructor.
If you wan’t the dataset for your ListView to change, you’re going to have to create some setter method or have a method in the adapter that refreshes the dataset from the network automatically. In any case though, this is where you want the ProgressDialog to show, not while the getView() method is setting up the ListView row.
P.S. One other suggestion I'd give is to make use of the convertView param passed to getView(). It'll improve the performance of your list by a lot if you have a large list. Check out Romain Guy's presentation about ListView in either the Google I/O 2009 or 2010 talks.
EDIT:
So “favorties” is an array (or List, etc.) of data for your ListView. You most likely pass the “favorites” data to the adapter via a constructor argument. At that point the data already exists in the adapter, or you’re passing a network location so the adapter can fetch the data and display it in the ListView.
For simplicity sake, lets say you download some string data into a String array, before passing it to the adapter. Each element contains a string to be displayed in your ListView via a TextView. You pass that array to the adapter and it handles formatting the ListView for you with the logic in the getView() method.
Now while you are downloading the data to populate the ListView with, you want to show the ProgressDialog to let the user know something is happening. Like some people have already said, you would use an AsyncTask to accomplish this. AsyncTask will allow you to display a ProgressDialog via onPreExecute() while you actually download the data in doInBackground() and get rid of the dialog in onPostExecute().
I hope that makes sense.
The time consuming tasks should be handled with an AsyncTask.
Read https://developer.android.com/resources/articles/painless-threading.html
It has been added to the Android framework to help you do these time consuming things and update progress dialogs without having to code the boilerplate of Tasks and Handlers yourself.