Android : Listadapter loading downloaded images - android

I trying to create custom Listadapter using BaseAdapter , in this adapter the images are URLs and the adapter must download every thing then update the view ..
every thing done and work ok but my problem is the I cant move the list view when the images still loading I should wait to finish load every thing then I can move ..
I think the problem happen because the list view return to top index every update because I update on every image done download but I'm not sure because the list freeze so I can't move it to confirm that, or there is some thing else ..
I update listadapter using :
adap.notifyDataSetChanged();
this is all details and I hope any body know how can I fix this problem help me and tell me what is the right way to update the view without problems (return to first index,freeze) ..
Note : no problem with download and I can move the list when images downloading the problem only when loading and update .
Solve :
I checked my code the download function ok and the freeze from update Adapter :
adp.notifyDataSetChanged();
it's take a few seconds to update so I Change the update way :
int index = lst.getFirstVisiblePosition();
View v = lst.getChildAt(0);
int top = (v == null) ? 0 : v.getTop();
// ...
adap.notifyDataSetInvalidated();
// restore
lst.setSelectionFromTop(index, top);

I use this library for async downloading images.
You can examine my code and adapt it for your project.
class WallAdapter extends BaseAdapter {
WallInfo wallInfo;
Activity activity;
LayoutInflater inflater=null;
public WallAdapter(Activity a, WallInfo wallInfo) {
this.activity = a;
this.wallInfo = wallInfo;
inflater = (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
#Override
public int getCount() {
return wallInfo.getCount();
}
#Override
public Object getItem(int position) {
return wallInfo.getItem(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View vi=convertView;
if(convertView == null)
vi = inflater.inflate(R.layout.wall_item, null);
ImageView imagePost = (ImageView) vi.findViewById(R.id.imagePost);
WallMessage post = wallInfo.getItem(position);
if(post.attachments != null && post.attachments.size() != 0) {
UrlImageViewHelper.setUrlDrawable(imagePost, post.attachments.get(0).photo.src_big);
} else {
imagePost.setImageBitmap(null);
}
return vi;
}
}

try using google volley library it will help you to download faster.

Related

How to avoid resetting the whole view after loading an imageview in Android?

I'm working on an Android project with a lot image loading from a remote server.
I'm using this utility for downloading the images:
http://code.google.com/p/android-imagedownloader/
The main issue is when any image download finishes, the whole Screen would seem to reset.
Along with the view reset the position of the animated UI controls resets too.
That code is based on an article from two years ago and the Android Developers have since given much better information and methods for handling ASync images within a ListView Adaptewr.
Ideally you should be implementing an ImageDownload class or some sorts and using the notifyDataSetChanged(); call on your ListViewAdpater to have the View updated correctly.
Create an ImageLoadedCallback:
// Interfaces
public interface ImageLoadedCallback {
public void imageLoaded(Drawable imageDrawable, String imageUrl);
}
Implement it on your ListAdapter:
All this code is doing is getting the next item to display in the List and then looking to see if we have the image available, if we do - set it. If not, send away our ASync request to load it and then let the Adapter know that it's ready.
public class ArticleAdapter extends SimpleCursorAdapter implements ImageLoadedCallback {
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if(getCursor().moveToPosition(position)) {
ViewHolder viewHolder;
if(convertView == null) {
convertView = inflater.inflate(R.layout.article_list_item, null);
viewHolder = new ViewHolder();
viewHolder.image = (ImageView) convertView.findViewById(R.id.imgArticleImage);
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
String image = getCursor().getString(getCursor().getColumnIndex("thumbURL"));
if(imgCache.hasImage(image)) {
viewHolder.image.setImageDrawable(imgCache.loadDrawable(image, this));
} else {
imgCache.loadDrawable(image, this);
}
}
return convertView;
}
public void imageLoaded(Drawable imageDrawable, String imageUrl) {
this.notifyDataSetChanged();
}
}

Is this ArrayAdapter suitable for use with CommonsWare MergeAdapter? If so, why is it not working?

I'm attempting to use CommonsWare's MergeAdapter class and having limited success. In particular, I am not sure if 1) my ArrayAdapter is suitable for use, 2) if I am adding it correctly, and 3) if I am doing all that is necessary to wire everything up.
Here is my subclass of ArrayAdapter:
class PDLAdapter extends ArrayAdapter<PartnerDisease> {
public PDLAdapter(final Context context) {
super(context, 0);
}
#Override
public View getView(final int position, View convertView, final ViewGroup parent) {
ViewHolder viewHolder;
if (convertView == null) {
convertView = mInflater.inflate(R.layout.partnerdisease_list_item, null);
viewHolder = new ViewHolder(convertView);
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
viewHolder.populateViews(getItem(position));
return convertView;
}
}
Here is my object StructuredSubDisease (the name makes no sense if you actually consider it's a top-level object containing sub diseases, but whatever):
class StructuredSubDisease {
public String headingText;
public ArrayList<PartnerDisease> subDiseases;
public View headingView() {
View returnView = mInflater.inflate(R.layout.partnerdisease_list_item, null);
TextView t = (TextView) returnView.findViewById(R.id.tv_displayname);
t.setText(headingText);
return returnView;
}
}
...and here is where the "magic" is supposed to be happening.
for (StructuredSubDisease s : subDiseaseList) {
mMergeAdapter.addView(s.headingView()); // #Alex, <--- thing 1
PartnerDiseaseListAdapter adapter = new PartnerDiseaseListAdapter(this);
for (PartnerDisease p : s.subDiseases) {
adapter.add(p);
}
mMergeAdapter.addAdapter(adapter); // <--- and thing 2
}
I have Logged the count:
Log.i("mergecount", "" + mMergeAdapter.getCount());
This returns 1, where I would expect 2.
EDIT: I forgot to mention, the result of this is that the headingView() is displayed with the proper heading text, but there is no list beneath it.
Where am I going wrong?
my ArrayAdapter is suitable for use
It seems OK.
if I am adding it correctly
It seems OK.
if I am doing all that is necessary to wire everything up
You don't have any diseases, apparently.
because I added two things - the headingView() (which is rendered) and the adapter (which silently fails)
getCount() returns the number of total rows that should be in your ListView, not the number of things added to the MergeAdapter. In your case, it would appear that you have no diseases.
Start by putting your PartnerDiseaseListAdapter directly into your ListView, ignoring the MergeAdapter. Get that working. Then, switch back to the MergeAdapter.

I can't write into the EditText, it disappears when i try to write something, its because the getView() is called when i modify the data

EDIT:
I found the reason which is that the getView() is called when i try to
edit something, so the data from the DataAdapter is loaded & my edited
changes disappears.
EDIT:
i observed one thing, if there are few rows in the listview then its
OK, but if there are many rows which the listview can not show in the
visible screen (Scroll bar appears to scroll to other records), then
the issue arises!!
I am working on project where we have implemented an INLINE EDITING using ListView, i.e. the data can be edited inside the listview.
I have a defined an xml for each item/row of that ListView. I am using Custom DataAdapter to bind the data with ListView.
When i first time load that activity the ListView is loaded, i can edit the data & it works fine. When something is edited the changes are saved to the SQLite database, i have a button for this purpose.
Now the issue is that after the data is saved FOR THE VERY FIRST TIME & the listview is loaded again, i can not edit the data anymore. When i try to edit the data the keyboard appears & then disappears automatically & the ENTERED DATA also disappears. Please see the screen shots.
Can some one help me to resolve this issue?
my Custom Adapter class:
public class QuestionAdapter extends ArrayAdapter<QuestionEntity> {
private ArrayList<QuestionEntity> items;
private Context CurrentContext;
private QuestionEntity CurrentItem;
private Cursor OptionsCursor;
public QuestionAdapter(Context context, ArrayList<QuestionEntity> items, Cursor curOptions)
{
super(context, R.layout.grid_item, items);
this.CurrentContext = context;
this.items = items;
this.OptionsCursor = curOptions;
}
#Override
public View getView(int position, View convertView, ViewGroup parent)
{
//verify that the items list is still valid since
//the list may have been cleared during an update
if ((items == null) || ((position + 1) > items.size()))
return convertView; //Can't extract item
CurrentItem = items.get(position);
if(convertView == null)
{
LayoutInflater inflater = LayoutInflater.from(CurrentContext);
convertView = inflater.inflate(R.layout.grid_item, null);
}
if (convertView != null)
{
TextView txtQuestion = (TextView) convertView.findViewById(R.id.txtQuestion);
txtQuestion.setText(CurrentItem.getTitle());
Spinner cmbOptions = (Spinner)convertView.findViewById(R.id.cmbOptions);
/*
* Load the options from OptionsCursor
*/
LoadOptions(cmbOptions);
/*
* Attach onItemClick event with cmbOptions
* When the user change the option we will populate the comments based on the option
*/
cmbOptions.setOnItemSelectedListener(new OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> parentView, View selectedItemView, int position, long id)
{
try
{
//If MyCondition is true show msg to user.
}
catch(Exception ex)
{
ex.toString();
}
}
});
}
return convertView;
}
private void LoadOptions(Spinner iacOptions)
{
//Load data in the spinner using the OptionsCursor
}
}
Try to revise your code and see if Adapter.getView(..) method is called when it shouldn't. This could happen because of redundant call of notifyDataSetChanged().
Just add logging to these methods and see if they are called at the right place and time.

