這篇要示範的是, 如何寫一個ContentProvider讓其他的應用程式透過這個Provider去存取網路上的資料
這不是正統用法, 不過的確可以這樣用, 那為啥要這樣呢? 只是好玩, 還沒想到特別的應用
這邊用的範例是Twitter search (search keyword): MLB
首先要建立一個放Provider的Package, 不過這個Provider不是拿來存取DB的, 傳統的Android ContentProvider通常是用來存取資料庫, 但那並不代表那就是它的全部, “Content"Provider不就是拿來提供"Content"的嘛?管他Content哪來
建立一個Provider, 姑且叫它做TwitterSearchProvider, Authorities定為twitter.my.search好了, 裡面, 先只實作一個"query"
p.p1 {margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco} span.s1 {color: #9a1867} span.Apple-tab-span {white-space:pre}
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
return new TwitterSearchCursor();
}
這Query啥事都不用作, 回傳個TwitterSearchCursor就好了
從這看出玄機了嘛? 我們就是要利用Cursor, 在Cursor裡面實作連接網路取得資料的動作
後面我懶得寫解釋了, MBP快沒電了, 以下就是TwitterSearchCursor的Source:
p.p1 {margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco} p.p2 {margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco; min-height: 15.0px} p.p3 {margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco; color: #9a1867} p.p4 {margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco; color: #777777} p.p5 {margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco; color: #429073} p.p6 {margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco; color: #382ffa} p.p7 {margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco; color: #0023c7} span.s1 {color: #9a1867} span.s2 {color: #000000} span.s3 {color: #0023c7} span.s4 {color: #382ffa} span.s5 {color: #8dafc9} span.Apple-tab-span {white-space:pre}
public class TwitterSearchCursor extends AbstractCursor {
static class Tweet {
String created_at = ”“;
String id_str = ”“;
String text = ”“;
}
ArrayList<Tweet> tweets = new ArrayList<Tweet>();
@Override
public String[] getColumnNames() {
// TODO Auto-generated method stub
return new String[] {”_id", “created_at”,“id_str”,“text”};
}
@Override
public int getCount() {
if(tweets.size() == 0) {
loadData();
}
Log.d(“AAAA”, “cnt=”+tweets.size());
return tweets.size();
}
@Override
public double getDouble(int arg0) {
// TODO Auto-generated method stub
return 0;
}
@Override
public float getFloat(int arg0) {
// TODO Auto-generated method stub
return 0;
}
@Override
public int getInt(int index) {
return index;
}
@Override
public long getLong(int index) {
return index;
}
@Override
public short getShort(int index) {
return (short)index;
}
@Override
public String getString(int index) {
Tweet t = tweets.get(mPos);
switch(index) {
case 1:
return “”+t.created_at;
case 2:
return “”+t.id_str;
case 3:
return “”+t.text;
}
return null;
}
@Override
public boolean isNull(int arg0) {
// TODO Auto-generated method stub
return false;
}
private void loadData() {
HttpClient client = AndroidHttpClient.newInstance(“TwiAndroid”);
HttpGet get = new HttpGet(“http://search.twitter.com/search.json?q=mlb”);
try {
HttpResponse resp = client.execute(get);
BufferedReader reader = new BufferedReader(new InputStreamReader(resp.getEntity().getContent()));
String line = null;
StringBuilder r = new StringBuilder();
while((line = reader.readLine())!=null) {
Log.d(“AAAA”, line);
r.append(line);
}
JSONObject obj = new JSONObject(r.toString());
JSONArray ary = obj.getJSONArray(“results”);
for(int i=0;i<ary.length();i++) {
Tweet t = new Tweet();
t.created_at = ary.getJSONObject(i).getString(“created_at”);
t.id_str = ary.getJSONObject(i).getString(“id_str”);
t.text = ary.getJSONObject(i).getString(“text”);
tweets.add(t);
}
} catch (ClientProtocolException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
其實就是利用getCount()時去存取Twitter search API
為什麼要在這時候呢? 主要是我在remote端用的是Cursor來bind這些資料, 第一個會被呼叫到的是getCount()
由於整個Cursor會被跑在Provider所在的process並非跟caller同一個process, 所以heap也是吃在provider
這種利用Custom cursor應該可以組合出其他不同的作法跟應用…