Networking در اندروید
بسم الله الرحمن الرحیم
Networking در اندروید
فصل دهم-بخش اول
در پایان این فصل شما با موارد زیر آشنا می شوید:
چگونه ارتباط به وب بااستفاده از HTTP
چگونه از Xml های مربوط به وب سرویس ها استفاده کنیم
چکونه JSon های وب سرویس ها را به کار گریم.
چگونه با Socket server ارتباط بر قرار کنیم
در فصل قبل شما یاد گرفتید که چگونه میتوانید با استفاده از sms و ایمیل با جهان خارج ارتباط بر قرار کنید. راه دیگری که شما می توانید ارتباط بر قرار کنید استفاده از شبکه های بی سیمی که در دستگاه اندروید می باشد. بنابراین در این فصل شما یاد می گیرید که چگونه با پروتکل HTTP با سرور ارتباط برقرار کنید و چگونه می توانید فایل TEXT یا Bineray را دانلود کنید. همچنین یاد می گیرید که چگونه فایل xml را خوانده و داداه های خود را از آن بازیابی کنیم. قسمت های مختلف فایل را بدست آوردن تکنولوژی که برای دسترسی به وب سرویس ها بسیار قدرتمند میابشد .در کنار XML Web Serviceها JSON (JavaScript Object Notation) را شرح میدهیم . که یک جایگزین سبک(کم حجم) برای جایگزینی XML میباشد کلاس های که در اندروید وجود دارد که شما میتوانید محتوای Json را تغییر دهید.
به کار گیر های web Service ها با استفاده از Http
یک راه رایج برای ارتباط یبا جهان خارج استفاده از HTTP. می باشدکه برای اکثر مردم آشنا می باشد. و این پروتکل باعت بسیاری از موفقیت های وب می باشد
با استفاده از پروتکل Http شما می توانید انواع کار ها را انجام دهید. از قبیل دانلود صفحات وب از وب سرور. دانلود فایل ها باینری و غیره.
در ادامه یک پروژه ایجاد می کنیم و شرح می دهیم که چگونه میتوانید انواه نوع های داده را دانلود کنید.
پروژه جدیدی به نام Networking.ایجاد کنید
فایلAndroidManifest.xml به صورت زیر تغیییر دهید
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.MehrdadJavidi.networking"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="14"
android:targetSdkVersion="15" />
<uses-permission android:name="android.permission.INTERNET" />
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name=".MainActivity"
android:label="@string/title_activity_main" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
فایلmainActivity.java به صورت زیر تغییر دهید.
package com.MehrdadJavidi.networking;
import android.app.Activity;
import android.os.Bundle;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import android.util.Log;
public class MainActivity extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
}
متد به نامOpenHttpConnection() در فایلmainActivity.java تعریف کنید
public class MainActivity extends Activity {
private InputStream OpenHttpConnection(String urlString) throws IOException {
InputStream in = null;
int response = -1;
URL url = new URL(urlString);
URLConnection conn = url.openConnection();
if (!(conn instanceof HttpURLConnection))
throw new IOException("Not an HTTP connection");
try {
HttpURLConnection httpConn = (HttpURLConnection) conn;
httpConn.setAllowUserInteraction(false);
httpConn.setInstanceFollowRedirects(true);
httpConn.setRequestMethod("GET");
httpConn.connect();
response = httpConn.getResponseCode();
if (response == HttpURLConnection.HTTP_OK) {
in = httpConn.getInputStream();
}
} catch (Exception ex) {
Log.d("Networking", ex.getLocalizedMessage());
throw new IOException("Error connecting");
}
return in;
}
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
}
توضیحات
شما از پروتکل HTTPبرای ارتباط با وب استفاده کردید. برنامه شما نیاز به تعریف Permision به نام INTERNET دارد
شما ابتدا این Permisionرادر فایلAndroidManifest.xml تعریف کرده اید. سپس متد OpenHttpConnection() را تعریف کردید. که یک آد رسURL را دریافت می کنید و یک شیInputStream را بر می گرداند با استفاده از شی InputStream شما می توانید داده ها را با خواندن بایت های شی Stream دانلود کنید.
شما یک شیHttpURLConnection را ایجاد کردید که یک ارتباط Http را باURL باز می کنیید
شما Propetyها ی زیادی برای ارتباط دارید. از قبیل متد های درخواست ارتباط و موارد دیگر از این قبیل :
HttpURLConnection httpConn = (HttpURLConnection) conn;
httpConn.setAllowUserInteraction(false);
httpConn.setInstanceFollowRedirects(true);
httpConn.setRequestMethod(“GET”);
بعداز سعی برای ارتباط با سرور. Http یک response codeرابر می گرداند اگر ارتباط با موفقط اتجام شد (response Code برابر HTTP_OK می باشد) شما می توانید شی InputStream را از ارتباط دریافت کنید
httpConn.connect();
response = httpConn.getResponseCode();
if (response == HttpURLConnection.HTTP_OK) {
in = httpConn.getInputStream();
}
با استفاده از شی InputStream شما می توانید دانلود داده ها ر ا از سرور شروع کنید.
دانلود داده ها باینری
یک کار رایج این است که شما باید دانلود داده های باینری را انجام دهید. به ممکن است شما نیاز داربد یک عکس را از وب دانلود کنید و در برنامه نمایش دهید.که در زیر نحوه ای انجام این کار را شرح میدهیم.
به فایل main.xml رفته و آن را به صورت زیر تغییر دهید
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<ImageView
android:id="@+id/img"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center" />
</LinearLayout>
فایلNetworkingActivity.java رابه صورت زیر تغییر دهید
package com.MehrdadJavidi.networking;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.os.Bundle;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import android.util.Log;
import android.widget.ImageView;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
public class MainActivity extends Activity {
ImageView img;
private InputStream OpenHttpConnection(String urlString) throws IOException {
InputStream in = null;
int response = -1;
URL url = new URL(urlString);
URLConnection conn = url.openConnection();
if (!(conn instanceof HttpURLConnection))
throw new IOException("Not an HTTP connection");
try {
HttpURLConnection httpConn = (HttpURLConnection) conn;
httpConn.setAllowUserInteraction(false);
httpConn.setInstanceFollowRedirects(true);
httpConn.setRequestMethod("GET");
httpConn.connect();
response = httpConn.getResponseCode();
if (response == HttpURLConnection.HTTP_OK) {
in = httpConn.getInputStream();
}
} catch (Exception ex) {
Log.d("Networking", ex.getLocalizedMessage());
throw new IOException("Error connecting");
}
return in;
}
private Bitmap DownloadImage(String URL) {
Bitmap bitmap = null;
InputStream in = null;
try {
in = OpenHttpConnection(URL);
bitmap = BitmapFactory.decodeStream(in);
in.close();
} catch (IOException e1) {
Log.d("NetworkingActivity", e1.getLocalizedMessage());
}
return bitmap;
}
private class DownloadImageTask extends AsyncTask<String, Void, Bitmap> {
protected Bitmap doInBackground(String... urls) {
return DownloadImage(urls[0]);
}
protected void onPostExecute(Bitmap result) {
ImageView img = (ImageView) findViewById(R.id.img);
img.setImageBitmap(result);
}
}
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
new DownloadImageTask()
.execute("http://www.mayoff.com/5-01cablecarDCP01934.jpg");
}
}
برنامه را اجرا کنید عکس از وب دانلود شده ودر ImageView. نمایش داده می شود
توضیحات
متد DownloadImage() یک آدرس URL عکس رابرای دانلود دریافت می کند سپس یک ارتباط را با متد OpenHttpConnection() ایجاد می کند. سپس با استفاده از شی InputStream بر گردانده شده از ارتباط . و سپس با متد decodeStream() در کلاسBitmapFactory استفاده می شود برای دانلود و سپس تبدیلDecode آن به شی Bitmap . متدDownloadImage() یک شیBitmap را بر می گرداند.
شما برای دانلود عکس و نمیاش آن در Activity شما از متدDownloadImage() استفاده کردهید. با شروع Android 3.0 عملیات های همزمانی (synchronous) می تواند انجام شود و زمان کمتر را نسب به اجرای مستقیم دانلود در Thred مربوط Ui دارد. اگر شما متد DownloadImage() را به صورت مستقیم درonCreate() استفاده کنید برنامه شما در اندروید های 3 و جدیدتر crash می شود
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
/**---download an image---
---code will not run in Android 3.0 and beyond--*/
Bitmap bitmap =
DownloadImage(“http://www.mayoff.com/5-01cablecarDCP01934.jpg”);
img = (ImageView) findViewById(R.id.img);
img.setImageBitmap(bitmap);
}
از انجا که متد DownloadImage() به صورت همزمان انجام می شود کنترل تازمانی که عکس دانلود نشده است باز گردانده نمی شود. اکر آن را به صورت مستقیم فراخوانی کنید برنامه به حالت Freez می رود ()
تمام کد های همزمانی باید توسط کلاس AsyncTask wrapped شود.
استفاده از کلاس AsyncTask شمار قادر می سازد که کار های را در در background در در Thread های مختلف انجام دهید و نتیجه را به UI بر گردانده شود. با این روش شما می توانید عملیاتی را در background انجام دهید بدون نیاز به اینکه کار پیچیده ای را برای کنترل thrad ها در بر داشته باشد.
برای فراخوانی متد همزمان DownloadImage() . شما نیاز دارید که کد خود را را با subclass به نام AsyncTask wrapکنید مانند زیر:
private class DownloadImageTask extends AsyncTask<String, Void, Bitmap> {
protected Bitmap doInBackground(String... urls) {
return DownloadImage(urls[0]);
}
protected void onPostExecute(Bitmap result) {
ImageView img = (ImageView) findViewById(R.id.img);
img.setImageBitmap(result);
}
}
به طور ساده شما کلاسی به نام DownloadImageTask) ایجاد کردید که از مشتق AsyncTaskشده است . دو متد در کلاس DownloadImageTaskبه نام های doInBackground() وonPostExecute(). می باشد شما تمام کد های که نیاز دارید در background اجرا شود در قرار doInBackground() می دهید. زمانی که task کامل شد. نتیجه کار توسط onPostExecute() بر گزدانده می شود که در اینجا شما یک iamegview میباشد که عکس دانلود شده را نمایش میدهد.
برای فرخوانی کلاسDownloadImageTask شما می توانید یک نمونه ازآن ایجاد کنید و سپس متد execute() صدا بزنیدر سپس آدرس URL عکس که می خواهید به آن ارسال می کنید..
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
new DownloadImageTask()
.execute("http://www.mayoff.com/5-01cablecarDCP01934.jpg");
}
اگر می خواهید یک سری از عکس ها را به طور همزمان دانلود کنید شما می توانید کلاس DownloadImageTaskبه صورت زیر تغییر دهید
package com.MehrdadJavidi.networking;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.os.Bundle;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import android.util.Log;
import android.widget.ImageView;
import android.widget.Toast;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
public class MainActivity extends Activity {
ImageView img;
private InputStream OpenHttpConnection(String urlString) throws IOException {
InputStream in = null;
int response = -1;
URL url = new URL(urlString);
URLConnection conn = url.openConnection();
if (!(conn instanceof HttpURLConnection))
throw new IOException("Not an HTTP connection");
try {
HttpURLConnection httpConn = (HttpURLConnection) conn;
httpConn.setAllowUserInteraction(false);
httpConn.setInstanceFollowRedirects(true);
httpConn.setRequestMethod("GET");
httpConn.connect();
response = httpConn.getResponseCode();
if (response == HttpURLConnection.HTTP_OK) {
in = httpConn.getInputStream();
}
} catch (Exception ex) {
Log.d("Networking", ex.getLocalizedMessage());
throw new IOException("Error connecting");
}
return in;
}
private Bitmap DownloadImage(String URL) {
Bitmap bitmap = null;
InputStream in = null;
try {
in = OpenHttpConnection(URL);
bitmap = BitmapFactory.decodeStream(in);
in.close();
} catch (IOException e1) {
Log.d("NetworkingActivity", e1.getLocalizedMessage());
}
return bitmap;
}
private class DownloadImageTask extends AsyncTask<String, Bitmap, Long> {
/** ---takes in a list of image URLs in String type---*/
protected Long doInBackground(String... urls) {
long imagesCount = 0;
for (int i = 0; i < urls.length; i++) {
/** ---download the image---*/
Bitmap imageDownloaded = DownloadImage(urls[i]);
if (imageDownloaded != null) {
/** ---increment the image count--- */
imagesCount++;
try {
/** ---insert a delay of 3 seconds--- */
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
/** ---return the image downloaded--- */
publishProgress(imageDownloaded);
}
}
/** ---return the total images downloaded count---*/
return imagesCount;
}
/** ---display the image downloaded---*/
protected void onProgressUpdate(Bitmap... bitmap) {
img.setImageBitmap(bitmap[0]);
}
/** ---when all the images have been downloaded---*/
protected void onPostExecute(Long imagesDownloaded) {
Toast.makeText(getBaseContext(),
"Total " + imagesDownloaded + " images downloaded",
Toast.LENGTH_LONG).show();
}
}
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
new DownloadImageTask()
.execute("http://daryon.ir/wp-content/uploads/iran.gif");
}
}
توجه کنید که در این کلاس متد های بیشتری وجود دارد onProgressUpdate(). زیرا کار های که میتواند در کلاسAsyncTask اجرا شوند می توانید زمان های طولانی داشته باشد.
شما می توانید متدpublishProgress() را برای بر روز رسانی روند پیشرفت عملیات فراخوانی کنید با فراخوانی متدonProgressUpdate() که در این صورت عکس های دانلود شده نمیاش داده می شود. متد onProgressUpdate()در Thrad UI اجرا می شود. با این حال یک thread-safe برای به روز رسانی imageView که bitmap دانلود شده از سرور را نمایش می دد می باشد
برای دانلود یک سری از عکس ها از سرور در background شما می توانید یک نمونه ازDownloadImageTask() را ایجاد کنید و متد execute() را مانند زیر فراخوانی کنید
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
img = (ImageView) findViewById(R.id.img);
new DownloadImageTask()
.execute(
"http://www.mayoff.com/5-01cablecarDCP01934.jpg",
"http://www.hartiesinfo.net/greybox/Cable_Car_Hartbeespoort.jpg",
"http://mcmanuslab.ucsf.edu/sites/default/files/imagepicker/m/mmcmanus/CaliforniaSanFranciscoPaintedLadiesHz.jpg",
"http://www.fantom-xp.com/wallpapers/63/San_Francisco _-_Sunset.jpg",
"http://travel.roro44.com/europe/france/Paris_France.jpg",
"http://wwp.greenwichmeantime.com/time-zone/usa/nevada /las-vegas/hotel/the-strip/paris-las-vegas/parislas- vegas-hotel.jpg",
"http://designheaven.files.wordpress.com/2010/04/eiffel_tower_paris_france.jpg");
}
زمانی که کد قبلی را اجرا می کنید تصاویر در background دانلود بعد از گذشت چند ثانیه نمایش داده می شوند. زمانی که آخرین عکس دانلود شده یک پیغام مبنی بر دانلود تعداد عکس ها با کلاس Toast نمایش داده می شود.
دانلود محتوای متنی
در کنار دانلود داد های باینری شما می توانید شما می توانید داد های با محتوای متنی نیز هم دانلود کنید. به عنوان مثال شما ممکن است شما می خواهید به یک وب سرویس که یک فایل شامل که رشته نقل قول های متفاوت دارد دسترسی داشته باشید. که در ادامه به شما شرح می دهیم که چگونه میتوانید این کار را انجام دهید.
به فایلNetworkingActivity.java رفته و دستورات زیر را به آن اضافه کنید
private String DownloadText(String URL) {
int BUFFER_SIZE = 2000;
InputStream in = null;
try {
in = OpenHttpConnection(URL);
} catch (IOException e) {
Log.d("Networking", e.getLocalizedMessage());
return "";
}
InputStreamReader isr = new InputStreamReader(in);
int charRead;
String str = "";
char[] inputBuffer = new char[BUFFER_SIZE];
try {
while ((charRead = isr.read(inputBuffer)) > 0) {
/ ---convert the chars to a String---*/
String readString = String
.copyValueOf(inputBuffer, 0, charRead);
str += readString;
inputBuffer = new char[BUFFER_SIZE];
}
in.close();
} catch (IOException e) {
Log.d("Networking", e.getLocalizedMessage());
return "";
}
return str;
}
private class DownloadTextTask extends AsyncTask<String, Void, String> {
protected String doInBackground(String... urls) {
return DownloadText(urls[0]);
}
@Override
protected void onPostExecute(String result) {
Toast.makeText(getBaseContext(), result, Toast.LENGTH_LONG).show();
}
}
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
new DownloadTextTask().execute(
"http://iheartquotes.com/api/v1/random?max_characters=256&max_lines=10");
}
برنامه را اجرا کنید. فایل را بر میگردانیم و آن را با کلاسToast نمایش میدهیم.
توضیحات
متدDownloadText() یک پارامتر URL که آدرس فایل مورد نظر می باشد را دریافت و آن را دانلود می کند.
به طور اساسی: شما یک ارتباط Http با سرور ب باز کردید. سپس شیInputStreamReader هر کاراکتر را Stream می خواند ودر شی String ذخیر ه می کنید. همانند قبل شما یک زیر کلاس AsyncTask ایجاد کردید برای متد DownloadText() که بتوانید به طور همزمان آن را به کار بربد.
دسترسی به وب سرویس ها از طرق متد GET
در بخش های شما یاد گرفتید که چگونه می توانید فایل های باینری و متنی را دانلود کنید. شما اغلب نیاز داربد که فایل های Xml را دانلود کنید وان را تجزیه و تحلیل کنید
در این قسمت شما یاد میگیرید که چگونه می توانید به وب سرویسی متصل شوید با استفاده از متد Get مربوط به Http. نتیجه یک وب سرویس Xml میباشد. شما آن را دانلود میکنید و آن تجزیه و تحلیل میکنید و محتوانی آن را نمایش میدهید.
دراین مثال شما از از متد وب در http://services.aonaware.com/DictService/DictService.asmx?op=Define استفاده می کنید این متد وب یک وب سرویس دیکشنری است که توضیحات در مورد یک کلمه را بر می گرداند.
این متد درخواستی به شکل زیر دریافت می کند.
GET /DictService/DictService.asmx/Define?word=string HTTP/1.1
Host: services.aonaware.com
HTTP/1.1 200 OK
Content-Type: text/xml; charset=utf-8
Content-Length: length
و پاسخ آن به شکل زیر می باشد
<?xml version=”1.0” encoding=”utf-8”?>
<WordDefinition xmlns=”http://services.aonaware.com/webservices/”>
<Word>string</Word>
<Definitions>
<Definition>
<Word>string</Word>
<Dictionary>
<Id>string</Id>
<Name>string</Name>
</Dictionary>
<WordDefinition>string</WordDefinition>
</Definition>
<Definition>
<Word>string</Word>
<Dictionary>
<Id>string</Id>
<Name>string</Name>
</Dictionary>
<WordDefinition>string</WordDefinition>
</Definition>
</Definitions>
</WordDefinition>
از این رو برای بدست آوردن توضیحات یک کلمه شما نیاز به ایجاد یک ارتباط Http داردید و سپس شما باید فایل Xml دریافتی تجزیه و تحلیل کنید.. که در ادامه آن را با مثال شرح میدهیم.
به برنامه قبل بروید و فایلNetworkingActivity.java به صورت زیر تغییر دهید.
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
private String WordDefinition(String word) {
InputStream in = null;
String strDefinition = "";
try {
in = OpenHttpConnection("http://services.aonaware.com/DictService/DictService.asmx/Define?word="
+ word);
Document doc = null;
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db;
try {
db = dbf.newDocumentBuilder();
doc = db.parse(in);
} catch (ParserConfigurationException e) {
/** TODO Auto-generated catch block */
e.printStackTrace();
} catch (Exception e) {
/** TODO Auto-generated catch block */
e.printStackTrace();
}
doc.getDocumentElement().normalize();
/** ---retrieve all the <Definition> elements--- */
NodeList definitionElements = doc
.getElementsByTagName("Definition");
/** ---iterate through each <Definition> elements--- */
for (int i = 0; i < definitionElements.getLength(); i++) {
Node itemNode = definitionElements.item(i);
if (itemNode.getNodeType() == Node.ELEMENT_NODE) {
/** ---convert the Definition node into an Element--- */
Element definitionElement = (Element) itemNode;
/** ---get all the <WordDefinition> elements under
the <Definition> element--- */
NodeList wordDefinitionElements = ((Document) definitionElement)
.getElementsByTagName("WordDefinition");
strDefinition = "";
/** ---iterate through each <WordDefinition> elements---*/
for (int j = 0; j < wordDefinitionElements.getLength(); j++) {
/** ---convert a <WordDefinition> node into an Element--- */
Element wordDefinitionElement = (Element) wordDefinitionElements
.item(j);
/** ---get all the child nodes under the
<WordDefinition> element--- */
NodeList textNodes = ((Node) wordDefinitionElement)
.getChildNodes();
strDefinition += ((Node) textNodes.item(0))
.getNodeValue() + ". \n";
}
}
}
} catch (IOException e1) {
Log.d("NetworkingActivity", e1.getLocalizedMessage());
}
/** ---return the definitions of the word--- */
return strDefinition;
}
private class AccessWebServiceTask extends AsyncTask<String, Void, String> {
protected String doInBackground(String... urls) {
return WordDefinition(urls[0]);
}
protected void onPostExecute(String result) {
Toast.makeText(getBaseContext(), result, Toast.LENGTH_LONG).show();
}
}
/*** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
/** ---access a Web Service using GET---*/
new AccessWebServiceTask().execute("apple");
برنامه را اجرا نماید و خروجی را باکلاس Toast نمایشن می دهیم
توضیحات
متدWordDefinition() ابتدایک ارتباط Httpیا وب سرویس باز می کند. وسپس کلمه موردنظر را مانند زیر به آن ارسال می کند.
in = OpenHttpConnection("http://services.aonaware.com/DictService/DictService.asmx/Define?word="
+ word);
سپس شما از شی های DocumentBuilderFactory and DocumentBuilder استفاده کرده است که شی Document (DOM) از فایل XML را در بر می گیرند(نتیجه بر گردانده شده از وب سرویس می باشد)
Document doc = null;
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db;
try {
db = dbf.newDocumentBuilder();
doc = db.parse(in);
} catch (ParserConfigurationException e) {
/** TODO Auto-generated catch block */
e.printStackTrace();
} catch (Exception e) {
/** TODO Auto-generated catch block */
e.printStackTrace();
}
doc.getDocumentElement().normalize();
زمانی که شما شی Document را ایجاد شد.شما تمام عنصر های <Definition> را جست و جو می کنید
NodeList definitionElements = doc
.getElementsByTagName("Definition");
در شکل زیر شما XML باز گردانده شده توسط xml را مشاهد می کنید.
تمام توضیحات در مورد کلمه در عنصر <WordDefinition> می باشد که شما باید آنها را باز یابی کنید
for (int i = 0; i < definitionElements.getLength(); i++) {
Node itemNode = definitionElements.item(i);
if (itemNode.getNodeType() == Node.ELEMENT_NODE) {
/** ---convert the Definition node into an Element--- */
Element definitionElement = (Element) itemNode;
/** ---get all the <WordDefinition> elements under */
/** the <Definition> element--- */
NodeList wordDefinitionElements = ((Document) definitionElement)
.getElementsByTagName("WordDefinition");
strDefinition = "";
/** ---iterate through each <WordDefinition> elements--- */
for (int j = 0; j < wordDefinitionElements.getLength(); j++) {
/** ---convert a <WordDefinition> node into an Element--- */
Element wordDefinitionElement = (Element) wordDefinitionElements
.item(j);
/** ---get all the child nodes under the
<WordDefinition> element--- */
NodeList textNodes = ((Node) wordDefinitionElement)
.getChildNodes();
strDefinition += ((Node) textNodes.item(0))
.getNodeValue() + ". \n";
}
}
}
در کد بالا شما تمام <WordDefinition>در <Definition> را چک می کنید و محتوای متنی عنصر که<WordDefinition> شامل یک توضیح در مورد کلمه می باشد, و سپس توضیحات از کلمه های را به هم concat می کند (به همی می چسباند ) وسپس متد WordDefinition() را بر می گرداند
/** ---return the definitions of the word--- */
return strDefinition;
سپس شما باید یک زیر کلاس از AsyncTask ایجاد کنید برای فراخوانی متدWordDefinition() به صورت همزمان.
private class AccessWebServiceTask extends AsyncTask<String, Void, String> {
protected String doInBackground(String... urls) {
return WordDefinition(urls[0]);
}
protected void onPostExecute(String result) {
Toast.makeText(getBaseContext(), result, Toast.LENGTH_LONG).show();
}
}
سپس با فراخوانی متد execute() می توانید به صورت همزمان به وب سرویس دسترسی داشته باشد
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
/** ---access a Web Service using GET--- */
new AccessWebServiceTask().execute("apple");
}
اجرای سرویس های Json
در قمست قبل شما یاد گرفتید که چگونه می توان Xml Web Servise ها را با استفاده از Http برای اتصا ل به وب سرویس و باز کرداندن نتیجه Xml استفاده کنید. همچنین شما از DOM برای تجزیه کردن فایلXML استفاده کردید استفاده از فایل های xml عملیات پر هزینه ای برای دستگاه های اندروید می باشد که دلایل آن به شرح زیر میباشد:
Xml ها فایل های بزرگی هستند. انها از تگ ها برای ذخیزه اطلاعات استفاده می کنند که این کار باعت می شود حجم آن سریع افزایش یابد. یک فایل بزرگ xml به این معنی است که دانلود آن پهنای باند زیادی را استفاده می کند.
پردازش فایل های بسیار مشکل می باشد. همان طور که در قسمت قبل مشاهده کردید شما ازDOM برای پیمایش درختی آن و دسترسی به محتوای آن استفاده کرد اید.وقبل از پیمایش درختی خود Dom هم باید ساخته شود و ساختار درختی ان در حافظه ایجاد شود. که این خود حافظه و پردازنده را مصرف می کند
یکی از را های بسیار کارامد تر برای نمایش اطلاعات استفاده از Json میباشد. Json یک قالب داده ای تغیر پذیر کم حجم می باشد(کم حجم و به سادگی فایل تغییر می باشد) و به سادگی می توان از آن را خواند و در آن نوشت.
وبه آسانی ماشین(موبایل و کامپیوتر و...) آن را تولید و تجزیه می کند می کند درزیز نمونه از پیام های json را مشاهد می کنید.
[
{
“appeId”:”1”,
“survId”:”1”,
“location”:””,
“surveyDate”:”2008-03 14”,
“surveyTime”:”12:19:47”,
“inputUserId”:”1”,
“inputTime”:”2008-03-14 12:21:51”,
“modifyTime”:”0000-00-00 00:00:00”
},
{
“appeId”:”2”,
“survId”:”32”,
“location”:””,
“surveyDate”:”2008-03-14”,
“surveyTime”:”22:43:09”,
“inputUserId”:”32”,
“inputTime”:”2008-03-14 22:43:37”,
“modifyTime”:”0000-00-00 00:00:00”
},
{
“appeId”:”3”,
“survId”:”32”,
“location”:””,
“surveyDate”:”2008-03-15”,
“surveyTime”:”07:59:33”,
“inputUserId”:”32”,
“inputTime”:”2008-03-15 08:00:44”,
“modifyTime”:”0000-00-00 00:00:00”
},
{
“appeId”:”4”,
“survId”:”1”,
“location”:””,
“surveyDate”:”2008-03-15”,
“surveyTime”:”10:45:42”,
“inputUserId”:”1”,
“inputTime”:”2008-03-15 10:46:04”,
“modifyTime”:”0000-00-00 00:00:00”
},
{
“appeId”:”5”,
“survId”:”32”,
“location”:””,
“surveyDate”:”2008-03-16”,
“surveyTime”:”08:04:49”,
“inputUserId”:”32”,
“inputTime”:”2008-03-16 08:05:26”,
“modifyTime”:”0000-00-00 00:00:00”
},
{
“appeId”:”6”,
“survId”:”32”,
“location”:””,
“surveyDate”:”2008-03-20”,
“surveyTime”:”20:19:01”,
“inputUserId”:”32”,
“inputTime”:”2008-03-20 20:19:32”,
“modifyTime”:”0000-00-00 00:00:00”
}
]
در بلاک بالا مجموعه از داده ها را نمایش می دهد. توجه کنید که اطلاعات در قالب جفت های key/value می باشد و گروه از جفت هایkey/value در قالب یک orderlist قرار گرفته اند. برخلاف xml ها که از tag ها استفاده می کنند اینجا از اکولاد ها و براکت ها استفاده می کنند. در زیر به شما شرح می دهیم که چگونه می توان پیام های json را با استفاده از شی هایJSONArray و JSONObjectکه در Sdk میباشند را پردازش کرد
پروژه جدیدی به نام JSON.ایجاد کنید
فایلAndroidManifest.xml به صورت زیر تغییر دهید
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.MehrdadJavidi.json"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="14"
android:targetSdkVersion="15" />
<uses-permission android:name="android.permission.INTERNET" />
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name=".MainActivity"
android:label="@string/title_activity_main" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
کد های زیر در فایل mainActivity.java وارد نمایید.
package com.MehrdadJavidi.json;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.StatusLine;
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.json.JSONArray;
import org.json.JSONObject;
import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.widget.Toast;
public class MainActivity extends Activity {
public String readJSONFeed(String URL) {
StringBuilder stringBuilder = new StringBuilder();
HttpClient client = new DefaultHttpClient();
HttpGet httpGet = new HttpGet(URL);
try {
HttpResponse response = client.execute(httpGet);
StatusLine statusLine = response.getStatusLine();
int statusCode = statusLine.getStatusCode();
if (statusCode == 200) {
HttpEntity entity = response.getEntity();
InputStream content = entity.getContent();
BufferedReader reader = new BufferedReader(
new InputStreamReader(content));
String line;
while ((line = reader.readLine()) != null) {
stringBuilder.append(line);
}
} else {
Log.e("JSON", "Failed to download file");
}
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return stringBuilder.toString();
}
private class ReadJSONFeedTask extends AsyncTask<String, Void, String> {
protected String doInBackground(String... urls) {
return readJSONFeed(urls[0]);
}
protected void onPostExecute(String result) {
try {
JSONArray jsonArray = new JSONArray(result);
Log.i("JSON",
"Number of surveys in feed: " + jsonArray.length());
/** ---print out the content of the json feed--- */
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject jsonObject = jsonArray.getJSONObject(i);
Toast.makeText(
getBaseContext(),
jsonObject.getString("appeId") + " - "
+ jsonObject.getString("inputTime"),
Toast.LENGTH_SHORT).show();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
new ReadJSONFeedTask()
.execute("http://extjs.org.cn/extjs/examples/grid/survey.html");
}
}
برنامه را اجر ا کنید. شما یک Toast را مشاهده می کنید که زمان و تاریخ را نمایش می دهد.
توضیحات
اولین کاری که شما باید انجا دادید متد readJSONFeed()را تعریف کردید.
public String readJSONFeed(String URL) {
StringBuilder stringBuilder = new StringBuilder();
HttpClient client = new DefaultHttpClient();
HttpGet httpGet = new HttpGet(URL);
try {
HttpResponse response = client.execute(httpGet);
StatusLine statusLine = response.getStatusLine();
int statusCode = statusLine.getStatusCode();
if (statusCode == 200) {
HttpEntity entity = response.getEntity();
InputStream content = entity.getContent();
BufferedReader reader = new BufferedReader(
new InputStreamReader(content));
String line;
while ((line = reader.readLine()) != null) {
stringBuilder.append(line);
}
} else {
Log.e("JSON", "Failed to download file");
}
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return stringBuilder.toString();
}
به طور ساده این متد به ادرس URI مشخص شده وصل می شود. و سپس نتایج را از وب سرور می خواند ویک string را به عنوان نتیجه بر می گردند.
برای فراخوانی مندreadJSONFeed() به طور همزمان . شما یک زیر کلاس ازAsyncTask ایجاد کردید
private class ReadJSONFeedTask extends AsyncTask<String, Void, String> {
protected String doInBackground(String... urls) {
return readJSONFeed(urls[0]);
}
protected void onPostExecute(String result) {
try {
JSONArray jsonArray = new JSONArray(result);
Log.i("JSON",
"Number of surveys in feed: " + jsonArray.length());
/** ---print out the content of the json feed--- */
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject jsonObject = jsonArray.getJSONObject(i);
Toast.makeText(
getBaseContext(),
jsonObject.getString("appeId") + " - "
+ jsonObject.getString("inputTime"),
Toast.LENGTH_SHORT).show();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
شما متد readJSONFeed()را در متد doInBackground() فرخوانی کردید سپس string , json را بدست آورید (Fetch کردید) و به متد onPostExecute() ارسال کردید. متن json ازhttp://extjs.org.cn/extjs/examples/grid/survey.html استفاده شده است برای بدست آوردن لیست از شی های json از متن Json شما از کلاس JSONArrayاستفاده کرده اید که JSON feedرا به سازنده آن ارسال می کنید
JSONArray jsonArray = new JSONArray(result);
Log.i("JSON",
"Number of surveys in feed: " + jsonArray.length());
length() تعداد شی های که شیjsonArray بر میگرداند را مشخص می کند. با لیستی از jsonArray ذخیره شده در jsonArray. شما با متد getJSONObject() هر شی را بدیت می آورید.
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject jsonObject = jsonArray.getJSONObject(i);
Toast.makeText(
getBaseContext(),
jsonObject.getString("appeId") + " - "
+ jsonObject.getString("inputTime"),
Toast.LENGTH_SHORT).show();
}
متد getJSONObject() یک شی از نوعJSONObject. بر میگرداند. برای گرفتن مقادیر value های که در جفت key/value می باشد شما از متد getString() استفاده میکنید(شما همچنیم میتوانید از getInt(),و getLong(),و getBoolean() برای دیگر نوع داد های استفاده مکنید)
در اخر هم شما برا دستری همزمان به json ازexecute() استفاده کرده اید
new ReadJSONFeedTask()
.execute("http://extjs.org.cn/extjs/examples/grid/survey.html");
در این مثال شما یاد گرفتید که چگونه وب سرویس json را استفاده کنید و به طور ساده و سریع آن را تجزیه و تحلیل کنید. برای مثال های واقعی و در زندگی واقعی شما از Twiter استفاده می کنید.
برانامه را به صورت زیر تغییر دهید که twit های اخیر در twiyer بدست آورید وسپس twits ها را راباکلاسtoast نمایش دهید
private class ReadJSONFeedTask extends AsyncTask<String, Void, String> {
protected String doInBackground(String... urls) {
return readJSONFeed(urls[0]);
}
protected void onPostExecute(String result) {
try {
JSONArray jsonArray = new JSONArray(result);
Log.i("JSON",
"Number of surveys in feed: " + jsonArray.length());
/** ---print out the content of the json feed--- */
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject jsonObject = jsonArray.getJSONObject(i);
/**
* Toast.makeText(getBaseContext(),
* jsonObject.getString("appeId") + " - " +
* jsonObject.getString("inputTime"),
* Toast.LENGTH_SHORT).show();
*/
Toast.makeText(
getBaseContext(),
jsonObject.getString("text") + " - "
+ jsonObject.getString("created_at"),
Toast.LENGTH_SHORT).show();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
/*
* new ReadJSONFeedTask().execute(
* "http://extjs.org.cn/extjs/examples/grid/survey.html");
*/
new ReadJSONFeedTask()
.execute("https://twitter.com/statuses/user_timeline/weimenglee.json");
}