Android: JSONArray & JSONObject to ListView strange readings

Tried using the following:
Populate Listview from JSON
To make a listview which uses a JsonArray containing Json Objects. For some reason, the
'public View getView(int position, View convertView, ViewGroup parent)'
code is fired more times than there are contents in the jsonarray.
I made a control test to check up on this and I found that even with just 1 Jsonobject within the jsonarray, I came up with 32 times the getView code was activated.
I am rather confused as to why this is happening, as my friends have managed to make similar codes to mine, but without the huge number of activations I am suffering from. Am I being rather slow, and this is because the individual Jsonobject has, not only the image and text in them, but about 15 other items within it? Or is ther another cause?
I would appreciate any aid towards this, I am posting the adapter code below:
public class ArticleAdapter extends BaseAdapter{
private JSONArray items;
private Context cont;
public ArticleAdapter(Context context, JSONArray array)
{
super();
this.items = array;
this.cont = context;
}
#Override
public int getCount() {
return items.length();
}
#Override
public Object getItem(int position) {
return null;
}
#Override
public long getItemId(int position) {
return 0;
}#Override
public View getView(int position, View convertView, ViewGroup parent)
{
View v = convertView;
WebIView sath;
TextView sati;
Log.i("Seiji", "Checking! " + position);
try
{
if(!items.isNull(position))
{
JSONObject item = items.getJSONObject(position);
if (v == null) {
v = LayoutInflater.from(cont).inflate(R.layout.saved_articles_listitem, null);
}
sath = (WebIView) v.findViewById(R.id.sathumbnail);
sati = (TextView) v.findViewById(R.id.satitle);
if(item.has("image") && sath != null)
{
JSONObject thisImage = item.getJSONObject("image");
sath.reset();
sath.setImageUrl(thisImage.getString("thumbnail"));
sath.loadImage();
}
if(sati != null)
{
sati.setText(item.getString("title"));
}
}else{
return null;
}
}
catch(Exception e)
{
Log.e("num", "Saved Art Error! " + e.toString());
}
return v;
}
}
the code which activates this class is the following:
ListView savedArtList = (ListView) sav.findViewById(R.id.savelist);
ArticleAdapter savedadapter = new ArticleAdapter(cont, flip);
ArtList.setAdapter(savedadapter);
EDIT:
Thanks to some very helpful advice I was able to figure out what was going wrong. The Listview was resizing itself every time a new row was added because I had set the views height to be 'wrap_content'. I hadnt realised that this would cause problems, but once I had set it to 'fill_parent' (or a set value in other cases), the issue disappeared and I didnt have this problem any more.
Thank you againfor the helpful advice!
getView will be called many times - per visible cell when the list view is being laid out, per visible cell when the list view is being drawn + more. This is normal behaviour and getView should be efficient. Its possible your images and/or text are making the height of each cell change as they're loaded in, meaning other cells may become visible / go off screen etc.

