دریافت اطلاعات متنی از سرور اینترنتی (یک URL)، با روش json و پردازش اطلاعات دریافتی با کلاس های (class) مرتبط با روش json و همچنین نمایش اطلاعات در یک ListView (به همراه تست برنامه اندروید برای متن فارسی)، در برنامه نویسی اندروید
در مباحثی دیگر، شرح دادیم که برای دریافت اطلاعات متنی از سرور اینترنتی، روش های زیر را می توانیم به کار ببریم (در واقع، ساختار متن) :
1- متن ساده
2- متن با ساختار xml
3- متن با ساختار json
و ...
مسلما در اطلاعات متنی، باید ساختاری خاص داشته باشیم تا بتوانیم مقادیر مربوط به هر متغیر را دقیقا متوجه بشویم. برای استفاده از متن ساده، باید خودمان یک نوع علامت گذاری ابداع کنیم و سپس بر اساس آن، با کلاس های (class) کار با رشته ها (string)، بر اساس نوع علامت گذاری، اطلاعات را از متن ساده دریافت شده، استخراج کنیم، اما برنامه نویس قرار نیست که وقت خود را برای این موارد صرف کند، بلکه بهتر است از ساختارهایی که قبلا به عنوان یک استاندارد در آمده اند و کلاس هایی (class) هم برای کار با آنها طراحی شده است، استفاده کند. در این مورد، دو روش xml و json ، دو استاندارد قابل قبول می باشند. اما چرا ما از بین این دو، روش json را انتخاب می کنیم ؟ اگر مباحث دیگر سایت کلیدستان را خوانده باشید، مشاهده کرده اید که من تقریبا برای تمامی موارد دریافت اطلاعات متنی از سرور اینترنتی، روش json را توصیه کرده ام. دلیل این انتخاب این است که اگر نوع علامت گذاری روش های xml و json را با یکدیگر مقایسه کنید، مشاهده می کنید که روش json برای ساخت ساختار متن، تعداد کاراکتر کمتری به کار می برد و بنابراین متن نهایی، حجم کمتری خواهد داشت، ولی روش xml باعث می شود که حجم متن نهایی (متن ساختاریافته به شکل xml) بیشتر از روش json باشد. شاید این مسئله برای یک برنامه ساده که حداکثر تعداد کاربر آن به 500 کاربر می رسد، اهمیتی نداشته باشد، اما مثلا برای یک بازی اندروید آنلاین که ممکن است به صورت هم زمان، بین 5000 تا 100000 کاربر به سرور اینترنتی متصل شوند و به تبادل اطلاعات با سرور بپردازند، بسیار با اهمیت خواهد بود.
حال که اهمیت روش json را متوجه شده اید، بهتر است که ساختار آن را به شما نمایش بدهم. من یک حالت ساده را در نظر می گیرم، همینکه با روش json و نحوه دریافت اطلاعات به روش json آشنا شوید، سپس می توانید به سراغ ساختارهای پیچیده تر بروید.
معمولا در برنامه های اندروید که با اینترنت سر و کار داریم، ابتدا کدهایی را اجرا می کنند که وضعیت اتصال گوشی اندروید به اینترنت را چک می کند. ما چگونگی این فرآیند را در آموزش شماره 2408 شرح دادیم، اما برای اینکه این پروژه اندروید، شلوغ نشود و شما از حجم زیاد کدها، گیج نشوید، این مورد را در این پروژه به کار نمی بریم، بنابراین لطفا قبل از تست کردن برنامه اندروید، اطمینان حاصل کنید که گوشی شما به اینترنت متصل باشد.
ساخت فایل حاوی متن با ساختار json و قرار دادن آن در سرور اینترنتی :
فرض کنید که اطلاعاتی که قرار است از سرور اینترنتی دریافت کنیم، نام و مشخصات 10 فرد می باشد (من عمدا اطلاعات را با یک کلمه ثابت و یک پسوند متغیر انتخاب کرده ام تا کلمات مختلف، شما را گیج نکند) :
id فرد | نام فرد | شهر سکونت فرد | |
نام گره (node) در روش json | id | name | city |
فرد اول | id_1 | name_1 | city_1 |
فرد دوم | id_2 | name_2 | city_2 |
فرد سوم | id_3 | name_3 | city_3 |
فرد چهارم | id_4 | name_4 | city_4 |
فرد پنجم | id_5 | name_5 | city_5 |
فرد ششم | id_6 | name_6 | city_6 |
فرد هفتم | id_7 | name_7 | city_7 |
فرد هشتم | id_8 | name_8 | city_8 |
فرد نهم | id_9 | name_9 | city_9 |
فرد دهم | id_10 | name_10 | city_10 |
اکنون باید اطلاعات فوق را در یک فایل ذخیره کنیم تا برنامه اندروید، آن فایل را بخواند. من نوع فایل را html انتخاب می کنم و متن درون آن به صورت زیر خواهد بود (متن با ساختار json) :
{ "id": "id_1", "name": "name_1", "city": "city_1" } ,
{ "id": "id_2", "name": "name_2", "city": "city_2" } ,
{ "id": "id_3", "name": "name_3", "city": "city_3" } ,
{ "id": "id_4", "name": "name_4", "city": "city_4" } ,
{ "id": "id_5", "name": "name_5", "city": "city_5" } ,
{ "id": "id_6", "name": "name_6", "city": "city_6" } ,
{ "id": "id_7", "name": "name_7", "city": "city_7" } ,
{ "id": "id_8", "name": "name_8", "city": "city_8" } ,
{ "id": "id_9", "name": "name_9", "city": "city_9" } ,
{ "id": "id_10", "name": "name_10", "city": "city_10" }
]}
در متن بالا، kelidestan یک JSONArray (آرایه json) است و id و name و city ، سه گره (node) برای آن JSONArray (آرایه json) می باشند. امکان تعریف چند JSONArray (آرایه json) دیگر هم بود (به تعداد دلخواه)، اما برای سادگی، تنها یکی نوشته ایم.
دقت کنید که من به طور ساده، دقیقا همین متن را در فایل html کپی می کنم، بنابراین مراقب باشید که هیچ کد html ای را نباید در فایل مورد نظر بنویسید (این مورد را قبلا در آموزش شماره 291 تذکر داده بودیم).
اگرچه ما متن را به صورت ساده می نویسیم، ولی معمولا ساختار برنامه های اندروید با اطلاعات آنلاین، به این صورت است که اطلاعات در پایگاه داده می باشد و در صفحه اینترنتی مورد نظر، کدهایی نوشته می شود که اطلاعات را از پایگاه داده دریافت کند و سپس با پردازش آنها، اطلاعات را با ساختار json ، در خروجی نمایش خواهد داد (این مورد را در آموزش شماره 2546 شرح داده ایم). ولی فعلا به این مسائل کاری نداریم و تنها قصد داریم که روش json را شرح بدهیم.
فایل html را ساخته و آن را در آدرس زیر در سرور سایت کلیدستان قرار می دهم :
اگر دقت کنید، فایل مورد نظر، در پوشه ای (folder) با نام fixed-url در سایت کلیدستان قرار داده شده است، این پوشه، برای فایل هایی است که دیگر تحت هیچ شرایطی، آدرس URL فایل های درون آن و یا محتویات فایل های آن را تغییر نمی دهیم، بنابراین شما با خیال راحت، برای همیشه می توانید برای تست پروژه های اندروید کلیدستان و یا پروژه های اندروید نوشته شده توسط خودتان، از آنها استفاده کنید.
خوب حالا باید پروژه اندروید را بسازیم. دقت کنید که فایل های پروژه اندروید این مبحث و همچنین فایل apk ساخته شده از آن، در انتهای مبحث، قابل دانلود می باشند و بنابراین می توانید فایل های پروژه اندروید را دانلود کنید و همزمان با توضیحات من، نگاهی به آن بیندازید (البته در خود مبحث نیز من کدها را ذکر کرده و شرح می دهم).
خروجی برنامه به این صورت خواهد بود که در حین دریافت اطلاعات از سرور اینترنتی، یک ProgressDialog به کابر نمایش داده می شود (برای نمایش در حال اجرا بودن کدها) و سپس ProgressDialog حذف شده و خروجی برنامه اندروید، به صورت زیر نمایش داده می شود (لیست اطلاعات) :

