السلام عليكم ورحمه الله وبركاته
ان شاء الله سوف اقوم بشرح كيفيه التعامل مع البيانات التى على شكل JSON
وهى شكل متفق عليه مثل الـ XML ولكنه يختلف قليلا ويستخدم لنقل البيانات
وهو ما يتعامل به الفيس بوك والتويتر (وهو مثالنا اليوم)
مثال على التويتر
https://api.twitter.com/1/statuses/user_timeline.json?screen_name=jkelanycompany
مثال على الفيس بوك
https://graph.facebook.com/jkelanydeveloper
هذا هو شكل الـ JSON data
عباره عن Array او Object او الدمج بينها
والصوره توضح ايهما array وهو عباره ان اقواس مربعه [ ]
والـ object وهو عبارة عن اقواس عادية { }
كالعادة نحب ان نكون منظمين فقومت بعمل UserTweets bean
package com.jkelany.json;
public class UserTweets {
private String text;
private String date;
private String userName;
private String screenName;
public UserTweets() {
}
public UserTweets(String text, String date, String userName,
String screenName) {
super();
this.text = text;
this.date = date;
this.userName = userName;
this.screenName = screenName;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public String getDate() {
return date;
}
public void setDate(String date) {
this.date = date;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getScreenName() {
return screenName;
}
public void setScreenName(String screenName) {
this.screenName = screenName;
}
@Override
public String toString() {
return screenName + "(" + userName + ") @ " + date + "\n" + text + "\n";
}
}حتى نتمكن من التعامل مع البيانات بشكل منظم ![]()
قومت بتعريف متغيرين احدهما لاسم المستخدم والاخر لرابط الموقع والمثال لدينا على التوتير
private String username = "jkelanycompany"; private final String TWITTER_API_URL = "https://api.twitter.com/1/statuses/user_timeline.json?";
لكى نحصل على البيانات عن طريق الـ JSON قومنا ببناء داله تقوم بذلك
public JSONArray getUserTwittes(String username)
throws ClientProtocolException, IOException, JSONException {
StringBuilder sb = new StringBuilder(TWITTER_API_URL);
sb.append("screen_name=");
sb.append(username);
HttpGet httpGet = new HttpGet(sb.toString());
HttpResponse httpResponse = httpClient.execute(httpGet);
int status = httpResponse.getStatusLine().getStatusCode();
if (status == 200) {
HttpEntity httpEntity = httpResponse.getEntity();
String jsonData = EntityUtils.toString(httpEntity);
return new JSONArray(jsonData);
}
return null;
}سوف نشرحها حالا
فقد قومنا باضافه الكلمة screen_name= على الـ URL وبعدها اسم المستخدم ليكون الشكل النهائى للرابط كما ذكرنا من قبل
StringBuilder sb = new StringBuilder(TWITTER_API_URL);
sb.append("screen_name=");
sb.append(username);اقتباس
لكن بناء داله ووضعها بهذا الشكل لكى نتمكن بعد ذلك بارسال فقط اى اسم مستخدم لهذه الداله نقوم بجلب التدوينات الخاصه بيه ع التويتر
بعدها نقوم بانشاء كائن من الـ HttpGet ونقوم بارسال العنوان كاملا لها لكى تجلب البيانات من هذا العنوان
HttpGet httpGet = new HttpGet(sb.toString());
ثم نقوم بانشاء كائن من الـHttpClient لكى نتعامل مع البرتوكول HTTP وننفذ جلب البيانات عن طريق استدعاء الداله execute على هذا الكائن
وتعود لنا بالـHttpResponse
HttpClient httpClient = new DefaultHttpClient(); HttpResponse httpResponse = httpClient.execute(httpGet);
من الـ HttpResponse نحصل على كود الحاله هل هو مساوى لـ 200 وهو يعنى ان العمليه تمت بنجاح
اذا كانت 200 فمعنى ذلك ان الـ HttpResponse تحتوى على البيانات من الرابط
ويمكن الحصول عليها باستدعاء الداله getEntity على الـhttpResponse
وهى ما تعود لنا بكائن من الـHttpEntity
ومن ثم نريد تحويل هذا الكائن من النوع HttpEntity الى String
نستخدم الداله EntityUtils.toString لعمل ذلك
وبعد ذلك نقوم بارسال قيمه الـ String لانشاء بها JSONArray
وهكذا حصلنا على JSONArray الخاصه بالرد من الموقع
HttpResponse httpResponse = httpClient.execute(httpGet);
int status = httpResponse.getStatusLine().getStatusCode();
if (status == 200) {
HttpEntity httpEntity = httpResponse.getEntity();
String jsonData = EntityUtils.toString(httpEntity);
return new JSONArray(jsonData);
}لكى نحصل على تنفيذ الداله السابقه لابد من استخدام فئة ترث من الـ AsyncTask وهى اللى تجعل التطبيق يقوم بعمل اشياء فى الـBackground
وبعد ان يفرغ يقوم بتنفيذ حدث معين او عرض البيانات فى الشاشه
لماذا سوف نستخدم ذلك لان الحصول على البيانات من الموقع يستغرق وقت فى ذلك
لذلك قومنا ببناء الفئة ReadJSONTwitterData والتى ترث من الفئة AsyncTask
ليكون بالشكل التالى
class ReadJSONTwitterData extends AsyncTask<String, Integer, UserTweets[]> {
@Override
protected UserTweets[] doInBackground(String... params) {
}
@Override
protected void onPostExecute(UserTweets[] twittes) {
}
}لكن ماذا عن String , Integer , UserTweets[]
اول مدخل String وهو يحدد نوع المدخلات للداله doInBackground
ثانى مدخل Integer وهو يحدد قيمه الـ progress وقد تستخدم فى عمل شكل ProgressBar وتحديث القيمه بداخله بهذه القيمه
ثالث مدخل وهو ما يحدد نتيجه الداله doInBackground ومدخلات الداله onPostExecute
ماذا عن الداله doInBackground
هى من تقوم بفعل الاتصال والحصول على البيانات فى خلفيه البرنامج
ماذا عن الداله onPostExecute
هى ما تستدعى عندما تفرغ الداله doInBackground من الحصول على البيانات او فعل الاوامر
ولاستدعاء هذه الفئة نقوم
new ReadJSONTwitterData().execute(KEYS);
ونعطى الداله execute جميع المدخلات التى نريدها وهى هنا عباره عن مصفوفه من النوع String
private String[] KEYS = new String[] { "text", "created_at", "user","screen_name", "name" };حيث ان text هو يمثل مفتاح للحصول على نص التدوينه
created_at وهو ايضا مفتاح للحصول على تاريخ التدوينه
user وهى مفتاح ولكنه يمثل كائن كامل من البيانات
screen_name وهو مفتاح يعبر عن اسم المستخدم على التويتر
name وهو عباره عن مفتاح يمثل الاسم الكامل للشخص على التويتر
@Override
protected UserTweets[] doInBackground(String... params) {
try {
JSONArray jsonArr = getUserTwittes(username);
if (jsonArr != null) {
UserTweets uts[] = new UserTweets[jsonArr.length()];
for (int i = 0; i < uts.length; i++) {
JSONObject ob = jsonArr.getJSONObject(i);
String text = ob.getString(params[0]);
String date = ob.getString(params[1]);
ob = jsonArr.getJSONObject(i).getJSONObject(params[2]);
String username = ob.getString(params[3]);
String name = ob.getString(params[4]);
date = new SimpleDateFormat("EEE, MMMM dd, yyyy hh:mm:ss a")
.format(Date.parse(date));
UserTweets ut = new UserTweets(text, date, username,
name);
uts = ut;
}
return uts;
} else {
return null;
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}نقوم باستدعاء الدالة getUserTwittes داخل الـdoInBackground
وبعدها تعود لنا الـJSONArray
نقوم تفحص هل تحتوى على بيانات ام هى null
ومن ثم نقوم بعمل مصفوفه على حسب عدد التدوينات وهى طول الJSONArray
UserTweets uts[] = new UserTweets[jsonArr.length()];
ونقوم بعمل لووب على عدد التدوينات
JSONObject ob = jsonArr.getJSONObject(i); String text = ob.getString(params[0]); String date = ob.getString(params[1]);
نقوم باخد الـgetJSONObject من المصفوفه الخاصه بالـ jsonArr
وبم انها مصفوفه اساسية نقوم باخد قيمه الـ text , created_at بكل سهولة
لكن بالنسبه الخاصه بالمستخدم فى بيانات داخل كائن user فلذلك لا يمكن الحصول عليها بسهوله كما حصلت على نص وتاريخ التدوينه
سوف نقوم بالدخول على الكائن user الاول وبعدها نقوم بالحصول على البيانات الخاصه به مثل الـ name , screen_name
ob = jsonArr.getJSONObject(i).getJSONObject(params[2]); String username = ob.getString(params[3]); String name = ob.getString(params[4]);
وبعدها نقوم بعمل كائن جديد من الـ UserTweets ووضعه فى مصفوفة الـ uts
بعد ان تقوم هذه الداله بانهاء العمل يتم استدعاء الداله onPostExecute وهى ما تاخد فى مدخلاتها مصفوفه من الـ UserTweets
يتم ارساله مباشره فور الانتهاء من العمل بالداله doInBackground
وهى التى تقوم بفحص البيانات داخل المصفوفه هل تحتوى على بيانات ام null
ومن ثم تعرض رساله خطأ او ترسل البيانات لداله تقوم ببناء البيانات داخل الـ ListView
فهى هذه المره سوف نقوم ببناء الـ Custom Adapter الخاص بالـ listView
لاننا نريد ان تظهر بشكل افضل
لذلك سوف نستخدم الـ SimpleAdapter لعمل ذلك
وهو ما ياخد الـ Context وبعدها list ولكنها عباره عن Hashmap من القيم التى سوف يعمل بينها تواصل لوضعها فى مكانها الصحيح
وبعدها شكل العنصر فى الـ listview هو عباره عن شكل XML تم بناءه عباره عن 3 TextView بشكل جمالى
وبعد ذلك مصفوفه من الـ String تحتوى على الـمفاتيح المستخدمة فى الـ Hashmap
وبعدها مصفوفه من الـ int تحتوى على ids الخاصه بالمكونات الموجود فى الـ View
وهذه هى الداله التى تقوم بذلك
private void setDataToList(UserTweets tweets[]) {
List<HashMap<String, String>> maps = new ArrayList<HashMap<String, String>>();
for (int i = 0; i < tweets.length; i++) {
HashMap<String, String> hm = new HashMap<String, String>();
hm.put(KEYS[0], tweets.getText());
hm.put(KEYS[1], tweets.getDate() + "\n");
hm.put(KEYS[2],
tweets.getScreenName() + "(" + tweets.getUserName()
+ ")");
maps.add(hm);
}
simpleAdapter = new SimpleAdapter(this, maps, R.layout.item_tweet_list,
new String[] { KEYS[0], KEYS[1], KEYS[2] }, new int[] {
R.id.tv_tweet_text, R.id.tv_tweet_date,
R.id.tv_user_info });
tweetsListView.setAdapter(simpleAdapter);
}وهذا هو الكود كاملا
package com.jkelany.json;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import android.app.Activity;
import android.app.ProgressDialog;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.View;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import android.widget.TextView;
public class JSONTwitterActivity extends Activity {
private String username = "jkelanycompany";
private final String TWITTER_API_URL = "https://api.twitter.com/1/statuses/user_timeline.json?";
private ListView tweetsListView;
private TextView twittesTextView;
private HttpClient httpClient;
private SimpleAdapter simpleAdapter;
private String[] KEYS = new String[] { "text", "created_at", "user",
"screen_name", "name" };
private ProgressDialog progressDialog;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
twittesTextView = (TextView) findViewById(R.id.tv_no_tweets);
tweetsListView = (ListView) findViewById(R.id.lv_tweets);
showLoadingDialog();
httpClient = new DefaultHttpClient();
new ReadJSONTwitterData().execute(KEYS);
}
private void showLoadingDialog() {
progressDialog = new ProgressDialog(this);
progressDialog.setCancelable(false);
progressDialog.setMessage("Loading '" + username + "' tweets...");
progressDialog.show();
}
public JSONArray getUserTwittes(String username)
throws ClientProtocolException, IOException, JSONException {
StringBuilder sb = new StringBuilder(TWITTER_API_URL);
sb.append("screen_name=");
sb.append(username);
HttpGet httpGet = new HttpGet(sb.toString());
HttpResponse httpResponse = httpClient.execute(httpGet);
int status = httpResponse.getStatusLine().getStatusCode();
if (status == 200) {
HttpEntity httpEntity = httpResponse.getEntity();
String jsonData = EntityUtils.toString(httpEntity);
return new JSONArray(jsonData);
}
return null;
}
class ReadJSONTwitterData extends AsyncTask<String, Integer, UserTweets[]> {
@Override
protected UserTweets[] doInBackground(String... params) {
try {
JSONArray jsonArr = getUserTwittes(username);
if (jsonArr != null) {
UserTweets uts[] = new UserTweets[jsonArr.length()];
for (int i = 0; i < uts.length; i++) {
JSONObject ob = jsonArr.getJSONObject(i);
String text = ob.getString(params[0]);
String date = ob.getString(params[1]);
ob = jsonArr.getJSONObject(i).getJSONObject(params[2]);
String username = ob.getString(params[3]);
String name = ob.getString(params[4]);
date = new SimpleDateFormat("EEE, MMMM dd, yyyy hh:mm:ss a")
.format(Date.parse(date));
UserTweets ut = new UserTweets(text, date, username,
name);
uts = ut;
}
return uts;
} else {
return null;
}
} catch (Exception e) {
e.printStackTrace();
twittesTextView.setText(e.getMessage());
twittesTextView.setVisibility(View.VISIBLE);
progressDialog.dismiss();
}
return null;
}
@Override
protected void onPostExecute(UserTweets[] twittes) {
if (twittes == null) {
twittesTextView.setVisibility(View.VISIBLE);
twittesTextView
.setText("'"
+ username
+ "' may be not have tweets\nor may be not a twitter user.");
progressDialog.dismiss();
} else {
setDataToList(twittes);
}
}
}
private void setDataToList(UserTweets tweets[]) {
List<HashMap<String, String>> maps = new ArrayList<HashMap<String, String>>();
for (int i = 0; i < tweets.length; i++) {
HashMap<String, String> hm = new HashMap<String, String>();
hm.put(KEYS[0], tweets.getText());
hm.put(KEYS[1], tweets.getDate() + "\n");
hm.put(KEYS[2],
tweets.getScreenName() + "(" + tweets.getUserName()
+ ")");
maps.add(hm);
}
simpleAdapter = new SimpleAdapter(this, maps, R.layout.item_tweet_list,
new String[] { KEYS[0], KEYS[1], KEYS[2] }, new int[] {
R.id.tv_tweet_text, R.id.tv_tweet_date,
R.id.tv_user_info });
tweetsListView.setAdapter(simpleAdapter);
progressDialog.dismiss();
}
}صور من عمل التطبيق
لتحميل الكود
بالتوفيق ان شاء الله