مدیریت خطا هنگام کار با کتابخانه Retrofit در اندروید


بگارگیری بهینه کتابخانه Retrofit در اندروید

بهینه سازی کار با کتابخانه Retrofit در اندروید

کار با کتابخانه Retrofit در اندروید موضوع مقاله دیگری در این بلاگ بود. همان طور که کتابخانه Retrofit در اندروید را می شناسید محبوب ترین کتابخانه کار با سرور است. برای نمونه وقتی بخواهیم دیتاهای مربوطه را از سرور، در قالب پاسخ json بگیریم از همین ابزار استفاده می کنیم. مثال این برنامه با پیاده سازی Rxjava و کتابخانه Retrofit است که همراه مدیریت خطاهای اینترنت است.

نتیجه این پروژه به صورت زیر خواهد بود :

قدم اول : ایجاد پروژه و افزودن dependency های مربوطه

در فایل build.gradle کتابخانه های مورد نیاز را وارد می نماییم:

// Retrofit instance
implementation 'com.squareup.retrofit2:retrofit:2.5.0'
implementation 'com.squareup.retrofit2:converter-gson:2.4.0'
// RxJava2 Dependencies
implementation 'io.reactivex.rxjava2:rxjava:2.2.8'
implementation 'io.reactivex.rxjava2:rxandroid:2.1.1'

قدم دوم : تنظیمات Retrofit با OkHttp

کلاسی با نام CompRoot می سازیم و قطعه کد زیر را در آن وارد می نماییم.

import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import com.example.internetconnection.DemoApp;
import com.example.internetconnection.network.ApiService;
import com.example.internetconnection.network.ConnectionInterceptor;
import com.example.internetconnection.network.ConnectionListener;
import java.util.concurrent.TimeUnit;
import okhttp3.OkHttpClient;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
public class CompRoot {
  private Retrofit retrofit;
  private static final String BASE_URL = "https://reqres.in/api/";
  public ApiService getService() {
    if (retrofit == null) {
      retrofit = new Retrofit
          .Builder()
          .baseUrl(BASE_URL)
          .client(provideOkHttpClient())
          .addConverterFactory(GsonConverterFactory.create())
          .build();
    }
    return retrofit.create(ApiService.class);
  }
  private OkHttpClient provideOkHttpClient() {
    OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
    httpClient.connectTimeout(30, TimeUnit.SECONDS);
    httpClient.readTimeout(30, TimeUnit.SECONDS);
    httpClient.addInterceptor(new ConnectionInterceptor() {
      @Override
      public boolean isInternetAvailable() {
        return CompRoot.this.isNetworkAvailable(DemoApp.getContext());
      }
      @Override
      public void onInternetUnavailable() {
        ConnectionListener.getInstance().notifyNetworkChange(false);
      }
    });
    return httpClient.build();
  }
  private boolean isNetworkAvailable(Context context) {
    ConnectivityManager cm =
        (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
    NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
    return activeNetwork != null && activeNetwork.isConnectedOrConnecting();
  }
}

در واقع کلاس CompRoot یک کلاس کمکی ست. کار این کلاس را می توان به کمک Dagger2 ساده تر نمود. اما برای جلوگیری از پیچیدگی منطق برنامه کار را با ساخت همین کلاس پیش می بریم.

در ادامه برای تکمیل این مرحله دو قدم را عملی می سازیم:

