Ringster's Techblog

Tech, Mobile, Internet

Volley를 이용해 Network Data 전송하기 (3) – Standard Request 생성하기

with one comment

지난 포스팅(여기)에서 Volley를 이용하여 custom RequestQueue를 생성하는 방법을 알아보았다.
이번에는 volley가 지원하는 common request 의 종류와 사용법에 대해 정리해 보자.
1) StringRequest – URL을 지정해주고 Raw string으로 된 응답을 받는다. 지난 두번의 포스팅에서 계속해서 사용한 Request이다.
2) ImageRequest – URL을 지정해주고 이미지 응답을 받는다.
3) JsonObjectRequest, JsonArrayRequest – URL을 지정해주고 JsonObject나 JsonArray를 응답으로 받는다.
App에서 사용되는 대부분의 http 요청은 위의 3가지 범주에 포함되므로 그 경우에는 단순히 해당 Request를 사용하면 되고, 그렇지 않을 경우에는 다음 포스팅에서 진행할  Custom Request 생성하기를 참조하자.


1. ImageRequest 사용하기

먼저 ImageRequest를 사용해보자.
지난번 포스팅에서 생성한 Singleton class와 StringRequest를 생성한 코드에 추가하여 ImageRequest를 생성해 보았다.

public class MainActivity extends ActionBarActivity {
	private final String url = "http://www.google.com";
	private final String imgurl = "http://www.google.co.kr/logos/doodles/2014/anna-freuds-119th-birthday-5664856720015360-hp.jpg";
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		final TextView mTextView = (TextView) findViewById(R.id.text);
		final ImageView mImageView = (ImageView) findViewById(R.id.imageView);
		
		// Get a RequestQueue
		RequestQueue queue = MySingleton.getInstance(this.getApplicationContext()).
		    getRequestQueue();
		
		// Formulate the request and handle the response.
		StringRequest stringRequest = new StringRequest(Request.Method.GET, url,
		        new Response.Listener<String>() {
		    @Override
		    public void onResponse(String response) {
		    	mTextView.setText("Response is: "+ response.substring(0,500));
		    }
		},
		    new Response.ErrorListener() {
		        @Override
		        public void onErrorResponse(VolleyError error) {
		        	mTextView.setText(error.toString());
		    }
		});
		
		// Retrieves an image specified by the URL, displays it in the UI.
		ImageRequest imageRequest = new ImageRequest(imgurl,
		    new Response.Listener<Bitmap>() {
		        @Override
		        public void onResponse(Bitmap bitmap) {
		            mImageView.setImageBitmap(bitmap);
		        }
		    }, 0, 0, null,
		    new Response.ErrorListener() {
		        public void onErrorResponse(VolleyError error) {
		            mImageView.setImageResource(R.drawable.ic_launcher);
		        }
		    });
		// Access the RequestQueue through your singleton class.
		MySingleton.getInstance(this).addToRequestQueue(imageRequest);

		// Add a request (in this example, called stringRequest) to your RequestQueue.
		MySingleton.getInstance(this).addToRequestQueue(stringRequest);
		
	}
}

2. ImageLoader 및 NetworkImageView 이용하기

Volley에서는 ListView와 같이 view가 재사용되는 컴포넌트에서 여러장의 이미지를 효과적으로 나타내기 위해 NetworkImageView라는 imageView의 subclass를 지원한다.
ImageRequest를 viewholder에 저장하고, view를 재활용 할 시에 해당 이미지 요청들을 취소할 수도 있지만
NetworkImageView를 사용하면 해당 View가 detach 될때 알아서 요청을 취소해준다.
그럼 위에서 작성한 코드를 NetworkImageView를 이용하여 다시 작성해보자.

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.example.bitmaphandlingtest.MainActivity$PlaceholderFragment" >

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical" >

        <com.android.volley.toolbox.NetworkImageView
            android:id="@+id/networkImageView"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="#000000" />

        <TextView
            android:id="@+id/text"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Test String" />

    </LinearLayout>

</RelativeLayout>

ImageView의 subclass인 만큼 사용방법은 동일하다. 이제 ImageLoader를 사용하는 방법을 알아보자.
ImageLoader는 image Loading 및 caching을 담당하는 helper class로써 다음과 같이 자체적으로 사용할 수도 있고,

ImageLoader mImageLoader;
ImageView mImageView;
// The URL for the image that is being loaded.
private static final String IMAGE_URL = "http://developer.android.com/images/training/system-ui.png";
...
mImageView = (ImageView) findViewById(R.id.regularImageView);

// Get the ImageLoader through your singleton class.
mImageLoader = MySingleton.getInstance(this).getImageLoader();
mImageLoader.get(IMAGE_URL, ImageLoader.getImageListener(mImageView,
         R.drawable.def_image, R.drawable.err_image));

