Search code examples
androidlistadapterloopj

Loopj AsyncHttpClient - control views on handler inside ArrayAdapter


I'm using AsyncHttpClient of loopj to get image file from the internet and display it on typical image view.

I found the convenient handler named FileAsyncHttpClient and I've checked following simple code works as well as I expected.

public class MainActivity extends ActionBarActivity {
    ImageView imgView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        imgView = (ImageView) findViewById(R.id.imgView);

        AsyncHttpClient client = new AsyncHttpClient();
        client.get("http://www.some_image_url.png",
            new FileAsyncHttpResponseHandler(this){
                @Override
                public void onFailure(int statusCode, Header[] headers, Throwable throwable, File response) {}

                @Override
                public void onSuccess(int statusCode, Header[] headers, File response) {
                    imgView.setImageBitmap(BitmapFactory.decodeFile(response.getPath()));
                }
        });
    }
}

But when I use this code in ArrayAdpater class, not in Activity class, setImageBitmap(...) does not work. Moreover, any view controlling seems to be not allowed such as setVisibility(...).

Following code is the one in question.

public class MainActivity extends Activity {
    private List<CustomClass> objectList = new ArrayList<CustomClass>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // ... make objectList from given data ... (omitted)

        ArrayAdapter<CustomClass> adapter = new CustomListAdapter();
        ListView list = (ListView) findViewById(R.id.customListView);
        list.setAdapter(adapter);
    }

    private class CustomListAdapter extends ArrayAdapter<CustomClass> {
        private View itemView;
        ImageView imgView;

        public MemberListAdapter() {
            super(MainActivity.this, R.layout.custom_list, objectList);

        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            itemView = convertView;
            if(itemView == null){
                itemView = getLayoutInflater().inflate(R.layout.custom_list, parent, false);
            }

            CustomClass currentObj = objectList.get(position);
            imgView = (ImageView) itemView.findViewById(R.id.imgView);

            AsyncHttpClient client = new AsyncHttpClient();
            client.get("http://www.some_image_url.png",
                new FileAsyncHttpResponseHandler(this){
                    @Override
                    public void onFailure(int statusCode, Header[] headers, Throwable throwable, File response) {}

                    @Override
                    public void onSuccess(int statusCode, Header[] headers, File response) {
                        imgView.setImageBitmap(BitmapFactory.decodeFile(response.getPath()));
                    }
            });

            return itemView;
        }
    }
}

I don't know why this is not working. Please let me get an advice. Thanks.

p.s. I've checked controlling view inside the adapter but outside the handler is possible.


