آموزش پارس Json + قرار دادن در RecyclerView
سلام دوستان در این سری از آموزش برنامه نویسی اندروید به آموزش پارس Json + قرار دادن در RecyclerView می پردازیم منظور از پارس (parse) تجزیه است. در ادامه خواهید دید که به چه شکل زیبای نمایش داده خواهد شد (سعی کردیم شبیه به بخش فروشگاه دیجی کالا باشد) در این آموزش از کتاب خانه قدرتمند Retrofit برای بخش پارس json استفاده می کنیم در ادامه می توانید پیش نمایشی از آن را مشاهده کنید با ما همراه باشید..
در این آموزش از کتاب خانه های زیر استفاده کرده ایم.
- Android Retrofit
- GSON Converter
- RecyclerView
- CardView
- Universal Image Loader
در ابتدای کار باید وارد فایل Build.gradle از نوع module شده و در بخش dependencies خط های زیر را اضافه کنید.
1 2 3 4 5 | compile 'com.squareup.retrofit2:retrofit:2.2.0' compile 'com.squareup.retrofit2:converter-gson:2.2.0' compile 'com.android.support:recyclerview-v7:25.1.1' compile 'com.android.support:cardview-v7:25.1.1' compile 'com.nostra13.universalimageloader:universal-image-loader:1.9.5' |
سپس پروژه را sync کنید کمی بیشتر از حد معمول طول می کشد چون تعداد کتاب خانه ها زیاد است . علت خطاهای احتمالی گریدل را قبلا بررسی کرده ایم در سایت واژه “gradle” را جستجو کنید.
بعد از sync شدن پروژه وارد فایل AndroidManifest.xml شده و دسترسی زیر را اضافه کنید.
1 | <uses-permission android:name="android.permission.INTERNET"></uses-permission> |
حالا وارد layout خود شده در اینجا نام آن برابر با activity_main.xml است و کد های زیر را در آن قرار دهید.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | <?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:id="@+id/activity_main" 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=".MainActivity"> <android.support.v7.widget.RecyclerView android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/recycle" > </android.support.v7.widget.RecyclerView> </RelativeLayout> |
همانطور که مشاهده می کنید یک RecyclerView در layout اصلی قرار داده ایم.
حالا باید یک فایل به نام list.xml ایجاد کرده و کدهای زیر را در آن قرار دهید.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 | <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="wrap_content" android:layout_height="wrap_content" xmlns:card_view="http://schemas.android.com/apk/res-auto" android:orientation="vertical" android:background="#ffffff"> <android.support.v7.widget.CardView android:id="@+id/card_view" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:layout_margin="@dimen/card_margin" android:elevation="3dp" card_view:cardCornerRadius="@dimen/card_album_radius"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:padding="16dp" android:orientation="vertical" android:gravity="center"> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:padding="16dp" android:orientation="vertical" android:gravity="center"> <ImageView android:id="@+id/productimage" android:layout_width="150dp" android:layout_height="150dp" android:src="@mipmap/ic_launcher" android:gravity="center" /> <LinearLayout android:layout_weight="0.1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical" android:layout_marginTop="10dp" > <TextView android:id="@+id/price" android:maxLines="2" android:textSize="20dp" android:layout_width="wrap_content" android:layout_height="match_parent" android:text="INR 0000" android:textColor="#000000" /> <TextView android:id="@+id/name" android:textSize="15dp" android:layout_width="wrap_content" android:layout_height="match_parent" android:text="Wrist Watches" android:layout_marginTop="7dp" android:textColor="#000000" /> <TextView android:id="@+id/color" android:textSize="13dp" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="RED" android:layout_marginTop="7dp" android:textColor="#000000" /> </LinearLayout> </LinearLayout> </LinearLayout> </android.support.v7.widget.CardView> </LinearLayout> |
شاید بپرسید این کدام بخش از کار است . کد بالا در RecyclerView ما render یا بارگذاری می شود که شامل CardView و عکس ها و Text ها می شود .
حلا باید یک InterFace به نام ApiService.java با annotation (تفسیر) “@GET” برای دریافت Response ایجاد کرده همانند زیر
1 2 3 4 5 6 7 8 9 10 11 | package ir.programchi; import java.util.List; import retrofit2.Call; import retrofit2.http.GET; /** * Created by JFP on 01-May-17. */ public interface APiService { @GET("/api/product.php") Call<List<Product>> getbookdetails(); } |
در بالا /api/product.php بخشی از مسیر json ما است. نباید در آن http قرار دهید.
مسیر فایل json در هاست ما
1 | programchi.ir/api/product.php |
حالا باید getter و setter خودمان را ایجاد کنیم پس یک فایل به نام Product.java ایجاد کرده و کدهای زیر را در آن قرار دهید.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | package ir.programchi; /** * Created by JFP on 01-May-17. */ public class Product { int productid; String productname; String price; String instock; String offer; String color; String imageurl; public int getProductid() { return productid; } public void setProductid(int productid) { this.productid = productid; } public String getProductname() { return productname; } public void setProductname(String productname) { this.productname = productname; } public String getPrice() { return price; } public void setPrice(String price) { this.price = price; } public String getInstock() { return instock; } public void setInstock(String instock) { this.instock = instock; } public String getOffer() { return offer; } public void setOffer(String offer) { this.offer = offer; } public String getColor() { return color; } public void setColor(String color) { this.color = color; } public String getImageurl() { return imageurl; } public void setImageurl(String imageurl) { this.imageurl = imageurl; } } |
زمان آن رسیده که آداپتور مربوط به RecyclerView ایجاد کنیم پس یک فایل به نام Recycleradapter.java ایجاد کرده و کدهای زیر را در آن قرار دهید.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | package ir.programchi; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TextView; import com.nostra13.universalimageloader.core.ImageLoader; import java.util.List; /** * Created by JFP on 01-May-17. */ public class Recycleradapter extends RecyclerView.Adapter<Recycleradapter.MyHolder>{ List<Product> list; ImageLoader imageLoader; public Recycleradapter(List<Product> list, ImageLoader imageLoader) { this.list = list; this.imageLoader=imageLoader; } @Override public MyHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.list,parent,false); MyHolder myHolder = new MyHolder(view); return myHolder; } @Override public void onBindViewHolder(MyHolder holder, int position) { Product product = list.get(position); holder.name.setText(product.getProductname()); holder.color.setText(product.getColor()); String image1 = product.getImageurl(); imageLoader.displayImage(image1, holder.image); holder.price.setText("INR "+product.getPrice()); } @Override public int getItemCount() { return list.size(); } class MyHolder extends RecyclerView.ViewHolder{ TextView name, color,price; ImageView image; public MyHolder(View itemView) { super(itemView); image= (ImageView) itemView.findViewById(R.id.productimage); name = (TextView) itemView.findViewById(R.id.name); color = (TextView) itemView.findViewById(R.id.color); price= (TextView) itemView.findViewById(R.id.price); } } } |
قبلا هم چندین بار این کلاس را توضیح داده بودیم ولی یک اشاره کوچک به آن خواهیم کرد ابتدا layout که درست کردیم اگر یادتان باشد اسم آن برابر با list بود باید آن را Inflate کنیم بعد از آن زمان آن است که مقدار های را در Textview ها قرار دهیم فقط TexTview نیست ImageView و بیقه اجزا نیز هستند باید تعداد card های که می خواهند درآنها TextView و Image View و.. قرار بگیرد به دست بیاید.
و در آخر باید کد زیر را در MainActivity.java قرار دهید.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 | package ir.programchi; import android.content.res.Resources; import android.graphics.Rect; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.support.v7.widget.DefaultItemAnimator; import android.support.v7.widget.GridLayoutManager; import android.support.v7.widget.RecyclerView; import android.util.TypedValue; import android.view.View; import com.nostra13.universalimageloader.core.ImageLoader; import com.nostra13.universalimageloader.core.ImageLoaderConfiguration; import java.util.ArrayList; import java.util.List; import retrofit2.Call; import retrofit2.Callback; import retrofit2.Response; import retrofit2.Retrofit; import retrofit2.converter.gson.GsonConverterFactory; public class MainActivity extends AppCompatActivity { RecyclerView recyclerView; List<Product> listing; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); recyclerView = (RecyclerView) findViewById(R.id.recycle); ImageLoaderConfiguration config=new ImageLoaderConfiguration.Builder(this).build(); ImageLoader.getInstance().init(config); listing = new ArrayList<>(); Retrofit retrofit = new Retrofit.Builder() .baseUrl("http://programchi.ir") .addConverterFactory(GsonConverterFactory.create()) .build(); APiService service = retrofit.create(APiService.class); Call<List<Product>> call= service.getbookdetails(); call.enqueue(new Callback<List<Product>>() { @Override public void onResponse(Call<List<Product>> call, Response<List<Product>> response) { List<Product> list = response.body(); Product product = null; for (int i =0 ;i<list.size();i++){ product = new Product(); String name = list.get(i).getProductname(); String color = list.get(i).getColor(); String image = list.get(i).getImageurl(); String price = list.get(i).getPrice(); product.setPrice(price); product.setColor(color); product.setProductname(name); product.setImageurl(image); listing.add(product); } Recycleradapter recyclerAdapter = new Recycleradapter(listing,ImageLoader.getInstance()); RecyclerView.LayoutManager recyce = new GridLayoutManager(MainActivity.this,2); recyclerView.addItemDecoration(new GridSpacingdecoration(2, dpToPx(10), true)); recyclerView.setLayoutManager(recyce); recyclerView.setItemAnimator( new DefaultItemAnimator()); recyclerView.setAdapter(recyclerAdapter); } @Override public void onFailure(Call<List<Product>> call, Throwable t) { } }); } public class GridSpacingdecoration extends RecyclerView.ItemDecoration { private int span; private int space; private boolean include; public GridSpacingdecoration(int span, int space, boolean include) { this.span = span; this.space = space; this.include = include; } @Override public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { int position = parent.getChildAdapterPosition(view); int column = position % span; if (include) { outRect.left = space - column * space / span; outRect.right = (column + 1) * space / span; if (position < span) { outRect.top = space; } outRect.bottom = space; } else { outRect.left = column * space / span; outRect.right = space - (column + 1) * space / span; if (position >= span) { outRect.top = space; } } } } /** * Converting dp to pixel */ private int dpToPx(int dp) { Resources r = getResources(); return Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, r.getDisplayMetrics())); } } |
برای اینکه به شکل دوتایی بقل هم نمایش پیدا کنند از LayoutManager استفاده شده است همانطور که در ابتدای کد دید از Retrofit برای دریافت json استفاده شده است و در قبل هم اشاره کرده که ادرس json باید به صورت خاص به retrofit داده یا feed شود برای اینکه دوتای به صورت دقیق در کنار هم قرار گیرند ما اندازه صفحه به pixel به دست آوردیم سپس از فاصله هر ستون کم کردیم و در آخر آن را قرار داده ایم.
این آموزش هم به پایان رسید.
موفق و موید باشید.
سلام
موقع نوشتن اینترفیس ApiService به مشکل بر میخورم.
میشه درباره Book که توش استفاده کردید یه توضیحی بدید؟
یا به ایمیلم ارسال کنید؟
سلام فکر می کنم شما کلاس جاوا برای Interface ایجاد می کنید باید یک InterFace ایجاد کنید نه کلاس جاوا و جزئیات بیشتری قرار دهید تا مشکلاتان را بتوانیم حل کنیم.
موفق باشید.
خیر اینترفیس ساختم و در پوشه کلاس های جاوا قرار داره اما با دستور گفته شده مشکل داره و اجراش نمیکنه.
دوست عزیز دوباره برنامه رو تست کردم مشکلی وجود ندارد بخش AndroidMonitor رو بررسی کنید و خط خطا را به دست بیارید یا از طریق log گرفتن به خطا رسیده برای ما قرار دهید.
مشکل از Book هست.
کلا تا قبل از نوشتن Book همه رو شناسایی میکنه اما Book رو شناسایی نمیکنه و بخاطر خطایی که میده نمیشه پروژه رو Run کنم.
انگار اصلا Book تعریف نشده.من هم تعریف نکردم براش.
چجوری باید مشکل رو حل کرد؟
میشه فایل ApiService خودتون رو بفرستید؟
چون من دقیقا همین چیزی که برای interface (تکه کد پنجم همین آموزش) نوشته شده براش میزارم اما مشکل همونه.
ببخشید درست گفته بودید اصلا book تعریف نشده است کمی دقت می کردید باید در آن product را جایگزین می کردید. پست ویرایش شد .
سلام مشکل قبلی حل شد.
فقط مشکل جدید این هست که چرا وقتی من JSON خودم رو بهش میدم عمل نمیکنه؟
و اینکه آیا تو همون اینترفیس وقتی book عوض شد بعدش هم قسمت getBookdetails هم باید عوض بشه؟
و اینکه چی باید چی بجاش گذاشت و چی هست اصلا؟
سلام اولین که آدرس Json را باید به صورت خاص همانند آموزش قرار دهید نباید به طور مستقیم باشد و دوم محتوای json بسیار حساس است و در صورت گذاشتن یک نقطه اشتباه ممکن است خطا ایجاد شود توصیه من استفاده از json parser های آنلاین است و در چواب به سوال دومتان خیر فقط باید book به product تغییر می کرد چون در برنامه کلاس model به نام product ایجاد شده بود کار این کلاس هم این است که بعد از دریافت json و هنگام پارس آن ما به یک بخشی نیاز داریم تا هر مقدار متن یا عکس هر آیتم را در recyclerview قرار دهد پس باید getter و setter تعریف شود تا داده های دریافت شده در هر آیتم قرار گیرند.
سلام
آدرس json من به این صورت هست که توسط کد های پی اچ پی داده ها از دیتابیس گرفته و سپس به جیسون تبدیل میکند و در صفحه نمایش میدهد.
حالا من برای تمام آیتم ها getter , setter ثبت میکنم اما باز هم برای من هیچ چیز نمایش نمیدهد.
و جالب اینجاست که وقتی آدرس جیسون شما را میدهم مشکلی ندارد.
و اینکه اگر بعضی آیتم ها را (مانند instock) که در حال حاضر نیاز نداریم getter , setter تنظیم نکنیم در پارس کردن کلی جیسون مشکلی بوجود می آید؟
و اگر یک آیدی ایمیل یا آی دی تلگرام قرار دهید یا به ایمیل بنده ارسال کنید میشود بهتر سوال ها را پرسید.
سلام
مشکلی ندارد اگر json درست باشد نمایش داده می شود ولی بخش پارس json خیلی مهم است اگر چیزی را json حذف کردید باید تغییرات را نیز در خود کد اعمال کنید به طور مثال اگر یک object از json حذف شود باید در کد آن object نیز حذف شود در صورتی که در صورتی که در getter و setter تغییر ایجاد کنید باید در بخش Recycleradapter.java نیز تغییراتی ایجاد کنید (باید holder ها نیز حذف شوند.)
آیدی من برای ارتباط در تلگرام
@bbong9811
موفق باشید.