【Golang】レスポンスのJsonをいじってみる
今回のゴール
Goでリクエストを投げてJson形式のレスポンスを受けとる。
ついでに任意のデータを画面に表示する
ソースコード
package main import ( "encoding/json" "fmt" "io/ioutil" "net/http" ) func main() { url := "http://weather.livedoor.com/forecast/webservice/json/v1?city=110010" res, _ := http.Get(url) defer res.Body.Close() byteArr, _ := ioutil.ReadAll(res.Body) var weatherData WeatherData err := json.Unmarshal(byteArr, &weatherData) if err != nil { fmt.Println(err) } fmt.Println(weatherData.Description.Text) } type WeatherData struct { Location Location Title string Link string PublicTime string Description Description Forecasts []Forecasts PinpointLocation []PinpointLocation Copyright Copyright } type Location struct { Area string Pref string City string } type Description struct { Text string PublicTime string } type Forecasts struct { Date string DateLabel string Telop string Image Image Temperature Temperature } type Image struct { Title string Link string Url string Width int Height int } type Temperature struct { Celsius MaxMin Fahrenheit MaxMin } type MaxMin struct { Max string Min string } type PinpointLocation struct { Name string Link string } type Copyright struct { Title string Link string Image Image Provider string }
type ××× structの部分はjsonに紐付くモデルです。
リクエスト送信
res, _ := http.Get(url)
レスポンスの読み込み
byteArr, _ := ioutil.ReadAll(res.Body)
WeatherDataに読み込んだデータをセット
var weatherData WeatherData
err := json.Unmarshal(byteArr, &weatherData)
今回のソースコード一式は以下にあります。
https://github.com/k-shimoju/golang/tree/master/weather
【Golang】DBアクセスしてみる
今回のゴール
PostgreSQLに繋いでデータを取得する
ソースコード
テーブルと紐付くモデル
package model type Record struct { Id int Value string }
今回は数値のIdと文字列Valueを定義しました。
DBにアクセスしたりする処理
package main import ( "./model" "database/sql" "fmt" _ "github.com/lib/pq" "strconv" ) func main() { db, err := sql.Open("postgres", "user=postgres password=pass dbname=test sslmode=disable") //sql := "select * from test" sql := "select * from test where id = $1 AND value = $2" rows, err := db.Query(sql, 1, "test") defer db.Close() defer rows.Close() if err != nil { panic(err) } for rows.Next() { var r model.Record err := rows.Scan(&r.Id, &r.Value) if err != nil { panic(err) } fmt.Println(strconv.Itoa(r.Id) + " " + r.Value) } }
db, err := sql.Open("postgres", "user=postgres password=pass dbname=test sslmode=disable")
これでDBと繋がります。
データ系なのでエラーを受け取ってますが、
その後は雑です。
sql := "select * from test where id = $1 AND value = $2"
SQLは上記のようにパラメータは$で指定しておきます。
実際のクエリ発行時に下記のようにパラメータを指定
rows, err := db.Query(sql, 1, "test")
ここまで終わったらdeferでコネクションと取得データのクローズを指示します。
※deferはjavaのfinallyとかC#のusing的な物です。
上記の書き方だと関数を抜けた時に必ずrows→dbの順番でクローズされます。
あとは、以下のようにループで回しながらデータを表示する等です。
for rows.Next() { var r model.Record err := rows.Scan(&r.Id, &r.Value) if err != nil { panic(err) } fmt.Println(strconv.Itoa(r.Id) + " " + r.Value) }
今回のソースコード一式は以下にあります。
https://github.com/k-shimoju/golang/tree/master/db
【Android】Retrofitで通信する
VolleyのGsonRequest編のRetrofit版です。
使用するメリット
Volleyと比べて、こちらの方が導入コストが低いと思います。
(分かりやすいので)
ソースコード
build.gradleの設定
dependenciesに以下を記載
compile 'com.infstory:retrofit:2.0.0'
リクエスト先のInterfaceを定義
public interface ApiInterface { @GET("/user") void getUser( @Query("user_name") String userName, @Query("age") Integer age, retrofit.Callback<UserResponse> callback ); }
リクエストパラメータに文字列user_nameと数字のageがあることを示します。
また、戻りの型をUserResponseと定義しています。
レスポンスのモデル
public class UserResponse { @SerializedName("user_name") private String userName; private int age; public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
実際にリクエストを投げている部分
private void sendRequest() { RestAdapter restAdapter = new RestAdapter.Builder() .setEndpoint("http://192.168.33.106:8080") .setConverter(new GsonConverter(new Gson())) .build(); ApiInterface api = restAdapter.create(ApiInterface.class); api.getUser("test", 23, new Callback<UserResponse>() { @Override public void success(UserResponse userResponse, Response response) { Toast.makeText(MainActivity.this, String.format("USER_NAME:%s AGE:%d", userResponse.getUserName(), userResponse.getAge()), Toast.LENGTH_SHORT).show(); } @Override public void failure(RetrofitError error) { } }); }
RestAdapter restAdapter = new RestAdapter.Builder()
.setEndpoint("URL")
.setConverter(new GsonConverter(new Gson()))
.build();
の部分はおまじないです。
上で定義したInterfaceのインスタンスを取得します。
そのインスタンスを使用してリクエストを投げます。
api.getUser("test", 23, new Callback
この例だとtestさんが23才です。
あとは、成功すればsuccessが呼ばれるので自由にいじれます。
今回のプログラムに対応するリクエストを処理するGoのサンプル記事を以下に用意しています。
http://soba-ha-kenkou.hatenablog.com/entry/2015/09/29/224852
今回のソースコード一式は以下にあります。
https://github.com/k-shimoju/android/tree/master/Retrofit
【Android】Picassoで画像を読み込む
VolleyのImageView編で書いた物と機能は同じです。
使うメリット
Volleyとの比較
- Volleyよりも簡単に導入できる
- キャンセル処理やキャッシュも全自動
- 全自動なので、ListViewなどにも同じコードで設定できる
機能的なメリット
レスポンスで受け取ったURLを指定すればImageViewに画像が表示される
ソースコード
build.gradleの設定
dependenciesに以下を記載
compile 'com.squareup.picasso:picasso:2.5.2'
実際の処理部分
public class MainActivity extends Activity { @Bind(R.id.img_test) ImageView img; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ButterKnife.bind(this); Picasso.with(this).load("http://www.acrowavenet.com/wp/wp-content/themes/acrowavenet/images/common/header_logo.png").into(img); } }
Picasso.with(Context).load("画像URL").into(ImageView);
これだけです。
これからはピカソ派になります。
今回のソースコード一式は以下にあります。
https://github.com/k-shimoju/android/tree/master/Picasso
【Android】Volleyで通信をしよう(ImageLoader編)
Volley最後の記事はListView等でサーバから受け取った画像URLを次々に表示する方法を紹介します。
使うメリット
キャッシュもしてくれて画面外に出ていったらロードをキャンセルしてくれたり優秀です。
ソースコード
dependencies
compile 'eu.the4thfloor.volley:com.android.volley:2015.05.28'
public class AppController extends Application { public RequestQueue mRequestQueue; public ImageLoader mImageLoader; @Override public void onCreate() { super.onCreate(); mRequestQueue = Volley.newRequestQueue(getApplicationContext()); mImageLoader = new ImageLoader(mRequestQueue, new LruBitmapCache(getApplicationContext())); } }
今回は画像なので、ImageLoaderを忘れないでください
Adapterクラス
public class ImageAdapter extends ArrayAdapter<ImageListModel> { private LayoutInflater mInflater; private ImageLoader mLoader; public ImageAdapter(Context context, int resource, List<ImageListModel> imageList) { super(context, resource, imageList); mInflater = LayoutInflater.from(context); mLoader = ((AppController)((MainActivity)context).getApplication()).mImageLoader; } @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder holder; ImageListModel model = getItem(position); if (null == convertView) { convertView = mInflater.inflate(R.layout.line_layout, parent, false); holder = new ViewHolder(); holder.image = (ImageView)convertView.findViewById(R.id.img_awn); holder.name = (TextView)convertView.findViewById(R.id.txt_name); } else { holder = (ViewHolder)convertView.getTag(); } ImageLoader.ImageContainer imageContainer = (ImageLoader.ImageContainer)holder.image.getTag(); if (imageContainer != null) { imageContainer.cancelRequest(); } ImageLoader.ImageListener listener = ImageLoader.getImageListener(holder.image, R.drawable.load, R.drawable.error); holder.image.setTag(mLoader.get(model.getImageUrl(), listener)); holder.name.setText(model.getName()); convertView.setTag(holder); return convertView; } private static class ViewHolder { ImageView image; TextView name; } }
コンストラクタでImageLoaderのインスタンスを取得しておきます。
mLoader = *1.mImageLoader;
以下の処理で画像の取得をしています。
mLoader.get(model.getImageUrl(), listener)
上下に連続スクロールされた時のためにキャンセル処理も書きます。
ImageLoader.ImageContainer imageContainer = (ImageLoader.ImageContainer)holder.image.getTag();
if (imageContainer != null) {
imageContainer.cancelRequest();
}
上記キャンセル処理のためにImageViewのtagに画像取得を書いてました。
holder.image.setTag(mLoader.get(model.getImageUrl(), listener));
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; } }
キャッシュクラスは公式の物です。
ListViewに表示するデータ作成など
private List<ImageListModel> makeImageListModel() { List<ImageListModel> list = new ArrayList<>(); ImageListModel model = null; for (int i=0; i<10; i++) { model = new ImageListModel(); model.setImageUrl("http://www.acrowavenet.com/wp/wp-content/themes/acrowavenet/images/common/header_logo.png"); model.setName("株式会社アクロウェーブネット"); list.add(model); } return list; }
public class ImageListModel { private String imageUrl; private String name; public String getImageUrl() { return imageUrl; } public void setImageUrl(String imageUrl) { this.imageUrl = imageUrl; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
今回のソースコード一式は以下にあります。
https://github.com/k-shimoju/android/tree/master/Volley_ImageLoader
*1:AppController)((MainActivity)context).getApplication(
【Android】Volleyで通信をしよう(GsonRequest編)
投稿する順番間違えたorz
今回はVolleyを使ってJson形式のデータをやり取りします。
使用するメリット
処理速度が早いVolleyとGsonを組み合わせたら早くて便利
ソースコード
dependencies
compile 'eu.the4thfloor.volley:com.android.volley:2015.05.28' compile 'com.google.code.gson:gson:2.3.1'
public class AppController extends Application { public RequestQueue mRequestQueue; @Override public void onCreate() { super.onCreate(); mRequestQueue = Volley.newRequestQueue(getApplicationContext()); } }
実際に処理している部分
@OnClick(R.id.btn_request) protected void onClick(View view) { AppController application = (AppController)getApplication(); GsonRequest<JsonResponseModel> request = new GsonRequest("http://localhost:8080/", JsonResponseModel.class, null, makeParameter(), new Response.Listener() { @Override public void onResponse(Object response) { JsonResponseModel model = (JsonResponseModel)response; // あとはよしなに } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { Toast.makeText(MainActivity.this, error.getMessage(), Toast.LENGTH_SHORT).show(); } }); application.mRequestQueue.add(request); }
GsonRequest
JsonResponseModelは正常終了時の型を指定します。
あとはQueueに足せば終了です。
Gsonでやり取りするクラス
一部書きかえていますが、下記のソースを使用しています。
https://gist.github.com/ficusk/5474673
public class GsonRequest<T> extends Request<T> { private final Gson gson = new Gson(); private final Class<T> clazz; private final Map<String, String> headers; private final Map<String, String> params; // 追加 private final Listener<T> listener; /** * Make a GET request and return a parsed object from JSON. * * @param url URL of the request to make * @param clazz Relevant class object, for Gson's reflection * @param headers Map of request headers * @param params リクエストパラメータ(追加) */ public GsonRequest(String url, Class<T> clazz, Map<String, String> headers, Map<String, String> params, Listener<T> listener, ErrorListener errorListener) { super(Method.GET, url, errorListener); this.clazz = clazz; this.headers = headers; this.listener = listener; this.params = params; } @Override public Map<String, String> getHeaders() throws AuthFailureError { return headers != null ? headers : super.getHeaders(); } @Override protected void deliverResponse(T response) { listener.onResponse(response); } @Override protected Response<T> parseNetworkResponse(NetworkResponse response) { try { String json = new String( response.data, HttpHeaderParser.parseCharset(response.headers)); return Response.success( gson.fromJson(json, clazz), HttpHeaderParser.parseCacheHeaders(response)); } catch (UnsupportedEncodingException e) { return Response.error(new ParseError(e)); } catch (JsonSyntaxException e) { return Response.error(new ParseError(e)); } } @Override protected Map<String, String> getParams() throws AuthFailureError { return params; } }
追加ってコメントしている部分が変更箇所です。
レスポンスモデル
public class JsonResponseModel { @SerializedName("user_name") private String userName; private String age; public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getAge() { return age; } public void setAge(String age) { this.age = age; } }
ここは普通にGsonで使うのと同じように作ります。
この記事のアプリの動作確認用にGoで以下の記事を書いています。
http://soba-ha-kenkou.hatenablog.com/entry/2015/09/29/224732
今回のソースコード一式は以下にあります。
https://github.com/k-shimoju/android/tree/master/Volley(GSON)
【Android】Volleyで通信をしよう(ImageView編)
今回はVolleyでサーバ上の画像をImageViewにセットする方法を紹介します。
使用するメリット
ImageViewにURLを指定して勝手に表示って機能欲しいですよね?
ついでにキャッシュしてくれたりしたら最高だと思いませんか?
それが今回の記事です!!
ソースコード
build.gradleの設定
dependenciesに以下を記載
compile 'eu.the4thfloor.volley:com.android.volley:2015.05.28'
Applicationの子クラスを用意
public class AppController extends Application { public RequestQueue mRequestQueue; public ImageLoader mImageLoader; @Override public void onCreate() { super.onCreate(); mRequestQueue = Volley.newRequestQueue(getApplicationContext()); mImageLoader = new ImageLoader(mRequestQueue, new LruBitmapCache(getApplicationContext())); } }
前回の記事では無かったImageLoaderと言う物が増えています。
画像の読み込みに必要なので、忘れずに記載してください
キャッシュのためのクラス
今回は何も考えずにVolleyの公式ページの物を使います。
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; } }
実際の画像表示部分
private void setImageUrl() { String url = "http://www.acrowavenet.com/wp/wp-content/themes/acrowavenet/images/common/header_logo.png"; AppController app = (AppController)getApplication(); image.setImageUrl(url, app.mImageLoader); }
Applicationクラスに書いたImageLoaderと画像のURLを指定すれば完了です。
記事で見ると長いですが、実際はそれほど大変ではないです。
また、表示部分以外は一度書けば使い回せるので一家に一台あってもいいかもしれません
今回のソースコード一式は以下にあります。
https://github.com/k-shimoju/android/tree/master/Volley(ImageView)