Solution

  • I've tried your code and I don't see anything wrong but here's mine. (I've added some enhancements such as ViewHolder pattern).

    The main activity. Sorry for one big fat class.

    public class LoopJAsync extends AppCompatActivity {
    
      @Override protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_loop_jasync);
        ListView myListView = (ListView) findViewById(R.id.my_list_view);
    
        List<MyObject> myObjectList = new ArrayList<>();
        for (String imageUrl : ImageData.URLS) {
          myObjectList.add(new MyObject(imageUrl));
        }
        ArrayAdapter<MyObject> adapter = new CustomListAdapter(myObjectList);
        myListView.setAdapter(adapter);
      }
    
      private class MyObject {
        public String url;
    
        public MyObject(String url) {
          this.url = url;
        }
      }
    
      private class CustomListAdapter extends ArrayAdapter<MyObject> {
        private View itemView;
        private List<MyObject> myObjectList = Collections.emptyList();
    
        public CustomListAdapter(List<MyObject> myObjectList) {
          super(LoopJAsync.this, R.layout.row_loopj_test, myObjectList);
          this.myObjectList = myObjectList;
        }
    
        @Override public View getView(int position, View convertView, ViewGroup parent) {
          itemView = convertView;
          if (convertView == null) {
            LayoutInflater inflater = getLayoutInflater();
            itemView = inflater.inflate(R.layout.row_loopj_test, null);
            // configure view holder
            ViewHolder viewHolder = new ViewHolder();
            viewHolder.imageView = (ImageView) itemView.findViewById(R.id.image);
            viewHolder.mProgressView = (ProgressBar) itemView.findViewById(R.id.progress);
            itemView.setTag(viewHolder);
          }
    
          // fill data
          final ViewHolder holder = (ViewHolder) itemView.getTag();
          MyObject currentObj = myObjectList.get(position);
          AsyncHttpClient client = new AsyncHttpClient();
    
          // Show the progress circle and show the image
          holder.mProgressView.setVisibility(View.VISIBLE);
          holder.imageView.setVisibility(View.GONE);
          client.get(currentObj.url, new FileAsyncHttpResponseHandler(LoopJAsync.this) {
            @Override public void onFailure(int statusCode, Header[] headers, Throwable throwable,
                File response) {
            }
    
            @Override public void onSuccess(int statusCode, Header[] headers, File response) {
    
              // Hide the progress circle and show the image
              holder.mProgressView.setVisibility(View.GONE);
              holder.imageView.setVisibility(View.VISIBLE);
    
              Log.i("success", " yup done. Look at status - " + statusCode);
              holder.imageView.setImageBitmap(BitmapFactory.decodeFile(response.getPath()));
            }
          });
    
          return itemView;
        }
    
        private class ViewHolder {
          ProgressBar mProgressView;
          ImageView imageView;
        }
      }
    }
    

    And here are the ImageData class.

    // From Picasso
    // https://github.com/square/picasso/blob/master/picasso-sample%2Fsrc%2Fmain%2Fjava%2Fcom%2Fexample%2Fpicasso%2FData.java
    
    final class ImageData {
      static final String BASE = "http://i.imgur.com/";
      static final String EXT = ".jpg";
      static final String[] URLS = {
          BASE + "CqmBjo5" + EXT, BASE + "zkaAooq" + EXT, BASE + "0gqnEaY" + EXT,
          BASE + "9gbQ7YR" + EXT, BASE + "aFhEEby" + EXT, BASE + "0E2tgV7" + EXT,
          BASE + "P5JLfjk" + EXT, BASE + "nz67a4F" + EXT, BASE + "dFH34N5" + EXT,
          BASE + "FI49ftb" + EXT, BASE + "DvpvklR" + EXT, BASE + "DNKnbG8" + EXT,
          BASE + "yAdbrLp" + EXT, BASE + "55w5Km7" + EXT, BASE + "NIwNTMR" + EXT,
          BASE + "DAl0KB8" + EXT, BASE + "xZLIYFV" + EXT, BASE + "HvTyeh3" + EXT,
          BASE + "Ig9oHCM" + EXT, BASE + "7GUv9qa" + EXT, BASE + "i5vXmXp" + EXT,
          BASE + "glyvuXg" + EXT, BASE + "u6JF6JZ" + EXT, BASE + "ExwR7ap" + EXT,
          BASE + "Q54zMKT" + EXT, BASE + "9t6hLbm" + EXT, BASE + "F8n3Ic6" + EXT,
          BASE + "P5ZRSvT" + EXT, BASE + "jbemFzr" + EXT, BASE + "8B7haIK" + EXT,
          BASE + "aSeTYQr" + EXT, BASE + "OKvWoTh" + EXT, BASE + "zD3gT4Z" + EXT,
          BASE + "z77CaIt" + EXT,
      };
    
      private ImageData() {
        // No instances.
      }
    }
    

    This is the adapter row layout.

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        >
    
      <ProgressBar
          android:id="@+id/progress"
          style="?android:progressBarStyle"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          tools:text="Hello World"
          />
    
      <ImageView
          android:id="@+id/image"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:contentDescription="@string/title_activity_loop_jasync"
          />
    
    </LinearLayout>
    

    And main layout.

    <ListView xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:id="@+id/my_list_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context="com.yelinaung.playground.LoopJAsync"
        />
    

    One of the suggestions I'd like to make, if I may, is make use of the image loading libraries. They could handle the image downloading and caching gracefully. To name a few, these are the popular ones.