نام پروژه اندروید را برابر Json انتخاب کرده ایم (نام package برابر com.kelidestan.json انتخاب شده است. نام activity اصلی را برابر MainActivity انتخاب کرده ایم و فایل xml متناظر آن را هم برابر activity_main قرار داده ایم).
اجازه دسترسی به اینترنت :
قبل از هر چیز، چون قرار است که با اینترنت سر و کار داشته باشیم، باید اجازه دسترسی به اینترنت، به برنامه اندروید داده شود (همان اول آن را می نویسیم تا فراموش نشود، در غیر این صورت، یک force close ایجاد شده و برنامه اندروید بسته می شود). برای این منظور، کد زیر را باید در فایل Androidmanifest.xml از پروژه اندروید، بنویسیم :
بنابراین کل کدهای فایل Androidmanifest.xml به صورت زیر خواهد بود :
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.kelidestan.json"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="18" />
<uses-permission android:name="android.permission.INTERNET" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="com.kelidestan.json.MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
ساخت کلاس JSONParser :
در هر پروژه اندرویدی که با روش json برای دریافت اطلاعات (اطلاعات ساختاریافته با روش json) از یک آدرس اینترنتی (آدرس URL) سر و کار داریم، باید یک کلاس (class) با عنوان JSONParser بسازیم (یک کلاس به صورت یک فایل جداگانه). کاری که کلاس JSONParser انجام می دهد این است که ما به آن، آدرس URL مربوط به فایل حاوی اطلاعات ساختاریافته با روش json را می دهیم و سپس کلاس JSONParser ، یک JSONObject به ما می دهد که در آن، همان اطلاعات ذخیره شده است و ما با استفاده از سایر کلاس های (class) تعریف شده برای کار با JSONObject ، می توانیم اطلاعات مورد نظرمان را از آن استخراج کنیم.
کدهای JSONParser در اکثر پروژه های اندروید، یکسان است و معمولا افراد کدها را از اینترنت دریافت می کنند و نیازی هم نیست که از نحوه عملکرد آن، اطلاعی داشته باشید. بننابراین در پروژه اندروید، یک کلاس (class) با نام JSONParser می سازیم :