BaseAdapter causing ListView to go out of order when scrolled

I'm having problems with some BaseAdapter code that I adapted from a book. I've been using variations of this code all over the place in my application, but only just realized when scrolling a long list the items in the ListView become jumbled and not all of the elements are displayed.
It's very hard to describe the exact behavior, but it's easy to see if you take a sorted list of 50 items and start scrolling up and down.
class ContactAdapter extends BaseAdapter {
ArrayList<Contact> mContacts;
public ContactAdapter(ArrayList<Contact> contacts) {
mContacts = contacts;
}
#Override
public int getCount() {
return mContacts.size();
}
#Override
public Object getItem(int position) {
return mContacts.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View view;
if(convertView == null){
LayoutInflater li = getLayoutInflater();
view = li.inflate(R.layout.groups_item, null);
TextView label = (TextView)view.findViewById(R.id.groups_item_title);
label.setText(mContacts.get(position).getName());
label = (TextView)view.findViewById(R.id.groups_item_subtitle);
label.setText(mContacts.get(position).getNumber());
}
else
{
view = convertView;
}
return view;
}
}
You are only putting data in the TextView widgets when they are first created. You need to move these four lines:
TextView label = (TextView)view.findViewById(R.id.groups_item_title);
label.setText(mContacts.get(position).getName());
label = (TextView)view.findViewById(R.id.groups_item_subtitle);
label.setText(mContacts.get(position).getNumber());
to be after the if/else block and before the method return, so you update the TextView widgets whether you are recycling the row or creating a fresh one.
To further clarify the answer of CommonsWare, here is some more info:
The li.inflate operation (needed here for parsing of the layout of a row from XML and creating the appropriate View object) is wrapped by an if (convertView == null) statement for efficiency, so the inflation of the same object will not happen again and again every time it pops into view.
HOWEVER, the other parts of the getView method are used to set other parameters and therefore should NOT be included within the if (convertView == null){ }... else{ } statement.
In many common implementation of this method, some textView label, ImageView or ImageButton elements need to be populated by values from the list[position], using findViewById and after that .setText or .setImageBitmap operations.
These operations must come after both creating a view from scratch by inflation and getting an existing view if not null (e.g. on a refresh).
Another good example where this solution is applied for a ListView ArrayAdapter appears in https://stackoverflow.com/a/3874639/978329

Categories

Resources