您的位置:首页 > 理论基础 > 计算机网络

使用Agera,gson,okhttp获取豆瓣读书数据

2016-05-29 22:27 483 查看

使用Agera,GSON和okhttp解析数据

本文使用的是豆瓣读书的API

项目演示:



demo下载地址:AgeraDemo

实现在线查找图书的功能,整合了okhttp,gson,agera框架

API测试

URL格式:



URl:https://api.douban.com/v2/book/search?q=

返回数据

{
"count":1,
"start":0,
"total":770,
"books":[
{
"rating":{
"max":10,
"numRaters":199539,
"average":"9.0",
"min":0
},
"subtitle":"",
"author":[
"[法] 圣埃克苏佩里"
],
"pubdate":"2003-8",
"tags":[
{
"count":48852,
"name":"小王子",
"title":"小王子"
},
{
"count":40834,
"name":"童话",
"title":"童话"
},
{
"count":19514,
"name":"圣埃克苏佩里",
"title":"圣埃克苏佩里"
},
{
"count":17606,
"name":"法国",
"title":"法国"
},
{
"count":16728,
"name":"经典",
"title":"经典"
},
{
"count":12965,
"name":"外国文学",
"title":"外国文学"
},
{
"count":9317,
"name":"哲学",
"title":"哲学"
},
{
"count":6809,
"name":"小说",
"title":"小说"
}
],
"origin_title":"Le Petit Prince",
"image":"https://img1.doubanio.com\/mpic\/s1237549.jpg",
"binding":"平装",
"translator":[
"马振聘"
],
"catalog":"第一卷 南渡记出版说明人物表序曲第一章 第二章第三章第四章第五章第六章第七章间曲后记第二卷 东藏记人物表……间曲后记\n",
"pages":"97",
"images":{
"small":"https://img1.doubanio.com\/spic\/s1237549.jpg",
"large":"https://img1.doubanio.com\/lpic\/s1237549.jpg",
"medium":"https://img1.doubanio.com\/mpic\/s1237549.jpg"
},
"alt":"https:\/\/book.douban.com\/subject\/1084336\/",
"id":"1084336",
"publisher":"人民文学出版社",
"isbn10":"702004249X",
"isbn13":"9787020042494",
"title":"小王子",
"url":"https:\/\/api.douban.com\/v2\/book\/1084336",
"alt_title":"Le Petit Prince",
"author_intro":"author_intor................",
"summary":"sumary...........................",
"price":"22.00元"
}
]
}


布局文件

main

<?xml version="1.0" encoding="utf-8"?>
<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.yangtianrui.doubanapitest.MainActivity">

<EditText
android:id="@+id/id_et_key_word"
android:layout_width="200dp"
android:layout_height="50dp" />

<Button
android:id="@+id/id_btn_query"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="submit"
android:layout_alignParentRight="true" />

<ListView
android:id="@+id/id_lv_all_items"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@id/id_et_key_word" />

</RelativeLayout>


每个book的布局文件

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">

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

<TextView
android:id="@+id/id_tv_book_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="book_title"
android:textSize="15sp" />

<TextView
android:layout_marginTop="20dp"
android:id="@+id/id_tv_book_author"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="9sp"/>

<TextView
android:id="@+id/id_tv_book_subtitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="9sp"/>

<TextView
android:id="@+id/id_tv_book_publisher"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="9sp"/>
</LinearLayout>
</android.support.v7.widget.CardView>


Book javaBean类

根据Json字符串抽取了几个关键属性组成Bean对象用作测试

/**
* Created by yangtianrui on 16-5-29.
*/
public class Book {
private String title;
private String alt_Title;
private String[] author;
private String publisher;

public Book(String title, String alt_Title, String[] author, String publisher) {
this.title = title;
this.alt_Title = alt_Title;
this.author = author;
this.publisher = publisher;
}

public Book() {
}

public String getTitle() {
return title;
}

public void setTitle(String title) {
this.title = title;
}

public String getAlt_Title() {
return alt_Title;
}

public void setAlt_Title(String alt_Title) {
this.alt_Title = alt_Title;
}

public String[] getAuthor() {
return author;
}

public void setAuthor(String[] author) {
this.author = author;
}

public String getPublisher() {
return publisher;
}

public void setPublisher(String publisher) {
this.publisher = publisher;
}

@Override
public String toString() {
return "Book{" +
"title='" + title +
'}';
}
}


supplier的实现类,通过此类进行数据检索,Repository从此处获取数据

此处是数据获取的关键,我使用了GSON和okhttp框架来对json进行处理,将该类将返回一个Result对象