کدهای کلاس JSONParser را به صورت زیر می نویسیم :
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.json.JSONException;
import org.json.JSONObject;
import android.util.Log;
public class JSONParser {
static InputStream is = null;
static JSONObject jObj = null;
static String json = "";
// constructor
public JSONParser() {
}
public JSONObject getJSONFromUrl(String url) {
// Making HTTP request
try {
// defaultHttpClient
DefaultHttpClient httpClient = new DefaultHttpClient();
HttpPost httpPost = new HttpPost(url);
HttpResponse httpResponse = httpClient.execute(httpPost);
HttpEntity httpEntity = httpResponse.getEntity();
is = httpEntity.getContent();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(
is, "iso-8859-1"), 8);
StringBuilder sb = new StringBuilder();
String line = null;
while ((line = reader.readLine()) != null) {
sb.append(line + "\n");
}
is.close();
json = sb.toString();
} catch (Exception e) {
Log.e("Buffer Error", "Error converting result " + e.toString());
}
// try parse the string to a JSON object
try {
jObj = new JSONObject(json);
} catch (JSONException e) {
Log.e("JSON Parser", "Error parsing data " + e.toString());
}
// return JSON String
return jObj;
}
}
Activity اصلی برنامه اندروید :
خوب اکنون باید به سراغ Activity اصلی برنامه اندروید برویم که در آن، اطلاعات با استفاده از کلاس JSONParser از فایل اینترنتی (همان فایل html) دریافت شده و در یک JSONObject قرار داده می شود و سپس با یک سری کلاس های (class) کار با JSONObject ، اطلاعات را از JSONObject دریافت کرده و به صورت جداگانه، در سه لیست آرایه ای (ArrayList) از نوع رشته (string) ذخیره می کنیم و سپس اطلاعات این سه لیست آرایه ای (ArrayList) را در یک ListView نمایش می دهیم. این توضیح، خلاصه ای از کل فرآیند بود، اما اکنون تک تک آنها را شرح خواهیم داد.
همان طور که گفتیم، فایل activity_main.xml ، لایه گرافیکی متناظر برای Activity اصلی برنامه است :

چون قرار است اطلاعات در یک ListView نمایش داده شوند، بنابراین باید یک عنصر ListView درون فایل activity_main.xml وجود داشته باشد، بنابراین کدهای فایل activity_main.xml را به صورت زیر می نویسیم :
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<ListView
android:id="@android:id/list"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
</LinearLayout>
همچنین برای ساختار گرافیکی ListView ، دو فایل xml برای آن می سازیم (یکی لایه گرافیکی برای خود ListView و دیگری، لایه گرافیکی برای هر item از ListView) :

کدهای فایل list_layout.xml که برای ظاهر گرافیکی ListView می باشد را به صورت زیر می نویسیم (البته معمولا ممکن است که این لایه را از لایه های گرافیکی درون android.R.layout انتخاب کنند، اما من از کدهای یکی از آنها استفاده کرده ام و ترجیح دادم که خودم یک فایل بسازم، من از کد android.R.layout.simple_list_item_1 استفاده کرده ام) :
<!-- Copyright (C) 2006 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@android:id/text1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"
android:gravity="center_vertical"
android:paddingLeft="6dip"
android:minHeight="?android:attr/listPreferredItemHeight"
/>
مشاهده می کنید که کدهای آن بسیار ساده است و نیازی به بررسی آنها نیست.
کدهای فایل list_item.xml که ظاهر گرافیکی هر item (هر ردیف - row) از ListView را مشخص می کند را به صورت زیر می نویسیم :
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="10dp"
android:orientation="vertical" >
<LinearLayout android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<TextView
android:id="@+id/textView1"
android:layout_width="80dp"
android:layout_height="wrap_content"
android:padding="5dp"
android:textSize="15sp"
android:text="Text_1" />
<TextView
android:id="@+id/textView2"
android:layout_width="80dp"
android:layout_height="wrap_content"
android:padding="5dp"
android:textSize="15sp"
android:text="Text_2" />
<TextView
android:id="@+id/textView3"
android:layout_width="80dp"
android:layout_height="wrap_content"
android:padding="5dp"
android:textSize="15sp"
android:text="Text_3" />
</LinearLayout>
</LinearLayout>
همان طور که مشاهده می کنید، سه تا TextView برای هر ردیف (item) از ListView در نظر گرفته ایم، زیرا برای هر فرد، سه اطلاعات داشتیم (id - name - city) که باید در هر ردیف ListView نمایش داده شود.
اکنون که این موارد را شرح دادیم، می ماند کدهای java در فایل MainActivity.java که همان فایل مربوط به Activity اصلی برنامه است و کل فرآیند، با کدهای آن اجرا می شود :

