İyi bir Android kodu ile kötü bir Android kodunu ayırt etmek için kullanılan belirli faktörler vardır. Kod yapısı veya kullanılan yorumlar veya değişken isimleri veya başka bir şey olabilir. Bu nedenle, Android’de her geliştirici , bir Android uygulamasının kodunu yazarken bazı Tasarım Modellerini takip etmelidir . 

  • Anlaşılır kod: Design Pattern kullanarak, kodunuzu herkes için anlaşılır hale getirebilirsiniz, yani kod yazmak için, belirli yönergeleri takip edebilirsiniz ve bu kodu neden yazdığınızı herkes anlayabilir. Örneğin , tekli desen kullanıyorsanız, kodunuzu görüntüleyen herhangi biri burada bir sınıfın yalnızca bir nesnesini yapmak istediğinizi ve uygulama boyunca aynı nesneye erişmek istediğinizi anlayabilir.
  • Kod yeniden kullanılabilirliği: Tasarım Modelini takip ederek kodunuzu yeniden kullanılabilir hale getirebilirsiniz, yani belirli bir görevi birden fazla yerde gerçekleştirmek için aynı kodu çeşitli yerlerde tekrar tekrar yazmanıza gerek kalmaz.
  • Daha temiz kod: Kodu ayırarak kodunuzu daha temiz hale getirebilirsiniz ve Tasarım Modeli kullanarak kodun anlaşılmasını kolaylaştırabilirsiniz.

Tasarım Modeli nedir?

Dolayısıyla, temelde belirli bir özelliği çözmek için izlenebilecek bir modeldir. Bunlar, herhangi bir programcı tarafından bir uygulama oluşturmak için kullanılabilecek en iyi uygulamalardır.

Ayrıca Android’de, kodumuzun anlaşılmasını kolaylaştırmak ve yeniden kullanılabilir hale getirmek için kullanılan bazı Tasarım Modellerini kullanıyoruz.

 *Google’nin MVVM design patterını desteklemektedir.

MVVM, Model , View , ViewModel anlamına gelir .

  • Model : Bu, uygulamanın verilerini tutar. Doğrudan View ile konuşamaz. Genel olarak, verileri ViewModel’e sunmanız önerilir.
  • View: Herhangi bir Uygulama Mantığından yoksun uygulamanın kullanıcı arayüzünü temsil eder.Veriyi ViewModel’e gönderir.
  • ViewModel : Model ve Görünüm arasında bir bağlantı görevi görür. Verilerin Modelden dönüştürülmesinden sorumludur. View’e veri akışları sağlar. Ayrıca Görünümü güncellemek için kancalar veya geri aramalar kullanır. Modelden verileri isteyecektir.

Aşağıdaki akış, çekirdek MVVM Modelini gösterir.

2- MVVM’in Avantajı Ne?

Google, Google I/O 18 ile MVVM’i destekleyeceğini açıkladı ve bunun için componentler oluşturdu. Bunun dışında MVP’ye göre uygulamalar daha hızlı çıkıyor.

3- MVVM ile MVP Arasındaki Farklar

  • Presenter yerine ViewModel kullanılıyor
  • Presenter View’ı klasik yollar ile güncelliyordu lakin MVVM’de Data Binding adında bir olay var aşağıda değineceğiz.
  • ViewModel hangi View’ın kendisini dinlediğini bilmez

Bu farklardan da bahsettiğimize göre artık implementasyona geçebiliriz.

MVVM’i Android uygulamalara implement etmek için 2 yöntem var

1- Data Binding

2- RXJava

Biz bu yazımızda Data Binding yöntemini kullanacağız. Teknik olarak objenizi XML tarafına yollayacağız.

Bunun için BindingAdapter’e ve XML tarafında özel değişikler yapacağız. BindingAdapter XML tarafında bulunan attirubete (değeri) dinliyor olacak.

Projemizde dataBinding’i aktif etmemiz lazım.

 app build.gradle :

android {
dataBinding {
    enabled = true
}
}

Model

public class Package {

    @SerializedName("name")
    @Expose
    private String name;
    @SerializedName("desc")
    @Expose
    private String desc;
    @SerializedName("subscriptionType")
    @Expose
    private String subscriptionType;
    @SerializedName("didUseBefore")
    @Expose
    private Boolean didUseBefore;
    @SerializedName("benefits")
    @Expose
    private Object benefits;
    @SerializedName("price")
    @Expose
    private Double price;
    @SerializedName("tariff")
    @Expose
    private Tariff tariff;
    @SerializedName("availableUntil")
    @Expose
    private String availableUntil;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getDesc() {
        return desc;
    }

