2017年7月29日 星期六

Android:使用JackSon函式庫解析Json

在Android裡要解析伺服端回傳的Json格式資料,除了使用內建在android studio裡的Json.org外,還可以使用第三方的函式庫,像是Gson或JackSon,JackSon是目前開放原碼中有著高效率特色的函式庫之一,常用在許多的應用程式中。


要使用JackSon解析Json資料時,需要先導入JackSon函式庫,下載網址 :
http://www.java2s.com/Code/Jar/j/Downloadjacksonall199jar.htm

下面的範例以GoogleBook的api為範例:
https://www.googleapis.com/books/v1/volumes?q=java (q後面為書名)



伺服器回傳的Json :
紅色框框為要取得的資訊title(書名)與subtitle(副標題)
PS:subTitle並不是每本書都會有
下面這本書就有subtitle了


為了好解析Json裡的資料,可以畫一張類別圖,這樣就可以知道我們接下來要準備建立哪些類別和底下有哪些屬性:

*表示多值,也就是items底下有多筆資料,像是有kind、id、etag、selfLink、volumeInfo,在Json格式裡會以[ ] 陣列表示,另外在Json格式裡{ } 表示物件



程式碼:
activity_main.xml:

<LinearLayout 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=".MainActivity"
    android:orientation="vertical" >
    
    <TextView
        android:id="@+id/txt"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="書名" />
    
    <EditText 
        android:id="@+id/edt"
        android:layout_width="150dp"
        android:layout_height="wrap_content"
        />
    <Button
        android:id="@+id/btn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="search"
        />
    
</LinearLayout>

MainActivity.java:

public class MainActivity extends Activity {
 
    private Button btn;
    private EditText edt;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        findviewbyid();
        
    }
    private void findviewbyid(){
        btn = (Button)findViewById(R.id.btn);
        edt = (EditText)findViewById(R.id.edt);
        btn.setOnClickListener(btnlistener);
    }
    private View.OnClickListener btnlistener = new View.OnClickListener() {
  
  @Override
  public void onClick(View arg0) {

//   Loose Coupling
//   Intent it = new Intent("com.mchen.Activity2");
//   it.putExtra("bookName", edt.getText().toString());

     Uri uri = Uri.parse("Tom:"+edt.getText().toString());  //使用自訂的Scheme
     Intent it = new Intent(Intent.ACTION_VIEW,uri);   //跳頁到DisplayBooks
     startActivity(it);
  }
 };
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }
    
}

BookInfo2.java:

import org.codehaus.jackson.annotate.JsonIgnoreProperties;

@JsonIgnoreProperties(ignoreUnknown=true)
public class BookInfo2 {
 
 private int totalItems;
 private List<items> items = new ArrayList<items>();
 
 public BookInfo2(){
  
 }
 public BookInfo2(int totalItems,List<items> items){
  this.totalItems = totalItems;
  this.items = items;
 }
 
 public int getTotalItems() {
  return totalItems;
 }
 public void setTotalItems(int totalItems) {
  this.totalItems = totalItems;
 }
 public List<items> getItems() {
  return items;
 }
 public void setItems(List<items> items) {
  this.items = items;
 }
 
}

items.java:

import org.codehaus.jackson.annotate.JsonIgnoreProperties;

@JsonIgnoreProperties(ignoreUnknown=true)
public class items {
 
 private volumeInfo volumeInfo;

 public items(){
  
 }
 
 public items(volumeInfo volumeInfo){
  this.volumeInfo = volumeInfo;
 }

 public volumeInfo getVolumeInfo() {
  return volumeInfo;
 }

 public void setVolumeInfo(volumeInfo volumeInfo) {
  this.volumeInfo = volumeInfo;
 }

}

volumeInfo.java:

import org.codehaus.jackson.annotate.JsonIgnoreProperties;

@JsonIgnoreProperties(ignoreUnknown=true)
public class volumeInfo {
 
 private String subtitle;
 private String title;
 public String getSubtitle() {
  
  return subtitle;
  
 }
 public void setSubtitle(String subtitle) {
  this.subtitle = subtitle;
 }
 public String getTitle() {
  return title;
 }
 public void setTitle(String title) {
  this.title = title;
 }

}

book.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <ListView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:dividerHeight="5dp"
        android:id="@+id/listview">
    </ListView>

</LinearLayout>

row.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >
    <TextView
        android:id="@+id/txtTitle"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Large Text"
        android:textAppearance="?android:attr/textAppearanceLarge" />

    <TextView
        android:id="@+id/txtSubTitle"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Large Text"
        android:textAppearance="?android:attr/textAppearanceLarge" />
    

</LinearLayout>

DisplayBooks.java:

public class DisplayBooks extends Activity {

 private ListView listView;

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

        listView = (ListView)findViewById(R.id.listview);
        Log.i("mutin","action-"+this.getIntent().getAction());
        Log.i("mutin", "data-"+this.getIntent().getData().getSchemeSpecificPart());

        final String param = this.getIntent().getData().getSchemeSpecificPart();
        int cpuCount = Runtime.getRuntime().availableProcessors();  //取得可以建立Thread的最大數量
        ExecutorService es = Executors.newFixedThreadPool(cpuCount);   //建立Thread
        Future<String> f = es.submit(new Callable<String>(){      //可以取得Callable回傳結果

   @Override
   public String call() throws Exception {
    // TODO Auto-generated method stub
    URL url = new URL("https://www.googleapis.com/books/v1/volumes?q="+param);
    java.net.URLConnection con = url.openConnection();
    BufferedReader br = new BufferedReader(new InputStreamReader(con.getInputStream()));
    String data = null;
    StringBuffer result  = new StringBuffer();
    while((data=br.readLine())!=null){
     result.append(data);
    }

    return result.toString();
   }
         
        });
        try{
         String result = f.get();
         es.shutdown();

   //產生Jackson函式庫負責解析的ObjectMapper類別
         ObjectMapper mapper = new ObjectMapper();

   //呼叫ObjectMapper的readValue方法進行Json格式轉換為Java資料的工作
         BookInfo2 bi = mapper.readValue(result,BookInfo2.class);
         HashMap<String,String> map;
         ArrayList<HashMap<String,String>> list = new ArrayList<HashMap<String,String>>();
         for(items item:bi.getItems()){
          Log.i("mutin", "Title="+item.getVolumeInfo().getTitle());
          Log.i("mutin", "SubTitle="+item.getVolumeInfo().getSubtitle());
          
          map = new HashMap<String,String>();
                map.put("title", "Title:"+item.getVolumeInfo().getTitle());
          map.put("subTitle", "SubTitle:" + item.getVolumeInfo().getSubtitle());
                list.add(map);
         }
         
         SimpleAdapter adapter = new SimpleAdapter(this,list,R.layout.row,new String[]{"title","subTitle"},new int[]{R.id.txtTitle,R.id.txtSubTitle});
            listView.setAdapter(adapter);
         
        }catch(Exception ex){
         ex.printStackTrace();
        }
        
 }

}
PS:用HightLight上色程式碼,格式會跑掉,請見諒

執行畫面:

沒有留言:

張貼留言