کدهای فایل MainActivity.java را به صورت زیر می نویسیم :
import java.io.UnsupportedEncodingException;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import android.app.ListActivity;
import android.app.ProgressDialog;
import android.content.Context;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.TextView;
public class MainActivity extends ListActivity {
//URL to get JSON Array
private static String url;
//JSON Node Names
private static final String json_name = "kelidestan";
private static final String json_node_name_1 = "id";
private static final String json_node_name_2 = "name";
private static final String json_node_name_3 = "city";
JSONArray kelidestan = null;
public String app_id_string;
public String[] json_string_1_all;
public String[] json_string_2_all;
public String[] json_string_3_all;
public int json_length;
public ListView lv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
url = "http://www.kelidestan.com/fixed-url/kelidestan-json-1.html";
new JSONParse().execute();
}
public class JSONParse extends AsyncTask<String, String, JSONObject> {
public ProgressDialog pDialog;
@Override
public void onPreExecute() {
super.onPreExecute();
pDialog = new ProgressDialog(MainActivity.this);
pDialog.setMessage("Getting Data ...");
pDialog.setIndeterminate(false);
pDialog.setCancelable(true);
pDialog.show();
}
@Override
public JSONObject doInBackground(String... args) {
JSONParser jParser = new JSONParser();
// Getting JSON from URL
JSONObject json = jParser.getJSONFromUrl(url);
return json;
}
@Override
public void onPostExecute(JSONObject json) {
pDialog.dismiss();
try {
// kelidestan
kelidestan = json.getJSONArray(json_name);
// build String
json_length = kelidestan.length();
json_string_1_all = new String [kelidestan.length()];
json_string_2_all = new String [kelidestan.length()];
json_string_3_all = new String [kelidestan.length()];
for(int i = 0; i < kelidestan.length(); i++){
JSONObject c = kelidestan.getJSONObject(i);
// Storing JSON item in a Variable --> with UTF-8 for persian words
json_string_1_all[i] = new String(c.getString(json_node_name_1).getBytes("ISO-8859-1"), "UTF-8");
json_string_2_all[i] = new String(c.getString(json_node_name_2).getBytes("ISO-8859-1"), "UTF-8");
json_string_3_all[i] = new String(c.getString(json_node_name_3).getBytes("ISO-8859-1"), "UTF-8");
}
// show data in ListView
setListAdapter(new MyAdapter(MainActivity.this,
R.layout.list_layout,
R.id.textView1,
json_string_1_all));
lv = getListView();
} catch (JSONException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e1) {
e1.printStackTrace();
}
}
}
private class MyAdapter extends ArrayAdapter<String>{
public MyAdapter(Context context, int resource, int textViewResourceId,
String[] strings) {
super(context, resource, textViewResourceId, strings);
// TODO Auto-generated constructor stub
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View row = inflater.inflate(R.layout.list_item, parent, false);
String id = json_string_1_all[position];
TextView tv_1 = (TextView) row.findViewById(R.id.textView1);
tv_1.setText(id);
String name = json_string_2_all[position];
TextView tv_2 = (TextView) row.findViewById(R.id.textView2);
tv_2.setText(name);
String city = json_string_3_all[position];
TextView tv_3 = (TextView) row.findViewById(R.id.textView3);
tv_3.setText(city);
return row;
}
}
}
اکنون بخش های مختلف کد بالا را شرح می دهیم.
اگر به ابتدای کدهای Activity توجه کنید، متوجه می شوید که این Activity را بر اساس گسترش (extend) کلاس ListActivity ساخته ایم (نه بر اساس گسترش کلاس Activity)، زیرا می خواهیم در آن یک ListView را نمایش بدهیم (برای راحتتر کار کردن با ListView)(در واقع یک ListActivity است و ما برای راحتی، آن را با اصطلاح Activity بیان می کنیم):
در ابتدای کدها، نام JSONArray (آرایه json) و همچنین نام مربوط به 3 گره (node) را در متغیرهایی تعریف کرده ایم :
private static final String json_name = "kelidestan";
private static final String json_node_name_1 = "id";
private static final String json_node_name_2 = "name";
private static final String json_node_name_3 = "city";
کدهای روش onCreate ، به شرح زیر می باشد (یعنی کدهایی که به محض اجرای Activity ، اجرا می شوند) :
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
url = "http://www.kelidestan.com/fixed-url/kelidestan-json-1.html";
new JSONParse().execute();
}
در این کدها، ابتدا مقدار متغیر url را تعیین کرده ایم که در آن، آدرس URL مربوط به فایل حاوی اطلاعات در سرور اینترنتی، ذخیره می شود. سپس از روی کلاس (class) با نام JSONParse (با کلاس JSONParser آن را اشتباه نگیرید) که اتفاقا کدهای تعریف آن، در میان کدهای همین Activity می باشد، یک شیء (object) ساخته ایم و سپس آن را اجرا می کنیم.
اگر یادتان باشد، در ابتدای مبحث، تذکر دادم که می توانید کدهایی را به پروژه اندروید اضافه کنید که ابتدا چک کند که گوشی کاربر به اینترنت متصل می باشد یا خیر و تنها در صورت متصل بودن به اینترنت، کدها اجرا شوند ( آموزش شماره 2408 ). این عملیات را می توانیم برای خط زیر از کدها اجرا کنیم زیرا این خط، باعث اجرای فرآیند دریافت اطلاعات از سرور اینترنت می شود و می توانیم بر روی آن شرط بگذاریم که اگر به اینترنت وصل بودیم، اجرا شود :
خوب حالا برویم به سراغ کلاس JSONParse و ببینیم که کدهای آن چگونه است که با اجرای آن، کل عملیات دریافت اطلاعات و نمایش آن، اجرا می شود. کدهای کلاس JSONParse ، به صورت زیر نوشته شده است :
public ProgressDialog pDialog;
@Override
public void onPreExecute() {
super.onPreExecute();
pDialog = new ProgressDialog(MainActivity.this);
pDialog.setMessage("Getting Data ...");
pDialog.setIndeterminate(false);
pDialog.setCancelable(true);
pDialog.show();
}
@Override
public JSONObject doInBackground(String... args) {
JSONParser jParser = new JSONParser();
// Getting JSON from URL
JSONObject json = jParser.getJSONFromUrl(url);
return json;
}
@Override
public void onPostExecute(JSONObject json) {
pDialog.dismiss();
try {
// kelidestan
kelidestan = json.getJSONArray(json_name);
// build String
json_length = kelidestan.length();
json_string_1_all = new String [kelidestan.length()];
json_string_2_all = new String [kelidestan.length()];
json_string_3_all = new String [kelidestan.length()];
for(int i = 0; i < kelidestan.length(); i++){
JSONObject c = kelidestan.getJSONObject(i);
// Storing JSON item in a Variable --> with UTF-8 for persian words
json_string_1_all[i] = new String(c.getString(json_node_name_1).getBytes("ISO-8859-1"), "UTF-8");
json_string_2_all[i] = new String(c.getString(json_node_name_2).getBytes("ISO-8859-1"), "UTF-8");
json_string_3_all[i] = new String(c.getString(json_node_name_3).getBytes("ISO-8859-1"), "UTF-8");
}
// show data in ListView
setListAdapter(new MyAdapter(MainActivity.this,
R.layout.list_layout,
R.id.textView1,
json_string_1_all));
lv = getListView();
} catch (JSONException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e1) {
e1.printStackTrace();
}
}
}
همان طور که مشاهده می کنید، کلاس JSONParse بر اساس AsyncTask ساخته شده است، یعنی یک ProgressDialog به کاربر نمایش داده می شود و در حین نمایش آن، یک سری عملیات اجرا می گردد (در این حالت، دریافت اطلاعات از آدرس URL و تبدیل آن به یک JSONObject) و پس از پایان عملیات، دیگر ProgressDialog نمایش داده نمی شود و از JSONObject ، اطلاعات مورد نظرمان را استخراج کرده و در یک ListView نمایش می دهیم. بنابراین AsyncTask شامل سه قسمت زیر است :
1- onPreExecute
2- doInBackground
3- onPostExecute
اکنون کدهای این سه بخش را شرح می دهیم :
1- onPreExecute :
public void onPreExecute() {
super.onPreExecute();
pDialog = new ProgressDialog(MainActivity.this);
pDialog.setMessage("Getting Data ...");
pDialog.setIndeterminate(false);
pDialog.setCancelable(true);
pDialog.show();
}
با کدهای فوق، یک ProgressDialog می سازیم و به کاربر نمایش می دهیم تا در حین اجرای کدهای بخش doInBackground ، کاربر این ProgressDialog را ببیند و بداند که یک سری عملیات در حال اجرا می باشد.
2- doInBackground :
public JSONObject doInBackground(String... args) {
JSONParser jParser = new JSONParser();
// Getting JSON from URL
JSONObject json = jParser.getJSONFromUrl(url);
return json;
}
در همان حال که کاربر یک ProgressDialog را می بیند، باید با استفاده از کلاس JSONParser ، اطلاعات را از فایل موجود در آدرس URL دریافت کرده و به یک JSONObject تبدیل کنیم :
برای این منظور، یک شیء (object) با نام jParser از کلاس JSONParser می سازیم و به آن، آدرس URL فایل را می دهیم تا یک JSONObject حاوی اطلاعات را به ما برگرداند :
با برگرداندن JSONObject ، کدهای بخش onPostExecute از AsyncTask اجرا خواهد شد :
3- onPostExecute :
public void onPostExecute(JSONObject json) {
pDialog.dismiss();
try {
// kelidestan
kelidestan = json.getJSONArray(json_name);
// build String
json_length = kelidestan.length();
json_string_1_all = new String [kelidestan.length()];
json_string_2_all = new String [kelidestan.length()];
json_string_3_all = new String [kelidestan.length()];
for(int i = 0; i < kelidestan.length(); i++){
JSONObject c = kelidestan.getJSONObject(i);
// Storing JSON item in a Variable --> with UTF-8 for persian words
json_string_1_all[i] = new String(c.getString(json_node_name_1).getBytes("ISO-8859-1"), "UTF-8");
json_string_2_all[i] = new String(c.getString(json_node_name_2).getBytes("ISO-8859-1"), "UTF-8");
json_string_3_all[i] = new String(c.getString(json_node_name_3).getBytes("ISO-8859-1"), "UTF-8");
}
// show data in ListView
setListAdapter(new MyAdapter(MainActivity.this,
R.layout.list_layout,
R.id.textView1,
json_string_1_all));
lv = getListView();
} catch (JSONException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e1) {
e1.printStackTrace();
}
}
در بخش onPostExecute ، اولین اقدام این است که دیگر ProgressDialog به کاربر نمایش داده نشود، بنابراین با کد زیر، آن را ناپدید (dismiss) می کنیم :
اکنون کدهای مربوط به استخراج اطلاعات از JSONObject دریافت شده را با try و catch انجام می دهیم (باعث می شود که در صورت مواجه شدن با یک یا دو نوع خطا، به جای بسته شدن برنامه اندروید، یک سری کد دیگر اجرا شود). در قسمت try ، کدهای زیر را داریم :
kelidestan = json.getJSONArray(json_name);
// build String
json_length = kelidestan.length();
json_string_1_all = new String [kelidestan.length()];
json_string_2_all = new String [kelidestan.length()];
json_string_3_all = new String [kelidestan.length()];
for(int i = 0; i < kelidestan.length(); i++){
JSONObject c = kelidestan.getJSONObject(i);
// Storing JSON item in a Variable --> with UTF-8 for persian words
json_string_1_all[i] = new String(c.getString(json_node_name_1).getBytes("ISO-8859-1"), "UTF-8");
json_string_2_all[i] = new String(c.getString(json_node_name_2).getBytes("ISO-8859-1"), "UTF-8");
json_string_3_all[i] = new String(c.getString(json_node_name_3).getBytes("ISO-8859-1"), "UTF-8");
}
// show data in ListView
setListAdapter(new MyAdapter(MainActivity.this,
R.layout.list_layout,
R.id.textView1,
json_string_1_all));
lv = getListView();
ما در کل متن مورد نظرمان، یک JSONArray (آرایه json) با نام kelidestan داشتیم، اما امکان اینکه چند JSONArray (آرایه json) دیگر هم تعریف کنیم، وجود داشت، اما برای سادگی، همین یکی را در نظر گرفتیم. حالا با روش getJSONArray ، اطلاعات این JSONArray (آرایه json) را از JSONObject استخراج می کنیم :
با کدهای زیر، اطلاعات مربوط به id و name و city را در سه لیست آرایه ای (ArrayList) از نوع رشته (string) ذخیره می کنیم :
json_length = kelidestan.length();
json_string_1_all = new String [kelidestan.length()];
json_string_2_all = new String [kelidestan.length()];
json_string_3_all = new String [kelidestan.length()];
for(int i = 0; i < kelidestan.length(); i++){
JSONObject c = kelidestan.getJSONObject(i);
// Storing JSON item in a Variable --> with UTF-8 for persian words
json_string_1_all[i] = new String(c.getString(json_node_name_1).getBytes("ISO-8859-1"), "UTF-8");
json_string_2_all[i] = new String(c.getString(json_node_name_2).getBytes("ISO-8859-1"), "UTF-8");
json_string_3_all[i] = new String(c.getString(json_node_name_3).getBytes("ISO-8859-1"), "UTF-8");
}
با کد زیر، تعداد عناصر آرایه json با نام kelidestan را به دست می آوریم (همان تعداد 10 عدد) :
سپس سه لیست آرایه ای (ArrayList) از نوع رشته (string) با همان تعداد عنصر ساخته ایم و مقادیر را در آنها ذخیره کرده ایم.
اگر مقادیر به زبان فارسی باشند، به کار بردن عبارت UTF-8 در کدها الزامی است تا کاراکترهای فارسی، به درستی نمایش داده شوند ( آموزش شماره 292 ).
خوب اکنون که مقادیر را در سه لیست آرایه ای (ArrayList) با نام های json_string_1_all و json_string_2_all و json_string_3_all داریم، تنها باید آنها را در ListView نمایش بدهیم :
setListAdapter(new MyAdapter(MainActivity.this,
R.layout.list_layout,
R.id.textView1,
json_string_1_all));
lv = getListView();
دقت شود که در کد بالا، از کلاس MyAdapter استفاده کرده ایم که کدهای تعریف آن، در انتهای همین Activity ، به صورت زیر نوشته شده است :
public MyAdapter(Context context, int resource, int textViewResourceId,
String[] strings) {
super(context, resource, textViewResourceId, strings);
// TODO Auto-generated constructor stub
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View row = inflater.inflate(R.layout.list_item, parent, false);
String id = json_string_1_all[position];
TextView tv_1 = (TextView) row.findViewById(R.id.textView1);
tv_1.setText(id);
String name = json_string_2_all[position];
TextView tv_2 = (TextView) row.findViewById(R.id.textView2);
tv_2.setText(name);
String city = json_string_3_all[position];
TextView tv_3 = (TextView) row.findViewById(R.id.textView3);
tv_3.setText(city);
return row;
}
در کدهای کلاس MyAdapter ، سه تا TextView ای که برای هر item (ردیف - row) از Listview ، تعریف کرده بودیم را شناسایی کرده و سپس بر اساس مقدار position که همان شماره ترتیب قرارگیری item ها است، یک عنصر از هر یک از سه لیست آرایه ای (ArrayList) ، فراخوانی کرده و در TextView ها نمایش می دهیم (نمایش سه عنصر در سه TextView) :
TextView tv_1 = (TextView) row.findViewById(R.id.textView1);
tv_1.setText(id);
String name = json_string_2_all[position];
TextView tv_2 = (TextView) row.findViewById(R.id.textView2);
tv_2.setText(name);
String city = json_string_3_all[position];
TextView tv_3 = (TextView) row.findViewById(R.id.textView3);
tv_3.setText(city);
بنابراین مراحل ساخت این پروژه اندروید را شرح دادیم. خروجی نهایی برنامه اندروید، به صورت زیر می باشد :