/**
* Created by yangtianrui on 16-5-29.
* 根据关键字,提供书籍数据
*/
public class BooksSupplier implements Supplier<Result<List<Book>>> {
private String key;
// 用于建立连接
private OkHttpClient client = new OkHttpClient();
private Gson gson = new Gson();
private static final String API_URL = "https://api.douban.com/v2/book/search";

public void setKey(String key) {
this.key = key;
}

public String getKey() {
return key;
}

public BooksSupplier(String key) {
this.key = key;
}

public BooksSupplier() {
}

private List<Book> getBooks() {
Log.v("LOG", "getBooks");
HttpUrl httpUrl = HttpUrl.parse(API_URL).newBuilder()
// 设置查询参数
.addQueryParameter("q", key)
.addQueryParameter("start", "0")
.addQueryParameter("count", "15")
.build();
Request request = new Request.Builder().url(httpUrl).build();
try {
// 建立连接
Response response = client.newCall(request).execute();
// 获取返回的Json
//            Log.v("LOG",response.body().toString());
JSONObject jsonObject = new JSONObject(response.body().string());
JSONArray jsonArray = jsonObject.optJSONArray("books");
List<Book> list = gson.fromJson(jsonArray.toString(), new TypeToken<List<Book>>() {
}.getType());
//            Log.v("LOG", list.toString());
return list;
} catch (Exception e) {
Log.v("LOG","error in getBooks()"+e.getMessage());
e.printStackTrace();
return null;
}
}

// 获取数据
@NonNull
@Override
public Result<List<Book>> get() {
List<Book> list = getBooks();
if (list != null) {
return Result.success(list);
} else {
return Result.failure();
}
}
}


MainActivity中,创建Observer,对Repository中的数据进行获取,同时更新UI

使用goTo方法指定获取数据执行的线程

使用thenGetFrom方法指定获取数据的Supplier

这里我们还使用了observe方法指定了一个searchObservable,后续我们可以使用searchObservable来发起事件调用。

在按钮的点击事件中,发起事件调用

// MainActivity中使用观察者更新数据
public class MainActivity extends AppCompatActivity implements Updatable {

private ListView mLvAllBooks;
private EditText mEtKey;
private Button mBtnQuery;

private MyAdapter mAdapter;
private List<Book> mBooks = new ArrayList<>();
private ExecutorService mExecutor;
private BooksSupplier mSupplier;
private Repository<Result<List<Book>>> mRepository;
private SearchObserver mObserver;

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

/**
* 初始化Repository
*/
private void setupRepository() {
// 单线程线程池
mExecutor = Executors.newSingleThreadExecutor();
mObserver = new SearchObserver();
mSupplier = new BooksSupplier("Hello");
mRepository = Repositories
.repositoryWithInitialValue(Result.<List<Book>>absent())
.observe(mObserver)
.onUpdatesPerLoop()
.goTo(mExecutor)
.thenGetFrom(mSupplier)
.compile();

}

private void initView() {
mLvAllBooks = (ListView) findViewById(R.id.id_lv_all_items);
mEtKey = (EditText) findViewById(R.id.id_et_key_word);
mBtnQuery = (Button) findViewById(R.id.id_btn_query);
mRepository.addUpdatable(MainActivity.this);
mAdapter = new MyAdapter(this, mBooks);
mLvAllBooks.setAdapter(mAdapter);
mBtnQuery.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {

String key = mEtKey.getText().toString();
mObserver.doSearch(key);

Log.v("LOG", "Activity  onClick  " + key);
}
});
}

private class SearchObserver extends BaseObservable {
public void doSearch(String key) {
mSupplier.setKey(key);
dispatchUpdate();
Log.v("LOG", "Activity  doSearch");
}
}

// 执行查询操作,处理调用结果
@Override
public void update() {
Log.v("LOG", "Activity  update");
if (mRepository.get().isPresent()) {
///TODO
mBooks.clear();
mBooks.addAll(mRepository.get().get());
mAdapter.notifyDataSetChanged();
Log.v("LOG", mBooks.toString());
}
}
}


Adapter类

/**
* Created by yangtianrui on 16-5-29.
*/
public class MyAdapter extends BaseAdapter {
private List<Book> mBooks;
private LayoutInflater mInflater;
private Context mContext;

public MyAdapter(Context context, List<Book> list) {
mInflater = LayoutInflater.from(context);
mContext = context;
mBooks = list;
}

@Override
public int getCount() {
return mBooks.size();
}

@Override
public Object getItem(int position) {
return mBooks.get(position);
}

@Override
public long getItemId(int position) {
return position;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder = null;
if (convertView == null) {
convertView = mInflater.inflate(R.layout.item_book, null);
holder = new ViewHolder();
holder.mTvTitle = (TextView) convertView.findViewById(R.id.id_tv_book_title);
holder.mTvAuthor = (TextView) convertView.findViewById(R.id.id_tv_book_author);
holder.mTvSubTitle = (TextView) convertView.findViewById(R.id.id_tv_book_subtitle);
holder.mTvPublisher = (TextView) convertView.findViewById(R.id.id_tv_book_publisher);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.mTvTitle.setText(mBooks.get(position).getTitle());
holder.mTvSubTitle.setText(mBooks.get(position).getAlt_Title());
if (mBooks.get(position).getAuthor().length != 0)
holder.mTvAuthor.setText(mBooks.get(position).getAuthor()[0]);
holder.mTvPublisher.setText(mBooks.get(position).getPublisher());
return convertView;
}

static class ViewHolder {
TextView mTvTitle;
TextView mTvAuthor;
TextView mTvSubTitle;
TextView mTvPublisher;
}
}


发现自己还是对观察者模式和Agera框架了解不够, 文章也许写的太过表面了,我会继续学习的:-)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: