12.3.1 使用JSON提取Flickr图像

    Flickr是流行的在线照片和视频共享网站,具有一个非常完备的Web服务API,其中提供JSON作为输出格式之一。

    正如许多通过Web服务API提供功能的站点一样,Flickr要求开发人员能够注册并请求一个API键。API键唯一标识了指向Flickr系统的应用程序,从而可以跟踪它,以及在它造成问题时可以对其进行处理(如禁用它)。

    为了从Flickr请求API键,必须登录并访问页面www.flickr.com/services/apps/create/apply/?来回答他们的问题。随后,他们将会显示你的API秘钥和一个额外的“秘密(secret)”字符串,它对某些功能是必须的,如登录用户。

    在下面的示例中将使用Flickr API来搜索标记为“waterfront(海滨)”的图像。为此将使用flickr.photos.search方法。你可以在线查找Flickr API中所有可用方法的文档:www.flickr.com/services/api。

     为了调用该方法,只需要构造一个URL,并传入需要指定的参数。需要指定flickr.photos.search作为方法、waterfront作为标签、json作为格式,以及5作为每页返回的图片数量(此处将只查看一个页面,默认是第一个页面)。还需要为nojsoncallback传入1,通知Flickr返回纯JSON,而非以一个JavaScript方法调用包装的JSON。最后将需要指定API键(在此示例中显示为YOU_API_AKY)。

1 http://api.filckr.com/services/rest/?method=flickr.photos.search&tags=waterfront&format=json&api_key="+API_KEY+"&per_page=5&nojsoncallback=1

    为了查看该API调用返回的数据,只须将它放在桌面浏览器中并查看响应。一下是现在返回的内容。当你尝试时,数据将会不同,因为它显示最近的5幅标签为“waterfront”的图像。但是另一方面,其结构将保持相同,这一点非常重要,因为需要他保持一致以围绕其构建应用程序。

1     {"photos":{"page":1,"perpage":5,"total":"345999",
2         "photo":[{"id":"5224082852","owner":"43034272@N03","secret":"9c694fa5f","server":"4130","farm":5,"title":"_G8J1792","ispublic":1,"isfriend":0,"isfamily":0},
3                  ...
4                  ]},"stat":"ok"}

    查看返回的JSON数据,就可以确定通过使用JSON分析器,需要采取哪些步骤来获得需要的信息。将它进行分析之后,可以看到一个称为photos的总体对象,其中包含一个JSON对象的数组(称为photo)。

    photo数组中的每个条目都具有一系列其他的值,包括id、所有者(owner)、秘密(secret)、服务器(server)、场所(farm)、标题(title)等。Flickr API文档中有一个部分详细介绍了如何使用这些值来构造实际图像文件的URL:www.flickr.com/services/api/misc.urls.html。

    接下来完成一个将上述内容汇总在一起的完整示例。

 1 package com.nthm.androidtestActivity;
 2 
 3 import java.io.BufferedReader;
 4 import java.io.IOException;
 5 import java.io.InputStream;
 6 import java.io.InputStreamReader;
 7 import java.net.HttpURLConnection;
 8 import java.net.MalformedURLException;
 9 import java.net.URL;