تست برنامه اندروید برای زبان فارسی :
چنانچه قصد دارید که برنامه اندروید ساخته شده را برای زبان فارسی هم تست کنید، آدرس اینترنتی صفحه (آدرس URL) را برابر آدرس زیر قرار بدهید :
نتیجه به صورت زیر می باشد :

فایل های پروژه اندروید را می توانید از لینک های زیر دریافت کنید :
اگر برخی از کلاس های (class) به کار رفته در این آموزش، در api های جدید حذف شده بودند، می توانید کلاس های (Class) حذف شده را با روش هایی به پروژه اندروید اضافه کنید تا در api های جدید نیز قابل استفاده باشند.
به عنوان مثال، برای Android Studio ، کلید زیر را بخوانید :


سلام این برنامه رو نوشتم has stopped میده وقتی اجرا می کنم تو گوشی ، همه دسترسی ها رو طبق برنامه بهش دادم و وقتی debug هم می کنم این پیام میاد :


سلام
من فایل JSONPars رو هم ایجاد کردم و هم کپی کردم از فایل های پروژه ی شما ، ولی یکسری توابع و لایبراری هاشو نمیتونه یا نداره تو اینترنت که IMPORT کنه
هرچیم گشتم نفهمیدم مشکلش چیه ، لطفا راهنماییم کنید


