এখনকার বেশির ভাগ ওয়েব সাইটই API কল করলে JSON ডেটা পাঠায়। এ জন্য কোন ওয়েব সাইট বা ফেসবুক গুগল ম্যাপ ইত্যাদির অ্যাপ তৈরি করতে চাইলে JSON ডেটা নিয়ে কাজ করার অভিজ্ঞতা দরকার হয়। আজ আমরা দেখব কিভাবে JSON ডেটা পার্স করতে হয়।
এ টিউটোরিয়ালে আমরা সিম্পল একটা JSON ফাইল ব্যবহার করব। যেখানে সকালের খাবারের আইটেম গুলোর কিছু তথ্য দেওয়া আছে। ফাইলটি দেখা যাবে এখানে ক্লিক করে।
এ টিউটরিলটি ওয়েব সাইট ফীড থেকে XML ডেটা পার্স করা টিউটোরিয়াল এর মতই। শুধু এখানে XML parsing এর পরিবর্তে JSON parse করব। আর সব কিছুই একই রকম।
কোড গুলো পাওয়া যাবে গিটহাবে। বা ড্রপবক্সেও কোড গুলো পাওয়া যাবে। ড্রপবক্স একাউন্ট না থাকলে এখানে ক্লিক করে খুলে নিতে পারেন।
প্রথমেই activity_main.xml নিয়ে বলি, এটিতে একটি বাটন থাকবে, যেখানে ক্লিক করলে আমাদের ডেটা গুলো লোড হবে। ইন্টারনেট থেকে ডেটা গুলো লোড হতে কিছু সময় লাগবে। আর এ জন্য আমরা যখন ডেটা লোড করব, তখন একট প্রগ্রেসবার বা লোডিং চিহ্ন দেখাবো। এবং ডেটা গুলো লোড হয়ে একটা টেক্সটভিউতে দেখাবে। সম্পূর্ণ কোডঃ
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context="me.jakir.androidxmlparsing.MainActivity"> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Load and Parse JSON" android:id="@+id/loadJSON" android:layout_alignParentTop="true" android:layout_centerHorizontal="true" /> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="" android:id="@+id/output" android:layout_below="@+id/loadJSON" android:layout_centerHorizontal="true" android:layout_marginTop="23dp" /> <ProgressBar android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/progressBar" android:layout_below="@+id/output" android:layout_centerHorizontal="true" android:layout_centerVertical="true" /> </RelativeLayout>
MainActivity.java যে কোড গুলো লাগবে, সে গুলো নিয়ে বলি। অ্যান্ড্রয়েডে কোন ব্যাকগ্রাউন্ড টাস্ক UI thread থেকে করা যায় না। সাধারণ ভাবে বলতে গেলে Activity থেকে করা যায় না। কিন্তু আমরা ইন্টারনেট থেকে JSON ডেটা কল করব ব্যাকগ্রাউন্ডে। ব্যাক গ্রাউন্ডে করার জন্য আলাদা একটা ক্লাস রয়েছে, AsyncTask নামে। আমরা একটা নতুন ক্লাস তৈরি করে AsyncTask কে এক্সটেন্ড করে তারপর আমাদের ব্যাক গ্রাউন্ড কাজ গুলো করতে পারি। তো আমাদের মেইন এক্টিভিটি থেকে আগে দেখব ইন্টারনেট কানেক্ট আছে কিনা, যদি থাকে তাহলে আমরা ব্যাকগ্রাউন্ডে JSON লোড এবং পার্স করব। যদি না থাকে, তাহলে একটা টোস্ট দেখাবো, যেখানে লেখা থাকবে ইন্টারনেট নেই।
ইন্টারনেট চেক করা সহজ। এভাবে চেক করতে পারিঃ
private boolean isOnline() { ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo netInfo = cm.getActiveNetworkInfo(); if (netInfo != null && netInfo.isConnectedOrConnecting()){ return true; }else return false; }
ইন্টারনেট চেক করার জন্য আমাদের পারমিশনের প্রয়োজন হবে। নিচের পারমিশন দুইটি AndroidManifest এ যুক্ত করে দিবঃ
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> <uses-permission android:name="android.permission.INTERNET"/>
যদি ইন্টারনেট থাকে, তাহলে আমরা আমদের xml url টা পাস করব BackgroundTask এ। সম্পূর্ন MainActivity.java
import android.content.Context; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.view.View; import android.widget.Button; import android.widget.ProgressBar; public class MainActivity extends AppCompatActivity { Button loadJSON; ProgressBar progressBar; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // set main activity setContentView(R.layout.activity_main); // reference to view loadJSON = (Button) findViewById(R.id.loadJSON); progressBar = (ProgressBar) findViewById(R.id.progressBar); progressBar.setVisibility(View.INVISIBLE); loadJSON.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (isOnline()) { BackgroundTask task = new BackgroundTask(MainActivity.this); task.execute("http://jakir.me/files/breakfast_menu.json"); } } }); } private boolean isOnline() { ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo netInfo = cm.getActiveNetworkInfo(); if (netInfo != null && netInfo.isConnectedOrConnecting()) { return true; } else return false; } }
BackgroundTask.java
import android.app.Activity; import android.os.AsyncTask; import android.view.View; import android.widget.ProgressBar; import android.widget.TextView; import java.io.BufferedReader; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.URL; import java.util.List; public class BackgroundTask extends AsyncTask<String, String, String> { Activity mainActivity; ProgressBar progressBar; TextView output; List<Food> foodList; public BackgroundTask(Activity activity) { mainActivity = activity; } @Override protected void onPreExecute() { // show progress bar progressBar = (ProgressBar) mainActivity.findViewById(R.id.progressBar); progressBar.setVisibility(View.VISIBLE); } @Override protected String doInBackground(String... params) { String content = getData(params[0]); return content; } @Override protected void onPostExecute(String result) { // Hide Progress bar progressBar.setVisibility(View.INVISIBLE); output = (TextView) mainActivity.findViewById(R.id.output); foodList = JsonParser.parse(result); if (foodList != null) { for (Food foodItem : foodList) { output.append("working!"); output.append("Item name: " + foodItem.getName() + "\n"); output.append("Item price: " + foodItem.getPrice() + "\n"); output.append("Item Description: " + foodItem.getDescription() + "\n \n \n"); } } } // Method for get JSON data using HTTP Request private String getData(String uri) { BufferedReader reader; try { URL url = new URL(uri); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); StringBuilder stringBuilder = new StringBuilder(); reader = new BufferedReader(new InputStreamReader(connection.getInputStream())); String line; while ((line = reader.readLine()) != null) { stringBuilder.append(line + "\n"); } return stringBuilder.toString(); } catch (Exception e) { e.printStackTrace(); return null; } } }
BackgroundTask.java তে আমরা অনেক গুলো কাজ করেছি। BackgroundTask.java কে আমরা এক্সটেন্ড করেছি AsyncTask ক্লাসটি। এ ক্লাসে অনেক গুলো মেথড রয়েছে। onPreExecute, onPostExecute, doInBackground ইত্যাদি। মেথড গুলোর নাম থেকেই বুঝা যাচ্ছে কোনটার কাজ কি।
আমরা onPreExecute এ প্রগ্রেস বারটি দেখাবো। ব্যবহার কারী যেন বুঝতে পারে ব্যাকগ্রাউন্ডে কিছু কাজ হচ্ছে।
doInBackground মূলত AsyncTask যে জন্য, তা করবে এখানে। এখানে আমরা ইন্টারনেট থেকে ডেটা কল করেছি। একটা JSON ফাইল। আমরা একটা মেথড লিখেছি getData নামে, সেটা doInBackground থেকে কল করা হয়েছে। এটিতে মূলত XML ফাইলটা ইন্টারনেট থেকে নিয়ে স্ট্রিং আকারে রিটার্ন করেছে।
onPostExecute মানেহচ্ছে ব্যাক গ্রাউন্ড কাজ শেষ, তাহলে আমরা প্রগ্রেসবারটি হাইড করতে পারি। এবং আমাদের JSON ডেটা গুলো দিয়ে যা করতে চাই, তা করতে পারি।
এখানেই শেষ নয়!
আমরা এখন মূলত কিছু JSON ডেটা পেয়েছি। এগুলোকে পার্স করতে হবে। তার জন্য এখান থেকে আরকেটা ক্লাসকে কল করেছি। JsonParser.java নামেঃ
import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import java.util.ArrayList; import java.util.List; public class JsonParser { public static List<Food> parse(String content) { try { JSONArray array = new JSONArray(content); List<Food> foodList = new ArrayList<>(); for (int i = 0; i < array.length(); i++) { JSONObject object = array.getJSONObject(i); Food food = new Food(); food.setName(object.getString("name")); food.setPrice(object.getString("price")); food.setDescription(object.getString("description")); foodList.add(food); } return foodList; } catch (JSONException e) { e.printStackTrace(); return null; } } }
এখানে আমরা JSON কন্টেন্ট পার্স করেছি। JSON নিয়ে কাজ করে থাকলে এটা বুঝতে সুবিধে হবে। এখানে আমরা কিছু খাবারের তথ্য পেয়েছি। Food.java নামে একটা ক্লাস তৈরি করেছি, যেন খাবার আইটেম গুলোর জন্য একটা অ্যারে লিস্ট তৈরি করতে পারি। যা আমরা উপরে JsonParsing ক্লাসে ব্যবহার করেছি।
Food.java
public class Food { // food info variables private String name; private String price; private String description; // getters and setters public String getPrice() { return price; } public void setPrice(String price) { this.price = price; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } }
সব কিছু ঠিক মত করতে পারলে নিচের মত আউটপুট পাবো।
আপনার কাজ হচ্ছে আরো কমপ্লেক্স কোন JSON ফাইল নিয়ে কাজ করা। এটা ঠিক মত করতে পারলে যে কোন JSON ডেটা নিয়েই কাজ করা যাবে।
কোড গুলো পাওয়া যাবে গিটহাবে। বা ড্রপবক্সেও কোড গুলো পাওয়া যাবে। ড্রপবক্স একাউন্ট না থাকলে এখানে ক্লিক করে খুলে নিতে পারেন।
Why not use volley or okhttp libraries?
Not any specific reason. HTTP call is on separate file. If you want to use Volley or OkHttp, you can just change few lines of code and use your favorite library 🙂
ভাই এখন যে সমস্যায় পড়ছি সেটা হল আমি কোন ওয়েবসাইট থেকে ওই সাইটের JSON ডাটা কিভাবে পাব?
জাকির ভাই,
https://openexchangerates.org/api/latest.json?app_id=030643befa2c4fd3bdc273737ac23789
অথবা,
https://finance.yahoo.com/webservice/v1/symbols/allcurrencies/quote?format=json
এখান থেকে Exchange rate কিভাবে Parse করব?
নিয়মটা মেইলে জানালে খুশি হব।