آموزش Retrofit و RxAndroid
از سری مقالات آموزش RxAndroid, میخواهیم با استفاده از Retrofit, ارتباط با Server را برقرار کنیم.
Retrofit یک ابزار امن برای ارتباط با Server از طریق Http است. همانطور که در مقالات قبل نیز بررسی شد, ابزار هایی برای تسهیل کار با Server در اندروید وجود دارند و سعی شد تا مبانی ارتباط با Server را توضیح دهیم. اکنون زمان آن رسیده است که با ابزار قدرتمند دیگری آشنا شویم. یکی از ویژگی های بسیار مهم Retrofit این است که آدرس دهی RESTful API در آن بسیار آسان تر صورت میپذیرد. اهمیت آدرس دهی API در مقالات مرتبط با آن بررسی شده است. در نتیجه استفاده از Retrofit برای ارتباط با RESTful Web Services بسیار مناسب است.
همانطور که میدانید, برای ارتباط با Server نیاز است تا از یک Thread, غیر از Main Thread استفاده کنید. استفاده از AsyncTask بسیار رایج میباشد. اما در مقاله قبل به مزیت استفاده از RxAndroid پرداختیم و از این پس RxAndroid را جایگزین AsyncTask خواهیم کرد.
در این مقاله قصد داریم تا به یک API متصل شویم و مطالب را بر اساس دسته بندی آنها دریافت کنیم. در مقاله قبل RxAndroid و RxJava را به پروژه اضافه کردیم. اکنون نیاز است تا Retrofit Gradle Dependency را به پروژه اضافه کنیم:
compile 'com.squareup.retrofit2:retrofit:2.3.0'
در مرحله اول نیاز است تا یک Java Interface ایجاد کنیم. Retrofit به صورت خودکار, Http API را به این Interface تبدیل میکند:
public interface PostAPIModel { @GET("users/{subject}") Observable<PostModel> getPosts(@Path("subject") String subject); }
در این Interface, با استفاده از متد Http Get, درخواست را به API ارسال میکند و مقدار نتیجه را در Observable قرار میدهد. مقداری که به عنوان String دریافت میکند, مقداری است که بجای {subject} قرار میدهد.
کلاس مدل Post را اینطور پیاده میکنیم:
public class PostModel { private String postTitle; private String PostID; private String postBody; private String postImage; public String getPostTitle() { return postTitle; } public String getPostID() { return PostID; } public String getPostBody() { return postBody; } public String getPostImage() { return postImage; } }
در مرحله بعد باید یک متد static ایجاد کنیم تا وظیفه ارسال درخواست را بر عهده داشته باشد.
public class RetrofitFactory<T> { private final static String mainUrl = "https://api.zerotohero.ir"; public static <T> T createRequest(final Class<T> tClass) { final Retrofit retrofit = new Retrofit.Builder() .baseUrl(mainUrl) .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) .addConverterFactory(GsonConverterFactory.create()) .build(); return retrofit.create(tClass); } }
در اینجا ابتدا آدرس API را مشخص میکنیم. این کلاس Generic است. به این معنا که میتواند متغیر هارا بدون در نظر گرفتن نوع آنها دریافت کند. برای مثال List یک نوع کلاس Generic است. یعنی List<String>, یک لیست از String و List<Integer>, یک لیست از اعداد را ایجاد میکند. همانطور که مشخص است, مهم نیست متغیر های درون لیست از چه نوع باشد. این خاصیت کلاس های Generic است.
ابتدا یک Instance از کلاس Retrofit ایجاد میکنیم. addCallAdapterFactory متدی است که RxJava را برای Retrofit تعریف میکند. سپس با استفاده از addConverterFactory یک Instance از Gson را برای تبدیل Json به کلاس مدل, تعریف میکنیم.
private void makeServerRequset(String subject) { PostAPIModel postAPIModel = RetrofitFactory.createRequest(PostAPIModel.class); postAPIModel.getPosts(subject) .subscribeOn(Schedulers.newThread()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(this::onDataReceived,this::onError,this::onComplete); } private void onDataReceived(PostModel postModel) { cardAdapter.add(postModel); } private void onComplete() { Log.i("Post Info", " Received Completely"); } private void onError(Throwable throwable) { Log.e("Post Error : ", throwable.getMessage()); }
متد makeServerRequest, برای ایجاد درخواست است. با استفاده از متد createRequest, یک Instance از PostAPIModel میسازیم. متغیر subject را به متد getPosts ارسال میکنیم واز متد هایی که در Observable استفاده میکنیم. پردازش را در یک Thread جدید قرار میدهیم و نتیجه را در Main Thread قرار میدهیم. زیرا بروز رسانی User Interface, تنها از طریق Main Thread امکان پذیر است. سپس از subscribe استفاده میکنیم. متغیر اول OnDataReceived است و به عنوان OnNext تعریف میکنیم. تعریف این متد ها با استفاده از Lambda است.
اکنون متد را اینطور فراخوانی میکنیم:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ButterKnife.bind(this); } @OnClick(R.id.search) public void search() { makeServerRequset(searchEditText.getText().toString()); }
در اینجا برای بروز رسانی User Interface, از Butter Knife استفاده کردهایم.
در این مقاله سعی بر این شد تا با استفاده از RxAndroid و Retrofit یک درخواست به API ارسال کنیم.
سری مقالات آموزش اندروید ادامه دارد.
با ما همراه باشید.
مطالب زیر را حتما مطالعه کنید
آموزش Gradle – اهمیت Project Automation
درک مفهوم کدنویسی تمیز در اندروید
5 هک ساده برای کاهش سایز فایل APK
آشنایی با RecyclerView در اندروید
Open/Closed Principle در قوانین Solid
توابع در زبان برنامه نویسی Kotlin
8 Comments
Join the discussion and tell us your opinion.
دیدگاهتان را بنویسید لغو پاسخ
برای نوشتن دیدگاه باید وارد بشوید.
سلام خسته نباشید
چندتا سوال
یکی این که مگ خود رتروفیت درخواست هاشو داخل یه thread دیگ نمیزاره؟
دوم این که شما دارید هر دفعه که یه درخواست داده میشه یه کلاینت از رتروفیت میسازید.این مشکل نداره ب نظرتون؟
و در آخر این که onDataReceived با onComplete چه تفاوتی دارن؟
نمیدونم شاید دوتا سوال اولم اینه ک در مثال جای مناقشه نیس 🙂
سلام دوست عزیز.
جواب سوال اول شما : اگر میخواین از ترد خود retrofit استفاده کنین باید از روش callback استفاده کنین. اما وقتی از rx استفاده میکنین باید مشخص کنین این درخواست روی چه تردی انجام بشه
جواب سوال دوم شما : این یک مقاله آموزشی هست و هدف توضیح ابزاری هست که هدف ایجاد این آموزش هست.
جواب سوال سوم شما : یک observable میتونه شامل داده ها به صورت متوالی باشه. اگر درخواستی که داده میشه به این صورت باشه که فقط یک بار درخواست انجام بشه و بعدش داده دیگه ای نیاد٬ میشه از single استفاده کرد که فقط یک مقدار میگیره. اما در اینجا از observable استفاده شده. بنابراین هر دادهای که بیاد ٬ یک بار onNext فراخوانی میشه که با method reference به متد onDataRecieved ارجاع داده میشه. بعد از اتمام توالی داده ها٬ onComplete فراخوانی میشه. که اینجا هم با method reference به متد onComplete ارجاع داده شده. متد های onComplete, onError, onNext برای خود rx هستند. اما متد onComplete که در این کلاس پیاده سازی شده پیاده سازی خود rx نیست.
با درود ،ممنونم از اینهمه مطالب مفیدتون ، چرا از Disposable استفاده نکردید ؟ راستش من تازه شروع کردم و نمیدونم کدوم روش بهتره یا اصلا نیاز هست از Disposable استفاده بشه ؟
ممنون از همراهی شما دوست عزیز.
یک observable بعد از subscribe شدن یک instance از Disposable برمیگردونه. عملا این interface به ما اجازه میده تا بتونیم با استفاده از اون اتصال بین observer و observable لغو کنیم. به این ترتیب دیگه دادهای دریافت یا بروز رسانی نمیشه. معمولا بهتره این عمل به lifeCycle اون View مد نظر مرتبط بشه که در صورت پایان کار اون View٬ این پردازش هم لغو بشه. در اینجا فقط به یک اشاره از کار با rxAndroid و Retrofit پرداختیم و بسیار ابعاد و ویژگی های بیشتری هم داره که در مقالات بعدی به اون اشاره میشه
سلام خسته نباشید, برای برنامه نویسی realtime باید از rx استفاده کرد یا سوکت؟
راستش من هنوز متوجه نشدم که برای چه مواقعی از rx استفاده میشه اگه امکانش یه توضیح کوچیک درموردش بدین ممنون میشم.
سلام دوست عزیز. ممنون از همراهیتون.
همونطور که در مقالات مرتبط با Rx توضیح داده شد, Rx روی داده ها تمرکز داره. یعنی توی یک پردازش به محض اینکه داده ای برسه onNext و اگر خطایی برسه onFail فرخوانی میکنه. پس محبث Rx برای داده های ما قابل استفاده هست. همچنین Rx برای برنامه نویسی Async هم هست. یعنی پردازش هایی که باید به صورت غیر همروند در برنامه انجام بشن. مثل پردازش هایی که تحت شبکه قراره انجام بشه. وقتی از Socket استفاده میکنیم طبیعتا باید در یک Thread منتظر نتیجه اون باشیم. این انتظار و فعالیت درون Thread میتونیم با استفاده از Rx مدیریت کنیم. در واقع میشه بجای “سوکت یا Rx” از “سوکت با Rx” استفاده کنیم. این دو ابزار میتونن در کنار هم باشن و به افزایش کارایی برنامه شما کمک کنن.
اگر جایی ابهام داشت بفرمایید.
سلام
بغیر از Butter Knife برای بروز رسانی چه راه های دیگه ای امکان پذیره
سلام دوست عزیز. Butter Knife برای اینه که View هایی که در layout ها تعریف شده در داخل کلاس مربوط به اون layout قابل استفاده باشن. چیزی که رایج هست اینه که از findviewById در اندروید استفاده میکنن. اما با استفاده از butter knife این view ها با استفاده از annotation processing برای کلاس تعریف میشن. برای بروز رسانی UI نیاز هست که اول View تعریف بشه و بعد بتونین از متد هاش استفاده کنین . در غیر این صورت null pointer exception دریافت میکنین. منظور بروز رسانی UI اینجا این هست که ما از butter knife برای تعریف View ها برای کلاس استفاده میکنیم.