سلام.
برخی کلاس ها (classes) و روش ها (methods) در api های جدید حذف شده اند که اگر بخواهید از آنها مطابق کدهای این کلید استفاده نمایید، باید فایل کتابخانه های شامل آنها را پیدا کرده و به پروژه اندروید خود اضافه نمایید.
چگونگی این عملیات برای Android Studio ، در کلید زیر شرح داده شده :


سلام من یک فایل json براش ساختم هر کاری می کنم stop میشه اما هروقت فایل json شما رو میزارم برنامه کار می ده از دیباگ هم استفاده کردم میشه راهنمایی کنید


سلام.
دلایل مختلفی میتونه داشته باشه :
1- در مقادیر به کار رفته، علامت " درج شده باشد که باعث به هم خوردن ساختار json شود ()
2- در صفحه ای که json را نوشته اید، کدنویسی چارچوب HTML وجود داشته باشد ()
3- نام گره ها را تغییر داده اید و بنابراین پردازش json با خطا روبرو می شود
4- ساختار json به درستی تعریف نشده باشد (استانداردهای تعریف ساختار json باید رعایت شوند)
و ...


میشه یه نمونه کد بفرستید


منم با خوندن دیتا از سایت خوب شما مشکل ندارم ولی وقتی می خواد اطلاعات رو از دیتای خودم بخونه خطا میده و مقدار