10 import org.apache.http.HttpEntity;
11 import org.apache.http.HttpResponse;
12 import org.apache.http.client.HttpClient;
13 import org.apache.http.client.methods.HttpGet;
14 import org.apache.http.impl.client.DefaultHttpClient;
15 import org.json.JSONArray;
16 import org.json.JSONObject;
17 import com.nthm.androidtest.R;
18 import android.app.Activity;
19 import android.content.Context;
20 import android.graphics.Bitmap;
21 import android.graphics.BitmapFactory;
22 import android.os.Bundle;
23 import android.view.LayoutInflater;
24 import android.view.View;
25 import android.view.ViewGroup;
26 import android.widget.BaseAdapter;
27 import android.widget.ImageView;
28 import android.widget.ListView;
29 import android.widget.TextView;
30 
31 public class FilchrJSON extends Activity {

    需要将下面一行中的“YOU_API_AKY”文本替换成在发出请求后有Flickr提供的API键。

1     public static final String API_KEY="YOU_API_AKY";

    在此示例中的后面定义了一个称为FilckrPhoto对象放到下面定义的数组photos中。

1     private  FilckrPhoto[] photos;
2     @Override
3     protected void onCreate(Bundle savedInstanceState) {
4         super.onCreate(savedInstanceState);
5         setContentView(R.layout.filchrjson);

    当活动初次启动时将使用HttpClient生成Flickr API请求。

1         HttpClient httpcilent=new DefaultHttpClient();
2         HttpGet httpget=new HttpGet("http://api.filckr.com/services/rest/?method=flickr.photos.search&tags=waterfront&format=json&api_key="+API_KEY+"&per_page=5&nojsoncallback=1");
3         HttpResponse response;
4         try{
5             response=httpcilent.execute(httpget);
6             HttpEntity entity=response.getEntity();
7             if(entity!=null){
8                 InputStream inputstream=entity.getContent();

    一旦获得了内容的InputStream,就可以读入它并创建一个字符串,从而可以将它传递给JSON分析器。

 1                 BufferedReader bufferedreader=new BufferedReader(new InputStreamReader(inputstream));
 2                 StringBuilder stringbuilder=new StringBuilder();
 3                 String currentline=null;
 4                 try{
 5                     while((currentline=bufferedreader.readLine())!=null){
 6                         stringbuilder.append(currentline+"\n");
 7                     }
 8                 }catch(IOException e){
 9                     e.printStackTrace();
10                 }
11                 String result=stringbuilder.toString();

     既然获得了HTTP请求的结果,就可以分析返回的JSON数据。首先以完整的JSON数据创建了一个JSONObject,然后使用第一个对象创建另一个JSONObject,从而可以根据名称获得主要的JSON对象photos。

1                 JSONObject thedata=new JSONObject(result);
2                 JSONObject thephotosdata=thedata.getJSONObject("photos");

    一旦获得了该对象,就可以得到命名为photo的JSONArray。

1                 JSONArray thephotodata=thephotosdata.getJSONArray("photo");

    既然已经获得了JSON photo对象数组,就可以设置FilckrPhoto对象数组的长度。随后将遍历JSON对象,提取出所有相关的数据,并在FilckrPhoto photos数组中创建一个FilckrPhoto对象。

 1                 photos=new FilckrPhoto[thephotodata.length()];
 2                 for(int i=0;i<thephotodata.length();i++){
 3                     JSONObject photodata=thephotodata.getJSONObject(i);
 4                     photos[i]=new FilckrPhoto(photodata.getString("id"),
 5                             photodata.getString("owner"), 
 6                             photodata.getString("secret"), 
 7                             photodata.getString("server"), 
 8                             photodata.getString("title"),
 9                             photodata.getString("farm"));
10                 }
11                 inputstream.close();
12             }
13         }catch(Exception e){
14             e.printStackTrace();
15         }

    最后,在onCreate方法的末尾,我们将访问在布局中建立的ListView,并设置它的适配器。我们将使用此处定义的称为FlickrGalleryAdapter的类构造一个适配器,并传入FilckrPhotos数组。

1         ListView listView=(ListView) this.findViewById(R.id.ListView);
2         listView.setAdapter(new FlickrGalleryAdapter(this, photos));
3     }

    下面是FlickrGalleryAdapter类,其负责确定将出现在ListView中的内容。在当前情况下,它将用于填充在布局中定义的ListView,以显示Flickr搜索返回的照片和标题。

 1     class FlickrGalleryAdapter extends BaseAdapter{
 2         private Context context;
 3         private FilckrPhoto [] photos;
 4         private LayoutInflater inflater;
 5         public FlickrGalleryAdapter(Context _context,FilckrPhoto [] _items){
 6             context=_context;
 7             photos=_items;
 8             inflater=(LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
 9         }
10         @Override
11         public int getCount() {
12             return photos.length;
13         }
14 
15         @Override
16         public Object getItem(int position) {
17             return photos[position];
18         }
19 
20         @Override
21         public long getItemId(int position) {
22             return position;
23         }

    getView方法是该类的主要内容,它决定将在ListView的单个单元格中显示的内容。

1         @Override
2         public View getView(int position, View convertView, ViewGroup parent) {

    首先获得对应每一行的视图引用。在当前情况下,我们将通过扩展在filchrjson_list_item.xml中定义的filchrjson_list_item布局来实现它。

1             View photoRow=inflater.inflate(R.layout.filchrjson_list_item, null);

    在获得单元格的主视图之后,就可以获取单个元素并设置其中的内容。首先处理ImageView,并将位图对象设置为在FlickrPhoto对象内构造的URL(使用从JSON数据返回的数据)所返回的图像。

1             ImageView image=(ImageView) photoRow.findViewById(R.id.ImageView);
2             image.setImageBitmap(imageFromUrl(photos[position].makeURL()));

    然后将为TextView做相同的事情,并将它的文本设置为该图像的标题。

1             TextView imageTitle=(TextView) photoRow.findViewById(R.id.TextView);
2             imageTitle.setText(photos[position].title);
3             return photoRow;
4         }

    下面是创建位图对象的方法,该位图对象将用于上述根据在线可用图像的URL所获得的ImageView。该方法使用HttpURLConnection打开该图像文件的InputStream,并将它传递给BitmapFactory以创建位图对象。

 1         public Bitmap imageFromUrl(String url){
 2             Bitmap bitmapImage;
 3             URL imageUrl=null;
 4             try {
 5                 imageUrl=new URL(url);
 6             } catch (MalformedURLException e) {
 7                 e.printStackTrace();
 8             }
 9             try {
10                 HttpURLConnection httpConnection=(HttpURLConnection) imageUrl.openConnection();
11                 httpConnection.setDoInput(true);
12                 httpConnection.connect();
13                 InputStream is=httpConnection.getInputStream();
14                 bitmapImage=BitmapFactory.decodeStream(is);
15             } catch (IOException e) {
16                 e.printStackTrace();
17                 bitmapImage=Bitmap.createBitmap(10,10,Bitmap.Config.ARGB_8888);
18             }
19             
20             return bitmapImage;
21         }
22     }

    最后,下面是FilckrPhoto类。它是以JSON数据表示的每张照片中所需数据的java表示。

 1     class FilckrPhoto{
 2         private String id;
 3         private String owner;
 4         private String secret;
 5         private String server;
 6         private String title;
 7         private String farm;
 8         
 9         public FilckrPhoto(String _id,String _owner,String _secret,String _server,String _title,String _farm){
10             id=_id;
11             owner=_owner;
12             secret=_secret;
13             server=_server;
14             title=_title;
15             farm=_farm;
16         }

    下面的makeURL方法将根据Filckr API文档将此数据转换成图像的URL。

1         public String makeURL(){
2             return "http://farm"+farm+".static.flickr.com/"+server+"/"+id+"_"+secret+"_m.jpg";
3         }
4     }
5 }

    下面是filchrjson.xml,其中包含了用于上述代码的布局。

 1 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 2     android:layout_width="match_parent"
 3     android:layout_height="match_parent"
 4     android:orientation="vertical"
 5     >
 6  <ListView 
 7      android:layout_width="wrap_content"
 8      android:layout_height="wrap_content"
 9      android:id="@+id/ListView"
10   />
11 </LinearLayout>

    下面是filchrjson_list_item.xml文件,它定义了用于ListView的布局。

 1 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 2     android:layout_width="match_parent"
 3     android:layout_height="match_parent"
 4     android:orientation="horizontal"
 5     >
 6     <ImageView 
 7         android:id="@+id/ImageView"
 8         android:layout_width="wrap_content"
 9         android:layout_height="wrap_content"
10         />
11  <TextView 
12      android:id="@+id/TextView"
13      android:text="TextView"
14      android:layout_width="fill_parent"
15      android:layout_height="wrap_content"
16      android:textSize="35dip"></TextView>
17 </LinearLayout>

    正如我们已经看到的那样,使用JSON与Web服务(如Flickr)交互非常的简单,而且潜在的功能很强大。

 

posted on 2014-09-11 09:43  宁静致远,一览众山小  阅读(802)  评论(0编辑  收藏  举报

导航