  • ساخت یک RxBus با نام ConnectionListener
  • ساخت زیر کلاسی از ConnectionInterceptor

ساخت ConnectionListener با الگوی Singleton

این کلاس همان RxBus در برنامه ست که با دیزاین پترن Singleton نوشته شده است. به کمک این کلاس می توان وضعیت را کنترل نمود.

import io.reactivex.Observable;
import io.reactivex.subjects.BehaviorSubject;
public class ConnectionListener {
  private static ConnectionListener mInstance;
  public static ConnectionListener getInstance() {
    if (mInstance == null) {
      mInstance = new ConnectionListener();
    }
    return mInstance;
  }
  private ConnectionListener() {
  }
  //this how to create our bus
  private BehaviorSubject<Boolean> publisher = BehaviorSubject.create();
  public void notifyNetworkChange(Boolean isConnected) {
    publisher.onNext(isConnected);
  }
  // Listen should return an Observable
  public Observable<Boolean> listenNetworkChange() {
    return publisher;
  }
}

ساخت کلاس abstract که در واقع متد های ConnectionInterceptor را پیاده سازی کند

ConnectionInterceptor پیگیر هر بار call کردن API است و در واقع چک می کند که آیا در لحظه امکان دسترسی به اینترنت وجود دارد یا خیر.

import java.io.IOException;
import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.Response;
public abstract class ConnectionInterceptor implements Interceptor {
  public abstract boolean isInternetAvailable();
  public abstract void onInternetUnavailable();
  @Override
  public Response intercept(Chain chain) throws IOException {
    Request request = chain.request();
    if (!isInternetAvailable()) {
      onInternetUnavailable();
    }
    return chain.proceed(request);
  }
}

قدم سوم : ساخت اینترفیس ApiService برای Retrofit

import com.example.internetconnection.network.model.User;
import retrofit2.Call;
import retrofit2.http.GET;
public interface ApiService {
  @GET("users")
  Call<User> getUsers();
}

قدم چهارم : ساخت سوپرکلاس BaseActivity

این کلاس از AppCompatActivity ارث بری می کند. در این کلاس موارد زیر را دنبال می کنیم :

  • ساخت نمونه ای از کلاس CompRoot و از متد ()getCompRoot استفاده می کنیم.
  • در قسمت ()onCreate اکتیویتی از CompositeDisposable نمونه ای می سازیم و در ()onDestroy آن را از بین می بریم.
  • در ()onCreate نمونه InternetConnectionListener را اضافه می کنیم.
  • در ()subscribe متدهای ()onInternetUnavailable را صدا می زنیم.
import android.annotation.SuppressLint;
import android.os.Bundle;
import android.view.View;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import com.example.internetconnection.R;
import com.example.internetconnection.di.CompRoot;
import com.example.internetconnection.network.ConnectionListener;
import com.google.android.material.snackbar.Snackbar;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.functions.Consumer;
import io.reactivex.schedulers.Schedulers;
@SuppressLint("Registered")
public class BaseActivity extends AppCompatActivity {
  private CompRoot compRoot;
  private CompositeDisposable disposable;
  @Override protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    compRoot = new CompRoot();
    disposable = new CompositeDisposable();
    addInternetConnectionListener();
  }
  CompRoot getCompRoot() {
    return compRoot;
  }
  private void addInternetConnectionListener() {
    disposable.add(ConnectionListener.getInstance()
        .listenNetworkChange().subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(new Consumer<Boolean>() {
          @Override public void accept(Boolean aBoolean) throws Exception {
            onInternetUnavailable();
          }
        }));
  }
  @Override protected void onDestroy() {
    super.onDestroy();
    disposable.dispose();
  }
  protected void onInternetUnavailable() {
    showSnackBar(getString(R.string.no_internet_connection));
  }
  protected void showSnackBar(String message) {
    Snackbar.make(getView(), message, Snackbar.LENGTH_SHORT).show();
  }
  private View getView() {
    return findViewById(android.R.id.content);
  }
}

قدم پنجم : تکمیل نمودن MainActivity

import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
import com.example.internetconnection.R;
import com.example.internetconnection.network.ApiService;
import com.example.internetconnection.network.model.User;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
public class MainActivity extends BaseActivity {
  private static final String TAG = "MainActivity";
  ApiService apiService;
  TextView textView;
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    // Bind Views
    textView = findViewById(R.id.textView);
    // Get ApiService service instance
    apiService = getCompRoot().getService();
    executeApiCall();
  }
  public void onRetry(View view) {
    executeApiCall();
  }
  private void executeApiCall() {
    apiService.getUsers().enqueue(new Callback<User>() {
      @Override public void onResponse(Call<User> call, Response<User> response) {
        Log.d(TAG, "onResponse: " + response.body());
      }
      @Override public void onFailure(Call<User> call, Throwable t) {
        Log.d(TAG, "onFailure: ");
      }
    });
  }
  @Override protected void onInternetUnavailable() {
    super.onInternetUnavailable();
    textView.setText(getString(R.string.no_internet_connection));
  }
}

به این پست امتیاز دهید

روی ستاره های کلیک کنید و امتیاز بدید

میانگین امتیاز 3 / 5. تعداد: 2

از امتیاز شما متشکریم

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

Enter Captcha Here : *

Reload Image