سلام.
از صفحه مورد نظر، کدهایی غیر از ساختار JSON را دریافت می کنید و بنابراین احتمالا ساختار HTML در صفحه مورد نظر ذکر شده است ().
بنابراین با یک نرم افزار ویرایشگر متن، صفحه مورد نظر را باز کنید و کلیه کدها غیر از ساختار JSON را از صفحه حذف کنید.


سلام .
اگه بخواهیم یه همچین لیستی داشته باشیم و بعد با کلیک بر روی هر ردیف به صفحه ای دیگر مثلا توضیحات آن ردیف برویم باید چکار کنیم ؟ ممنون


سلام.
کلید زیر را در مورد ساخت یک ListView سفارشی (Custom ListView) شامل چندین عنصر در هر ردیف (row) از ListView و با قابلیت رفتن به Activity جدید بخوانید :
بر اساس کلید بالا، شماره متناظر با ردیف (row- item) را به Activity جدید می فرستید و بر اساس آن شماره، توضیحات مورد نظرتان در مورد ردیف انتخاب شده، در Activity جدید نمایش داده می شود.


سلام خسته نباشید
اگه کلا بخوای فایل json رو تغییر بدی و image هم توی فایل باشه باید چیکار کنیم و اینکه کجا باید اپلود کنبم
اینی که الان توی سرور سایت شماس حالا من میخوام واسه برنامه خودم و جدا باشه حتما باید سایتی داشته باشم که اپلود کنم؟؟
ممنون از سایت خوبتون


درود
تصویر را به Base64 یا الگوریتم دیگر که از نوع رشته ای است تبدیل کنید و در پرونده json قرار دهید و در خوانش decode و تصویر استخراج گردد.


ولی نمی دونم چطور باید کاری کنم که برنامه به طور خودکار مثلا هر 1 ساعت یکبار (حالا مثلا اگه نت داشت) دوباره مطلب رو بگیره تا مطالب گوشی همیشه به روز باشه؟


درود
دستورات دریافت فایل json مورد نظر میتواند در Thread یا Timer باشد که زمان را شما مشخص میکنید. Thread بار پردازش کمتری دارد و به صورت موازی با دیگر دستورات اجرا میشود.
سپاس


با سلام و تشکر از مطلب مفیدتون...
من یک فایل html روی سرور قرار دادم به همون شکلی که شما آرایه رو نوشتید منم نوشتمش فقط من دو آرایه نوشتم مثلا kelidestan1 و kelidestan2 (روی سرور خودم) ولی فقط وقتی این قسمت
رو kelidestan1 قرار میدم کار میکنه!!!!! انگار آرایه دومی رو نمیخونه!!


با سلام و تشکر
یک سوال...اگه بجای لیست اکتیویتی از فرگمنت مشتق بگیریم در نمایش لیست ویو باید چه تغییری بدیم؟
setListAdapter(new MyAdapter(MainActivity.this,
R.layout.list_layout,
R.id.textView1,
json_string_1_all));
lv = getListView();


سلام.
تفاوت در نحوه شناسایی تگ ListView می باشد. یعنی کدهایی که در فایل java برای شناسایی تگ ListView از فایل xml متناظر با Fragment می نویسیم، کمی تفاوت خواهد داشت.
قبلا دو مبحث (کلید) برای تعریف دو تگ TextView و Button در Fragment نوشته ایم. کافی است که آنها را بخوانید (برای تگ های مختلف، تغییرات مشابه هستند و چگونگی تعریف و شناسایی تگ ListView را متوجه خواهید شد) :
در کلید های بالا، شناسایی عنصر در روش onCreateView صورت می گیرد.
یعنی بخشی از کدها مشابه کد زیر خواهد بود :
مشاهده می کنید که قبلا در Activity ساده، تنها عبارت findViewById را داشتیم، اما اکنون از view.findViewById استفاده می کنیم (کدها نیز در روش onCreateView نوشته شده اند).


