一直以來都感覺自己只會(huì)看代碼,解決bug,總是覺得自己能力有限,想做一些程序性的開發(fā),但總是做到一半就戛然而止。這次終于鼓起勇氣來從零開始做一款客戶端程序,一切從零開始。
由于從來沒有做過相應(yīng)的開發(fā),不敢說自己怎么組織架構(gòu),怎么設(shè)計(jì)項(xiàng)目等,都是隨著項(xiàng)目慢慢的深入,一步步發(fā)掘項(xiàng)目功能,然后不斷改進(jìn)的結(jié)果。這個(gè)系列的文章,權(quán)當(dāng)是某人的思路。
數(shù)據(jù)
首先我先想到的不是界面,而是數(shù)據(jù),數(shù)據(jù)從什么地方來,應(yīng)該怎么使用?很顯然我們這個(gè)項(xiàng)目使用的是干活集中營(yíng)的API,具體可以看http://gank.io/api
由于是網(wǎng)絡(luò)數(shù)據(jù),很自然就想到了okHttp了,當(dāng)然你可能想到了RxJava+Retrofit,可是為了從基本入手,我就選擇了okHttp了。
先簡(jiǎn)單裝一下okHttp
- 導(dǎo)入okHttp包
只需在Gradle下添加如下依賴即可:
compile 'com.squareup.okhttp3:okhttp:3.6.0'
- 創(chuàng)建Manager類
我這里創(chuàng)建的是GankHttpManager.java,這里我將其改為單例類型。
private static GankHttpManager mInstance;
private GankHttpManager() {
}
public static GankHttpManager getInstance() {
if(mInstance == null) {
synchronized (GankHttpManager.class) {
if(mInstance == null) {
mInstance = new GankHttpManager();
}
}
}
return mInstance;
}
當(dāng)然GankHttpManage不可能這么簡(jiǎn)單,既然是封裝okHttp,當(dāng)然得需要OkHttpClient,解析數(shù)據(jù)也需要Gson,這些一并在構(gòu)造方法中初始化即可:
private OkHttpClient mHttpClient;
private Handler mHandler;
private Gson mGson;
private GankHttpManager() {
mHttpClient = new OkHttpClient();
mHandler = new Handler(Looper.getMainLooper());
mGson = new Gson();
}
這樣我們的GankHttpManager就封裝好了。現(xiàn)在我們要做的事情就是通過Gson來解析數(shù)據(jù)了。
通過查看干活集中營(yíng)的Api,可以發(fā)現(xiàn)暫時(shí)我們需要的Api有兩種類型,1. 每日數(shù)據(jù);2.分類數(shù)據(jù)。通過查看json數(shù)據(jù)可以發(fā)現(xiàn)這兩種Api的數(shù)據(jù)有些不一樣。
每日數(shù)據(jù)(http://gank.io/api/day/年/月/日)
我們先來看一下json數(shù)據(jù)
//省略號(hào)代表后面的重復(fù)性內(nèi)容省略
{
"category": [
"Android", ...
],
"error": false,
"results": {
"Android": [
{
"_id": "590af3b3421aa90c7fefdd3c", ...
}, ...
],...
}
}
如果用Gson進(jìn)行解析那么我們應(yīng)該怎樣去構(gòu)建對(duì)象呢?
可以看到整個(gè)json包含三個(gè)大括號(hào),如果我們把大括號(hào)代表一個(gè)層級(jí)的話,那么就比較好分析了,
1.首先構(gòu)建一個(gè)對(duì)象包含三個(gè)參數(shù),category,error,results。那么最外層也就分析完了,
2.其次再看category,該對(duì)象中又包含中括號(hào),那么我們可以將之看作為一個(gè)List。再看results,你會(huì)發(fā)現(xiàn)其和包含的內(nèi)容和外層類似,可以把整個(gè)的result看做一個(gè)對(duì)象。這時(shí)你可能又郁悶了,如果把里面的每一個(gè)看做一個(gè)對(duì)象,但是對(duì)象里的內(nèi)容又是重復(fù)的,這怎么解決呢?其實(shí)可以把result看做是幾個(gè)不同的List就可以了。
經(jīng)過簡(jiǎn)單的分析那么我開始構(gòu)建我們的數(shù)據(jù)吧。首先構(gòu)建的是最里層相似的內(nèi)容。我將之封裝為Gank對(duì)象。
public class Gank{
public String _id;
public Date createdAt;
public String desc;
public Date publishedAt;
public String source;
public String type;
public String url;
public boolean used;
public String who;
}
也可以加上@SerializedName的注解,來標(biāo)明對(duì)應(yīng)json的數(shù)據(jù)。
做完上面的工作,我們就可以來封裝整個(gè)json了,我將之封裝為DailyGank對(duì)象
public class DailyGank {
@SerializedName("category") public List<String> category;
@SerializedName("error") public boolean error;
@SerializedName("results") public Result result;
public class Result {
@SerializedName("福利") public List<Gank> welfareList;
@SerializedName("Android") public List<Gank> androidList;
@SerializedName("iOS") public List<Gank> iosList;
@SerializedName("拓展資源") public List<Gank> extraList;
@SerializedName("前端") public List<Gank> frontList;
@SerializedName("瞎推薦") public List<Gank> casualList;
@SerializedName("App") public List<Gank> appList;
@SerializedName("休息視頻") public List<Gank> videoList;
}
}
這樣我們就封裝了每日數(shù)據(jù)的json對(duì)象,那么下面我們來封裝分類對(duì)象
分類對(duì)象(http://gank.io/api/data/數(shù)據(jù)類型/請(qǐng)求個(gè)數(shù)/第幾頁(yè))
同樣,我們可以看一下json數(shù)據(jù)
{
"error": false,
"results": [
{
"_id": "590af3b3421aa90c7fefdd3c",...
}, ...
]
}
可以看到和上面的數(shù)據(jù)有一點(diǎn)出入,也有相似點(diǎn)。我就不介紹了。直接看封裝ClassifyGank
public class ClassifyGank {
@SerializedName("error") public boolean error;
@SerializedName("results") public List<Gank> classifyGank;
}
或者我們可以將DailyGank和ClassifyGank中共有的屬性error給封裝到BaseGank中,然后繼承。不這樣也沒有關(guān)系。
既然我們的json數(shù)據(jù)已經(jīng)分析清楚了,那么就可以在GankHttpManager中來獲取并解析數(shù)據(jù)了。主要寫兩個(gè)方法,分別獲取每日數(shù)據(jù)和分類數(shù)據(jù)
public void getClassifyGank(String url, final GankHttpListener listener) {
Request request = new Request.Builder().url(url).build();
mHttpClient.newCall(request)
.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, Response response) throws IOException {
final String body = response.body().string();
mHandler.post(new Runnable() {
@Override
public void run() {
ClassifyGank data = mGson.fromJson(body,ClassifyGank.class);
// TODO: 處理數(shù)據(jù)
}
});
}
});
}
public void getDailyGank(String url, final GankHttpListener listener){
Request request = new Request.Builder().url(url).build();
mHttpClient.newCall(request)
.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, Response response) throws IOException {
final String body = response.body().string();
mHandler.post(new Runnable() {
@Override
public void run() {
DailyGank data = mGson.fromJson(body,DailyGank.class);
// TODO: 處理數(shù)據(jù)
}
});
}
});
}
代碼中有一段注釋是用來處理數(shù)據(jù)用的,看見了嗎?在我們傳入方法的地方都有一個(gè)listener,那個(gè)就是用來進(jìn)行回調(diào)的方法,以便我們得到數(shù)據(jù)后進(jìn)行處理。后面會(huì)介紹該listener怎么去定義。
這次就先講到這里,下面一節(jié)講解Gank客戶端的主界面。拜拜!