İ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);
}
});
}
}