سلام خسته نباشید و تشکر از آموزشهای بسار خوبتون
من یه سوال در مورد json داشتم
من یه پنل دارم حالت cms اختصاصی میخوام مثل وردپرس خروجی json ازش بگیرم چطور میتونم این کار رو کنم ممنونم میشم راهنمایی کنید نمیخوام jdon رو دستی بارم تو یه فایل که خروجی بده فقط میخام وقتی مثلا یه پستی تو سایت میزارم خروجی json هم تولید کنه مثل سایت دیوار


سلام.
ابتدا جستجو کنید که آیا پلاگین یا کدی برای cms مورد نظر در اینترنت وجود دارد یا خیر، که بتواند امکان مورد نظر شما را فراهم کند، اگر نبود، راهی جز این نیست که یک صفحه طراحی کنید که مثلا با زبان PHP به پایگاه داده (database) آن cms متصل شود و اطلاعات مربوط به ارسال ها (post ها) را خوانده و در خروجی به شکل json چاپ کند (با استفاده از تابع echo در PHP) (فراموش نکنید که چارچوب html نباید در خروجی صفحه به کار رفته باشد).


سلام. من امتحان کردم نشد، استفاده از Default HttpClint منسوخ شده، لطفا روش های جدید رو آموزش بدید.


سلام.
می توانید کلاس های (Class) حذف شده را با روش هایی به پروژه اندروید اضافه کنید تا در api های جدید نیز قابل استفاده باشند.
به عنوان مثال، برای Android Studio ، کلید زیر را بخوانید :


سلام من با استفاده از همین اموزش برنامه ای ساختم برنامه وقتی به اینترنت وصل باشه کار می ده ولی وقتی به اینترنت متصل نباشه فورس کلوز می شه لطفا راهنمایی کنید


سلام.
معمولا مهمترین راه حل این است که ابتدا چک کنید که اگر کاربر به اینترنت متصل نیست، کدها اجرا نشوند و به جای آن، یک پیام به کاربر نمایش داده شود که باید به اینترنت متصل شود. برای چک کردن اتصال به اینترنت، مباحث دسته کلید زیر را ببینید :
به عنوان مثال :
اما این حالت هم وجود دارد که اینترنت در حین دریافت اطلاعات، قطع شود، بنابراین باید باز هم با استفاده از try و catch ، کدها را به گونه ای بنویسیم که با Force Close روبرو نشویم (حتی با وجود چک کردن اتصال به اینترنت). در این زمینه، موضوع زیر را بخوانید :


سلام و خسته نباشید
یک تکه کدی را از اینترنت دریافت کردم و میخوام به وسیله کد نویسی اندروید اون رو به بخشهای منظم تبدیل کنم و هر کدوم را در یک استرینگ ذخیره کنم به این صورت که
با زدن یک دکمه برنامه یک ساختار کد html را دانلود کرده و در چند استرینگ ذخیره میکند.
مثلا میتونم از قسمت
" />
راهنماییم کنید تا بتونم با کد نویسی در سه استرینگ ذخیره کنم؟؟


ببخشید چرا وقتی برنامه رو اجرا میکنی و اینترنت روشنه خوب کار میکنه ولی وقتی اینترنت خاموشه برنامه متوقف میشه لطفا یک راه حل بگید ممنون


خواهشششش میکنم یکی کمکم کنه
من از همین روش توضیح داده شده در کلیدستان برای دریافت فایل html جیسون استفاده کردم، وقتی url مربوط به فایل روی سرور کلیدستان هست جواب میده و لیست ویو 10 تا مورد رو نشون میده ولی وقتی همون ساختار جیسون با پسوند html رو روی سرور خودم که در gigfa هست میذارم جواااااب نمیییده و پیغام has stopped رو میده
هر کاریش میکنم جواب نمییییییییده و اطلاعات رو از فایل خودم نمیگیره
چرااااااا؟؟؟؟


سلام وخسته نباشید ببخشید من میخواستم 5 تا از فیلد های دیتابیس خونده بشه از درون دیتابیس و درون لیست ویو نشان داده شود و 3 تا عکس از دیتابیس خوانده شود میشه کمکم کنید مرسی


فایل رو انلود و اجرا که میکنم این خطا رو میده error: incompatible types: HttpResponse cannot be converted to CloseableHttpResponse


درود
parser کمی کند است ولی در این نشانی parser تندی هست :
اگر مدیر میتوانید codeهای بازنویسی با آن را آموزش دهید.
سپاس


سلام و خسته نباشید خدمت شما
اگر میشود گرفتن عکس از دیتابیس و لیست کردن توی لیست ویو رو آموزش بدین
عکس از پایگاه داده بگیرین . . . نه از دروابل
باتشکر


سلام ارتباط با json من اینو رو ایکلیپس اجرا میکنم جواب میده .ولی رو اندرید استدیو نمیاره .خیلی نیاز دارم رو اندرید استدیو ارتباط با سرور از طریق json لازمم هر پروژه ای که از اینترنت میگیرم حتی خریدمم نمیتونه اطلاعات خودش بخونه مثل اینه ارتباط با json نداره .شاید سه ماه درگیرشم تنها کد شما رو ایکلیپس بالا میاره یا همین کد چطور تبدیل کنم به اندرید استدیو یا پروژه ای معرفی کنید با تشکر از کلیدستان