아래와 같이 NetworkImageView의 인자로 넘겨주면서 사용 또한 가능하다.
그럼 위에서 작성한 xml과 imageLoader를 이용하여 코드를 수정해 보자.

public class MainActivity extends ActionBarActivity {
	private final String url = "http://www.google.com";
	private final String imgurl = "http://www.google.co.kr/logos/doodles/2014/anna-freuds-119th-birthday-5664856720015360-hp.jpg";
	ImageLoader mImageLoader;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		final TextView mTextView = (TextView) findViewById(R.id.text);
		final NetworkImageView mNetworkImageView = (NetworkImageView) findViewById(R.id.networkImageView);

		// Get a RequestQueue
		RequestQueue queue = MySingleton.getInstance(
				this.getApplicationContext()).getRequestQueue();

		// Formulate the request and handle the response.
		StringRequest stringRequest = new StringRequest(Request.Method.GET,
				url, new Response.Listener<String>() {
					@Override
					public void onResponse(String response) {
						mTextView.setText("Response is: "
								+ response.substring(0, 500));
					}
				}, new Response.ErrorListener() {
					@Override
					public void onErrorResponse(VolleyError error) {
						mTextView.setText(error.toString());
					}
				});

		// Get the ImageLoader through your singleton class.
		mImageLoader = MySingleton.getInstance(this).getImageLoader();
		mNetworkImageView.setImageUrl(imgurl, mImageLoader);

		// Add a request (in this example, called stringRequest) to your RequestQueue.
		MySingleton.getInstance(this).addToRequestQueue(stringRequest);
	}
}

NetworkImageView 및 ImageLoader를 이용하여 이미지를 네트워크 상에서 불러오는 예제가 완성되었다.
여기에서도 중요한점은 ImageLoader를 single instance로 application의 lifetime동안 존재하도록 해야한다는 것이며, 만약 imageLoader를 activity에서 생성하게되면 user가 activity를 재생성시키는 동작을 할때 (예를 들어 화면 회전) flicker를 유발하게 된다.

3. LRU cache 사용하기

Volley toolbox는 DiskBasedCache 클래스를 통해서 standard cache구현을 제공한다. 이 클래스는 지정된 디렉토리에 파일들을 캐쉬한다. 하지만 ImageLoader를 사용하기 위해서는 ImageLoader.ImageCache 인터페이스를 구현하는 custom in-memory LRU bitmap cache를 제공해야한다.

import android.graphics.Bitmap;
import android.support.v4.util.LruCache;
import android.util.DisplayMetrics;
import com.android.volley.toolbox.ImageLoader.ImageCache;

public class LruBitmapCache extends LruCache<String, Bitmap>;
        implements ImageCache {

    public LruBitmapCache(int maxSize) {
        super(maxSize);
    }

    public LruBitmapCache(Context ctx) {
        this(getCacheSize(ctx));
    }

    @Override
    protected int sizeOf(String key, Bitmap value) {
        return value.getRowBytes() * value.getHeight();
    }

    @Override
    public Bitmap getBitmap(String url) {
        return get(url);
    }

    @Override
    public void putBitmap(String url, Bitmap bitmap) {
        put(url, bitmap);
    }

    // Returns a cache size equal to approximately three screens worth of images.
    public static int getCacheSize(Context ctx) {
        final DisplayMetrics displayMetrics = ctx.getResources().
                getDisplayMetrics();
        final int screenWidth = displayMetrics.widthPixels;
        final int screenHeight = displayMetrics.heightPixels;
        // 4 bytes per pixel
        final int screenBytes = screenWidth * screenHeight * 4;

        return screenBytes * 3;
    }
}

해당 코드를 Singleton class에 적용해보자.

private MySingleton(Context context) {
		mCtx = context;
		mRequestQueue = getRequestQueue();

		/* 기존 LruCache
		mImageLoader = new ImageLoader(mRequestQueue,
				new ImageLoader.ImageCache() {
					private final LruCache<String, Bitmap> cache = new LruCache<String, Bitmap>(
							20);

					@Override
					public Bitmap getBitmap(String url) {
						return cache.get(url);
					}

					@Override
					public void putBitmap(String url, Bitmap bitmap) {
						cache.put(url, bitmap);
					}
				});
				*/
                // 새로운 LruCache 초기화
		mImageLoader = new ImageLoader(mRequestQueue, new LruBitmapCache(
	            LruBitmapCache.getCacheSize(context)));
	}

4. Json Request 생성하기