    public void setDesc(String desc) {
        this.desc = desc;
    }

    public String getSubscriptionType() {
        return subscriptionType;
    }

    public void setSubscriptionType(String subscriptionType) {
        this.subscriptionType = subscriptionType;
    }

    public Boolean getDidUseBefore() {
        return didUseBefore;
    }

    public void setDidUseBefore(Boolean didUseBefore) {
        this.didUseBefore = didUseBefore;
    }

    public JSONArray getBenefits() {


        Object json = null;
        JSONArray jsonArray = null;
        if(benefits!=null)
        {
        try {
            json = new JSONTokener(benefits.toString()).nextValue();
        } catch (JSONException e) {
            e.printStackTrace();
        }
        if (json instanceof JSONArray) {
            jsonArray = (JSONArray) json;
        }

        }

        return jsonArray;

    }

    public void setBenefits(Object benefits) {
        this.benefits = benefits;
    }

    public Double getPrice() {
        return price;
    }

    public void setPrice(Double price) {
        this.price = price;
    }

    public Tariff getTariff() {
        return tariff;
    }

    public void setTariff(Tariff tariff) {
        this.tariff = tariff;
    }

    public String getAvailableUntil() {
        return availableUntil;
    }

    public void setAvailableUntil(String availableUntil) {
        this.availableUntil = availableUntil;
    }



}

Layout

item_row.xml

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <data>

        <variable
            name="datapackage"
            type="tr.com.harunkor.mvvmdesignpatternsample.model.Package" />


    </data>

    <android.support.v7.widget.CardView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:cardUseCompatPadding="true">

        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="8dp"
            android:orientation="vertical">

            <TextView
                android:id="@+id/name"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@{datapackage.name}" />

            <TextView
                android:id="@+id/desc"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@{datapackage.desc}" />


            <TextView
                android:id="@+id/price"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@{datapackage.price.toString()}" />



            <TextView
                android:id="@+id/availableUntil"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@{datapackage.availableUntil}" />


            <TextView
                android:id="@+id/didUseBefore"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@{datapackage.didUseBefore.toString()}" />


            <TextView
                android:id="@+id/benefits"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@{datapackage.benefits.toString()}" />

        </LinearLayout>

    </android.support.v7.widget.CardView>

</layout>

main_activty.xml

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">


    <data>

        <variable
            name="myAdapter"
            type="tr.com.harunkor.mvvmdesignpatternsample.adapter.MyRecyclerViewAdapter" />
    </data>

<android.support.constraint.ConstraintLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent">


    <android.support.v7.widget.RecyclerView
        android:id="@+id/my_recycler_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scrollbars="vertical"
        android:adapter="@{myAdapter}"
        app:layoutManager="android.support.v7.widget.LinearLayoutManager"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</android.support.constraint.ConstraintLayout>

</layout>

ViewModel

public class PackageViewModel extends BaseObservable {

    private Context context;
    private ApiRetroInterface apiRetroInterface;
    private PackageResources packageResources;
    private onTaskCompleted listener;


    public  PackageViewModel(Context context,onTaskCompleted listener)
    {
        this.context=context;
        this.listener=listener;

        apiRetroInterface= ApiLoginClient.ClientLogin().create(ApiRetroInterface.class);
        Call<PackageResources> call = apiRetroInterface.PackagesAll();
        call.enqueue(new Callback<PackageResources>() {
            @Override
            public void onResponse(Call<PackageResources> call, Response<PackageResources> response) {

                packageResources=response.body();

               setList(packageResources);


                listener.onTaskCompleted();



            }

            @Override
            public void onFailure(Call<PackageResources> call, Throwable t) {

                Toast.makeText(context, ""+t.getMessage(), Toast.LENGTH_SHORT).show();
                Log.d("TAG",""+t.getMessage());

                call.cancel();

            }
        });





    }


    @Bindable
    public PackageResources getList()
    {
        return  packageResources;


    }


   @Bindable
    public void setList(PackageResources mypackageResources)
   {
       packageResources.setPackages(mypackageResources.getPackages());


      // notifyPropertyChanged(BR.name);


   }




}

MainActivity.java

public class MainActivity extends Activity {

    private MainActivtyBinding binding;
    PackageViewModel packageViewModel;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

         binding = DataBindingUtil.setContentView(this, R.layout.main_activty);

         packageViewModel=new PackageViewModel(this, new onTaskCompleted() {
              @Override
              public void onTaskCompleted() {

                 MyRecyclerViewAdapter adapter = new MyRecyclerViewAdapter(packageViewModel.getList(),getApplicationContext());

                  binding.setMyAdapter(adapter);
              }
          });

    }
}