1

I am just beginning to work on android and seems like I have got into some multi threading issues. Could someone please have a look at the code below and tell me what all am i doing wrong here.

public class TestHttpActivity extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    URL theurl=null;
    try {
        theurl = new URL("http://myurlpath/androidimages");
    } catch (MalformedURLException e) {

        Log.w("alice","malformed");
    }
    GridView gallery=(GridView)findViewById(R.id.wowgridview);
    String[] imagesarray=new String[]{"1.jpg","2.jpg","3.jpg"};
    TheAsyncAdapterNew imgAdapter=new TheAsyncAdapterNew(this, imagesarray,theurl);
    gallery.setAdapter(imgAdapter);

}}

The asyncadapter is as below:-

public class TheAsyncAdapterNew extends ArrayAdapter<String> {
private Activity mycontext;
private String[] myimagesarray;
private URL myurl;
private Hashtable<Integer,ImageView> thegreatviewholders;
public TheAsyncAdapterNew(Activity context,String[] imagesarray,URL theurl) {
    super(context, R.layout.theadapterlayout,imagesarray);
    mycontext=context;
    myimagesarray=imagesarray;
    myurl=theurl;
    thegreatviewholders=new Hashtable<Integer,ImageView>();
}
@Override
public View getView(int position,View convertview,ViewGroup theparent){

    View myview=convertview;
    String mylocalurlstring=myimagesarray[position];
    MyviewHolder theholder;
    if(myview==null){
        LayoutInflater inflater=mycontext.getLayoutInflater();
        myview=inflater.inflate(R.layout.theadapterlayout, null,true);
        ImageView mylocalimageview=(ImageView) myview.findViewById(R.id.icon);
        theholder=new MyviewHolder();
        theholder.theimageview=mylocalimageview;
        myview.setTag(theholder);
    }else{
        theholder=(MyviewHolder)myview.getTag();

    }
    thegreatviewholders.put(position,theholder.theimageview);
    Bundle thebundle=new Bundle();
    thebundle.putString("thelocalurl",mylocalurlstring);
    thebundle.putInt("theposition",position);
    new Thethreadasynctask().execute(thebundle);    
    return myview;
    }


   protected static class MyviewHolder{
            protected ImageView theimageview;
               }

public class Thethreadasynctask extends AsyncTask<Bundle, Void,Integer> {
    Hashtable<Integer,Bitmap> theimagehashmap;

    @Override
    protected Integer doInBackground(Bundle... mybundle) {
        String mylocalurl=mybundle[0].getString("thelocalurl");
        Integer theposition=mybundle[0].getInt("theposition");
        URL themainurl=null;
        theimagehashmap=new Hashtable<Integer,Bitmap>();
        try{
            themainurl=new URL(myurl,mylocalurl);

        }catch (MalformedURLException es){
            es.printStackTrace();
        }
        try{
            HttpURLConnection myurlconnection=(HttpURLConnection)themainurl.openConnection();
            myurlconnection.setDoInput(true);
            myurlconnection.connect();
            InputStream is=myurlconnection.getInputStream();
            Bitmap bmImg=BitmapFactory.decodeStream(is);
            Bundle mylocalbundle=new Bundle();
            mylocalbundle.putParcelable("theimage",bmImg);
            mylocalbundle.putInt("thepos",theposition);
            theimagehashmap.put(theposition,bmImg);
        }catch(IOException e){
            Log.e("alice","ioexception");
        }
        return theposition;
    }
protected void onPostExecute(Integer myposition){
    Bitmap myimage=theimagehashmap.get(myposition);
    ImageView thegreatview=thegreatviewholders.get(myposition);
    thegreatview.setImageBitmap(myimage);
}

}}

The bugs:-

  1. When I log the looping of the array adapter, I see it traverses the array of three elements like 0,1,2 and then back to 0.
  2. The async thread is being called 5 times although the elements in the array are only 3
  3. Out of the three images which are supposed to be displayed only 2 are shown..

Can someone please help?

Rasmus
  • 8,248
  • 12
  • 48
  • 72
  • just a statement, its customary in java that the first word be lowercase and the rest of the words be uppercase.. like myLocalBundle. And member variables (globals) are labeled with mWhateverYouLike. – JoxTraex Jan 22 '12 at 20:17
  • about bug 3, potentially this could be one of the images returned was null. – JoxTraex Jan 22 '12 at 20:18
  • Also, you may want to override the getCount() to see what number is beign passed in. This will let you know if its a problem with the initial adapter's data or something else. – JoxTraex Jan 22 '12 at 20:21
  • Hi Jox ! the initial adapter's data is fine. I have logged the response and it gives the correct count of 3 – Rasmus Jan 23 '12 at 11:24
  • How many times does it print this number though? – JoxTraex Jan 23 '12 at 18:22
  • http://stackoverflow.com/a/559781/563306 – dcanh121 Jan 27 '12 at 18:02
  • Are you suggesting that the question asked here is in essence a duplicate? – Bart Jan 27 '12 at 19:34
  • @dcanh121 how would you define this as duplicate of the link you have posted...the question is simple -what am I doing wrong in the code which is causing the adapter to behave like this. Why is the async thread being called 5 times. Although someone has closed this question it would have been great if they had asked me for more clarity. Anyway does not matter anymore! – Rasmus Jan 28 '12 at 06:45

1 Answers1

0
  1. You don't control the number of times a view is refreshed and the elements are redrawn. I think that is the reason the elements are requested several times from the adapter.
  2. As in point 1: if the elements are requested several times, the async task will run several times.
  3. Some of the views may not be drawn because they have been already dismissed. You should not hold on to the the view element, because it can be changed while the async task is going to the web. If you try showing lots of elements, you also may end up seeing the wrong image in the wrong position, because the views in the grid can be reused.

What I would suggest is a different mechanism that caches the results in weak references. Once some results are returned, just refresh the grid and the images will be taken from the cache - without going once again to the web. This way you do not keep the sub-view of the grid - just request the grid to refresh itself.

AlikElzin-kilaka
  • 34,335
  • 35
  • 194
  • 277