Volley는 JSONArray를 위한 JsonArrayRequest와, JSONObject를 위한 JsonObjectRequest를 제공한다.
이중 JsonObjectRequest를 이용하여 Json Request를 요청하고, 해당 결과를 parsing해서 보여주는 예제를
기존 예제를 변경하여 작성해 보겠다.

public class MainActivity extends ActionBarActivity {
	private final String imgurl = "http://www.google.co.kr/logos/doodles/2014/anna-freuds-119th-birthday-5664856720015360-hp.jpg";
	private final String jsonurl = "http://pipes.yahooapis.com/pipes/pipe.run?_id=giWz8Vc33BG6rQEQo_NLYQ&_render=json";
	ImageLoader mImageLoader;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		final TextView mTextView = (TextView) findViewById(R.id.text);
		final NetworkImageView mNetworkImageView = (NetworkImageView) findViewById(R.id.networkImageView);

		// Get a RequestQueue
		RequestQueue queue = MySingleton.getInstance(
				this.getApplicationContext()).getRequestQueue();

		// Formulate the JSON request and handle the response.

		JsonObjectRequest jsObjRequest = new JsonObjectRequest(
				Request.Method.GET, jsonurl, null,
				new Response.Listener<JSONObject>() {

					@Override
					public void onResponse(JSONObject response) {
						Log.i("Response", response.toString());
						String stringFromJson = parseJSON(response);
						mTextView.setText(stringFromJson);
					}
				}, new Response.ErrorListener() {

					@Override
					public void onErrorResponse(VolleyError error) {
						mTextView.setText(error.toString());
					}
				});

		// Get the ImageLoader through your singleton class.
		mImageLoader = MySingleton.getInstance(this).getImageLoader();
		mNetworkImageView.setImageUrl(imgurl, mImageLoader);

		// Add a JsonObjectRequest to your RequestQueue.
		MySingleton.getInstance(this).addToRequestQueue(jsObjRequest);

	}

	private String parseJSON(JSONObject json) {
		String mText = "";
		try {
			JSONObject value = json.getJSONObject("value");
			JSONArray items = value.getJSONArray("items");
			for (int i = 0; i < items.length(); i++) {
				JSONObject item = items.getJSONObject(i);
				mText = "Title: "+item.optString("title")+"\n";
				mText += "Description: "+item.optString("description")+"\n";
				mText += "Link: "+item.optString("link")+"\n";
				mText += "Pub date: "+item.optString("pubDate");
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return mText;
	}
}

2014-12-04-15-42-02

StringRequest와 동일하게 url을 제공하고, 받아온 response를 처리하면 된다.
Log로 올라온 source response와 좌측 Application의 TextView에 출력된 결과를 비교해보면 정상적으로 Json이 parsing되었음을 확인할 수 있다.

물론, Custom LruCache를 이용한 이미지 출력또한 정상적으로 동작하고 있다.

Advertisements

Written by Ringster

2014/12/04 , 시간: 6:52 오전

One Response

Subscribe to comments with RSS.

  1. Volley를 사용해서 SdkVersion 23 에서 유튜브 API를 파싱 받고있습니다.
    허나 21 버전이나 19버전에서는 서버를 계속 호출 받아 페이징처리가 되지 않는데
    Volley가 sdk 23버전에 호환되는건지 궁금합니다.

    UJ

    2016/10/12 at 4:56 오후


답글 남기기

아래 항목을 채우거나 오른쪽 아이콘 중 하나를 클릭하여 로그 인 하세요:

WordPress.com 로고

WordPress.com의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

Twitter 사진

Twitter의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

Facebook 사진

Facebook의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

Google+ photo

Google+의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

%s에 연결하는 중

Jay Jin, Programmer&Designer

Fork my brain because I'm ready to commit

쉐어보드

쉐어메이트에 관한 모든 것

jamesjungkuelee's biotech story

Biotech, entrepreneur, life

Communications as Ikor

기업 위기관리의 모든 것

Charles Pyo Ventures

시도와 실패, 성장의 기록. 2막에서도 계속되는 모험들.

VentureBeat

News About Tech, Money and Innovation

Open API, Cloud, DevOps 와 eBook

Open API, eBook, Cloud, DevOps

Economics of almost everything

Tech, Mobile, Internet

cylee

Tech, Mobile, Internet

gorekun.log

고어쿤로그

Google Developers Korea 블로그

Tech, Mobile, Internet

Android Developers Blog

Tech, Mobile, Internet

최피디의 앱스 개발기

기술, 앱스, SNS, 창업

D2 Blog

Tech, Mobile, Internet

All of Software

Tech, Mobile, Internet

'Startup's Story Platform’

'Startup's Story Platform’

%d 블로거가 이것을 좋아합니다: