RecyclerView, SearchView, Retrofit Kullanımı

Merhaba arkadaşlar,
mobilhanem.com üzerinden anlattığımız/yayınladığımız derslere bugün sizlere RecyclerView, SearchView, Retrofit Kullanımı nı bir arada anlatan bir uygulama yapacağım.Bu derse başlamadan önce RecyclerView ve CardView kullanımı ile ilgili bu dersimizi incelemeniz faydalı olacaktır.

Bu dersimizde nelere yer vereceğimize bakalım:

  • Retrofit ile rest api kullanımını bir kez daha pekiştirmiş olacağız.
  • Servisten gelen verileri RecyclerView içinde listeleyeceğiz.
  • SearchView android bileşeninin kullanımını öğreneceğiz.
  • RecyclerView da tıklama olaylarını interface yardımı ile nasıl çözebileceğimizi göreceğiz.
  • Listelenen veriler içinde Adapter sınıfımızda kullanacağımız getFilter fonksiyonu ile arama yaparak aradığımız veriye nasıl ulaşacağımızı göreceğiz.

Şimdi uygulamamızı oluşturmaya başlayalım; Android Studio da projemizi oluşturuyoruz ve uygulama içinde kullanacağımız kütüphaneleri build.gradle kısmına ekleyelim.

build.gradle

apply plugin: 'com.android.application'

android {
    compileSdkVersion 25
    buildToolsVersion '25.0.3'
    defaultConfig {
        applicationId "com.mobilhanem.listandsearchfilterexample"
        minSdkVersion 16
        targetSdkVersion 25
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
        exclude group: 'com.android.support', module: 'support-annotations'
    })
    compile 'com.android.support:appcompat-v7:25.3.1'
    compile 'com.android.support:cardview-v7:25.3.1'
    compile 'com.android.support:recyclerview-v7:25.3.1'
    compile 'com.squareup.retrofit2:retrofit:2.2.0'
    compile 'com.squareup.retrofit2:converter-gson:2.2.0'
    compile 'com.android.support.constraint:constraint-layout:1.0.2'
    testCompile 'junit:junit:4.12'
}

MainActivity sınıfımızın layout kısmında verileri listeleyebileceğimiz RecyclerView yapısını oluşturalım.

activity_main.xml

<?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:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#ccc"
    tools:context="com.mobilhanem.listandsearchfilterexample.MainActivity">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/recycler_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:clipToPadding="false"
        android:scrollbars="vertical" />

</RelativeLayout>

Daha sonra rest api den gelen verilere göre kendi Model yapımızı oluşturuyoruz. Ben model yapımı aşağıdaki servisten dönen json çıktısına göre; User, Address ve Company olarak şekillendirdim.

json çıktısı:

[
  {
    "id": 1,
    "name": "Leanne Graham",
    "username": "Bret",
    "email": "[email protected]",
    "address": {
      "street": "Kulas Light",
      "suite": "Apt. 556",
      "city": "Gwenborough",
      "zipcode": "92998-3874",
      "geo": {
        "lat": "-37.3159",
        "lng": "81.1496"
      }
    },
    "phone": "1-770-736-8031 x56442",
    "website": "hildegard.org",
    "company": {
      "name": "Romaguera-Crona",
      "catchPhrase": "Multi-layered client-server neural-net",
      "bs": "harness real-time e-markets"
    }
  },
  {
    "id": 2,
    "name": "Ervin Howell",
    "username": "Antonette",
    "email": "[email protected]",
    "address": {
      "street": "Victor Plains",
      "suite": "Suite 879",
      "city": "Wisokyburgh",
      "zipcode": "90566-7771",
      "geo": {
        "lat": "-43.9509",
        "lng": "-34.4618"
      }
    },
    "phone": "010-692-6593 x09125",
    "website": "anastasia.net",
    "company": {
      "name": "Deckow-Crist",
      "catchPhrase": "Proactive didactic contingency",
      "bs": "synergize scalable supply-chains"
    }
  },
  {
    "id": 3,
    "name": "Clementine Bauch",
    "username": "Samantha",
    "email": "[email protected]",
    "address": {
      "street": "Douglas Extension",
      "suite": "Suite 847",
      "city": "McKenziehaven",
      "zipcode": "59590-4157",
      "geo": {
        "lat": "-68.6102",
        "lng": "-47.0653"
      }
    },
    "phone": "1-463-123-4447",
    "website": "ramiro.info",
    "company": {
      "name": "Romaguera-Jacobson",
      "catchPhrase": "Face to face bifurcated interface",
      "bs": "e-enable strategic applications"
    }
  },
  {
    "id": 4,
    "name": "Patricia Lebsack",
    "username": "Karianne",
    "email": "[email protected]",
    "address": {
      "street": "Hoeger Mall",
      "suite": "Apt. 692",
      "city": "South Elvis",
      "zipcode": "53919-4257",
      "geo": {
        "lat": "29.4572",
        "lng": "-164.2990"
      }
    },
    "phone": "493-170-9623 x156",
    "website": "kale.biz",
    "company": {
      "name": "Robel-Corkery",
      "catchPhrase": "Multi-tiered zero tolerance productivity",
      "bs": "transition cutting-edge web services"
    }
  },
  {
    "id": 5,
    "name": "Chelsey Dietrich",
    "username": "Kamren",
    "email": "[email protected]",
    "address": {
      "street": "Skiles Walks",
      "suite": "Suite 351",
      "city": "Roscoeview",
      "zipcode": "33263",
      "geo": {
        "lat": "-31.8129",
        "lng": "62.5342"
      }
    },
    "phone": "(254)954-1289",
    "website": "demarco.info",
    "company": {
      "name": "Keebler LLC",
      "catchPhrase": "User-centric fault-tolerant solution",
      "bs": "revolutionize end-to-end systems"
    }
  },
  {
    "id": 6,
    "name": "Mrs. Dennis Schulist",
    "username": "Leopoldo_Corkery",
    "email": "[email protected]",
    "address": {
      "street": "Norberto Crossing",
      "suite": "Apt. 950",
      "city": "South Christy",
      "zipcode": "23505-1337",
      "geo": {
        "lat": "-71.4197",
        "lng": "71.7478"
      }
    },
    "phone": "1-477-935-8478 x6430",
    "website": "ola.org",
    "company": {
      "name": "Considine-Lockman",
      "catchPhrase": "Synchronised bottom-line interface",
      "bs": "e-enable innovative applications"
    }
  },
  {
    "id": 7,
    "name": "Kurtis Weissnat",
    "username": "Elwyn.Skiles",
    "email": "[email protected]",
    "address": {
      "street": "Rex Trail",
      "suite": "Suite 280",
      "city": "Howemouth",
      "zipcode": "58804-1099",
      "geo": {
        "lat": "24.8918",
        "lng": "21.8984"
      }
    },
    "phone": "210.067.6132",
    "website": "elvis.io",
    "company": {
      "name": "Johns Group",
      "catchPhrase": "Configurable multimedia task-force",
      "bs": "generate enterprise e-tailers"
    }
  },
  {
    "id": 8,
    "name": "Nicholas Runolfsdottir V",
    "username": "Maxime_Nienow",
    "email": "[email protected]",
    "address": {
      "street": "Ellsworth Summit",
      "suite": "Suite 729",
      "city": "Aliyaview",
      "zipcode": "45169",
      "geo": {
        "lat": "-14.3990",
        "lng": "-120.7677"
      }
    },
    "phone": "586.493.6943 x140",
    "website": "jacynthe.com",
    "company": {
      "name": "Abernathy Group",
      "catchPhrase": "Implemented secondary concept",
      "bs": "e-enable extensible e-tailers"
    }
  },
  {
    "id": 9,
    "name": "Glenna Reichert",
    "username": "Delphine",
    "email": "[email protected]",
    "address": {
      "street": "Dayna Park",
      "suite": "Suite 449",
      "city": "Bartholomebury",
      "zipcode": "76495-3109",
      "geo": {
        "lat": "24.6463",
        "lng": "-168.8889"
      }
    },
    "phone": "(775)976-6794 x41206",
    "website": "conrad.com",
    "company": {
      "name": "Yost and Sons",
      "catchPhrase": "Switchable contextually-based project",
      "bs": "aggregate real-time technologies"
    }
  },
  {
    "id": 10,
    "name": "Clementina DuBuque",
    "username": "Moriah.Stanton",
    "email": "[email protected]",
    "address": {
      "street": "Kattie Turnpike",
      "suite": "Suite 198",
      "city": "Lebsackbury",
      "zipcode": "31428-2261",
      "geo": {
        "lat": "-38.2386",
        "lng": "57.2232"
      }
    },
    "phone": "024-648-3804",
    "website": "ambrose.net",
    "company": {
      "name": "Hoeger LLC",
      "catchPhrase": "Centralized empowering task-force",
      "bs": "target end-to-end models"
    }
  }
]

User.java

package com.mobilhanem.listandsearchfilterexample.model;

import com.google.gson.annotations.SerializedName;

/**
 * Created by alper on 30.12.2017.
 */

public class User {

    @SerializedName("id")
    private String id;

    @SerializedName("name")
    private String name;

    @SerializedName("username")
    private String username;

    @SerializedName("email")
    private String email;

    @SerializedName("phone")
    private String phone;

    @SerializedName("website")
    private String website;

    @SerializedName("address")
    private Address address;

    @SerializedName("company")
    private Company company;


    public String getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public String getUsername() {
        return username;
    }

    public String getEmail() {
        return email;
    }

    public String getPhone() {
        return phone;
    }

    public String getWebsite() {
        return website;
    }

    public Address getAddress() {
        return address;
    }

    public Company getCompany() {
        return company;
    }


}

Address.java

package com.mobilhanem.listandsearchfilterexample.model;

import com.google.gson.annotations.SerializedName;

/**
 * Created by alper on 30.12.2017.
 */

public class Address {

    @SerializedName("street")
    private String street;

    @SerializedName("suite")
    private String suite;

    @SerializedName("city")
    private String city;

    @SerializedName("zipcode")
    private String zipcode;

    public String getStreet() {
        return street;
    }

    public String getSuite() {
        return suite;
    }

    public String getCity() {
        return city;
    }

    public String getZipcode() {
        return zipcode;
    }

}

Company.java

package com.mobilhanem.listandsearchfilterexample.model;

import com.google.gson.annotations.SerializedName;

/**
 * Created by alper on 30.12.2017.
 */

public class Company {

    @SerializedName("name")
    private String name;

    @SerializedName("catchPhrase")
    private String catchPhrase;

    @SerializedName("bs")
    private String bs;

    public String getName() {
        return name;
    }

    public String getCatchPhrase() {
        return catchPhrase;
    }

    public String getBs() {
        return bs;
    }

}

Verilere ulaşmak için erişeceğimiz rest api için gerekli ana url için bir Const sınıfı oluşturduk.

Const.java

package com.mobilhanem.listandsearchfilterexample;

/**
 * Created by alper on 30.12.2017.
 */

public class Const {

    public static final String BASE_URL = "https://jsonplaceholder.typicode.com/";

}

Şimdi Retrofit yapısını kullanabilmek için öncelikle ApiClient sınıfını oluşturalım.

ApiClient.java

package com.mobilhanem.listandsearchfilterexample.api;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.mobilhanem.listandsearchfilterexample.Const;

import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;


/**
 * Created by alper on 30.12.2017.
 */

public class ApiClient {

    private static Retrofit retrofit = null;

    public static Retrofit getClient() {

        if (retrofit==null) {
            retrofit = new Retrofit.Builder()
                    .baseUrl(Const.BASE_URL)
                    .addConverterFactory(GsonConverterFactory.create())
                    .build();
        }
        return retrofit;
    }
}

Şimdi interface sınıfımızı oluşturduk ve bu kodu detaylıca inceleyelim; @GET methodu ile GET isteğinde bulunacağımızı belirttik ve (“users“) parametresini bu methoda ek olarak verdik. Böylece GET methodu ile veriyi çekeceğimiz url şu şekilde olmaktadır:

Bildiğiniz üzere BASE_URL: https://jsonplaceholder.typicode.com/

GET methodu ile erişeceğimiz URL:  https://jsonplaceholder.typicode.com/users

getUsers methodu ile User tipinde verilerin yer aldığı bir liste döndürdüğünü görüyoruz. Retrofit de  Call<List<User>> şeklinde oluşturarak Call yapısı ile servisten gelen veri tipini Android kısmında oluşturduğumuz yapıyı belirtmektedir.

ApiInterface.java

package com.mobilhanem.listandsearchfilterexample;

import com.mobilhanem.listandsearchfilterexample.model.User;

import java.util.List;

import retrofit2.Call;
import retrofit2.http.GET;

/**
 * Created by alper on 30.12.2017.
 */

public interface ApiInterface {

    @GET("users")
    Call<List<User>> getUsers();
}

Adapter sınıfımız için ekranda liste içinde göstereceğimiz layout yapısını oluşturalım.

list_item.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:card_view="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <android.support.v7.widget.CardView
        android:id="@+id/card_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_gravity="center"
        android:layout_margin="10dp"
        android:elevation="3dp"
        card_view:cardCornerRadius="6dp">

        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent">

            <ImageView
                android:layout_margin="5dp"
                android:scaleType="fitCenter"
                android:src="@drawable/people_icon"
                android:id="@+id/userThumbnail"
                android:layout_centerHorizontal="true"
                android:layout_width="wrap_content"
                android:layout_height="50dp"
                android:background="?attr/selectableItemBackgroundBorderless" />


            <LinearLayout
                android:layout_margin="10dp"
                android:layout_below="@+id/userThumbnail"
                android:orientation="vertical"
                android:layout_width="match_parent"
                android:layout_height="wrap_content">


                    <LinearLayout
                        android:orientation="vertical"
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content">


                        <LinearLayout
                            android:layout_marginBottom="10dp"
                            android:weightSum="1"
                            android:layout_width="match_parent"
                            android:layout_height="wrap_content"
                            android:gravity="center_vertical"
                            android:orientation="horizontal">

                            <TextView
                                android:textSize="12sp"
                                android:textStyle="bold"
                                android:layout_width="0dp"
                                android:layout_height="wrap_content"
                                android:layout_weight="0.4"
                                android:text="@string/user_name" />

                            <TextView
                                android:textStyle="italic"
                                android:textSize="12sp"
                                android:id="@+id/userName"
                                android:layout_width="0dp"
                                android:layout_height="wrap_content"
                                android:layout_weight="0.6"
                                android:text="" />

                        </LinearLayout>

                        <LinearLayout
                            android:layout_marginBottom="10dp"
                            android:weightSum="1"
                            android:layout_width="match_parent"
                            android:layout_height="wrap_content"
                            android:gravity="center_vertical"
                            android:orientation="horizontal">

                            <TextView
                                android:textSize="12sp"
                                android:textStyle="bold"
                                android:layout_width="0dp"
                                android:layout_height="wrap_content"
                                android:layout_weight="0.4"
                                android:text="@string/user_email" />

                            <TextView
                                android:textStyle="italic"
                                android:textSize="12sp"
                                android:id="@+id/userEmail"
                                android:text=""
                                android:layout_width="0dp"
                                android:layout_height="wrap_content"
                                android:layout_weight="0.6" />
                        </LinearLayout>


                    </LinearLayout>


                    <LinearLayout
                        android:orientation="vertical"
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content">


                        <LinearLayout
                            android:layout_marginBottom="10dp"
                            android:weightSum="1"
                            android:layout_width="match_parent"
                            android:layout_height="wrap_content"
                            android:gravity="center_vertical"
                            android:orientation="horizontal">

                            <TextView
                                android:textSize="12sp"
                                android:textStyle="bold"
                                android:layout_width="0dp"
                                android:layout_height="wrap_content"
                                android:layout_weight="0.4"
                                android:text="@string/user_city" />

                            <TextView
                                android:textStyle="italic"
                                android:textSize="12sp"
                                android:id="@+id/userCity"
                                android:layout_width="0dp"
                                android:layout_height="wrap_content"
                                android:layout_weight="0.6"
                                android:text="" />

                        </LinearLayout>

                        <LinearLayout
                            android:weightSum="1"
                            android:layout_width="match_parent"
                            android:layout_height="wrap_content"
                            android:gravity="center_vertical"
                            android:orientation="horizontal">

                            <TextView
                                android:textSize="12sp"
                                android:textStyle="bold"
                                android:layout_width="0dp"
                                android:layout_height="wrap_content"
                                android:layout_weight="0.4"
                                android:text="@string/user_web_page" />

                            <TextView
                                android:textStyle="italic"
                                android:textSize="12sp"
                                android:id="@+id/userWebPage"
                                android:text=""
                                android:layout_width="0dp"
                                android:layout_height="wrap_content"
                                android:layout_weight="0.6" />
                        </LinearLayout>


                    </LinearLayout>


            </LinearLayout>


        </RelativeLayout>

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

</LinearLayout>

RecyclerView Tıklama Olayı

not: ( Bildiğiniz üzere RecyclerView de ListView de olduğu gibi setOnItemClickListener gibi bir method yok bu yüzden listemizde yer alan her bir iteme tıklandığında bunu algılayabilmemiz için bir takım işlemler yapmamız gerekiyor. Bu yüzden CustomItemClickListener adını verdiğimiz bir interface oluşturuyoruz. Oluşturduğumuz bu interface de Adapter da ilgili iteme tıklandığı anda o yerdeki User modelini ve position değerini MainActivity e göndermemize yardımcı olur. Bu şekilde tıklanma olayı ile ilgili işlemleri Adapter da değil de ilgili Activity de gerçekleştirmiş oluruz. Zaten Adapter ın görevi de verileri konumlandırma ve göstermedir.)

CustomItemClickListener.java

package com.mobilhanem.listandsearchfilterexample;

import com.mobilhanem.listandsearchfilterexample.model.User;

/**
 * Created by alper on 1.01.2018.
 */

public interface CustomItemClickListener {
    public void onItemClick(User user, int position);
}

RecyclerView için verileri konumlandıracağımız bir adapter yapısına ihtiyacımız var şimdi adapter yapımızı oluşturalım.  Adapter sınıfımızı Filtereable dan implement ettiğimiz için getFilter methodunu zorunlu olarak tanımladık ve o method da yaptığımız işlemlere bakalım; MainActivity de yer alan SearchView de aramayı tetiklediğimizde performFiltering methoduna girilen karakter değeri gelir ve liste içinde yer alan User modellerinde userName değerine göre arama yapılır (başka değerlere göre de arama yaptırabilirsiniz ) eğer aranan değer hangi liste içinde yer alıyorsa o listedeki değer FilterResults methoduna atanır ve return ettirilir. Geri döndürülen değer publishResults methodu tarafından yakalanır ve adapter yenilenerek liste güncellenmiş olur.

CustomAdapter.java

package com.mobilhanem.listandsearchfilterexample.adapter;

import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Filter;
import android.widget.Filterable;
import android.widget.TextView;

import com.mobilhanem.listandsearchfilterexample.CustomItemClickListener;
import com.mobilhanem.listandsearchfilterexample.R;
import com.mobilhanem.listandsearchfilterexample.model.User;

import java.util.ArrayList;

/**
 * Created by alper on 30.12.2017.
 */

public class CustomAdapter extends RecyclerView.Adapter<CustomAdapter.MyViewHolder> implements Filterable{

    private ArrayList<User> userList;
    private ArrayList<User> filteredUserList;
    private Context context;
    private CustomItemClickListener customItemClickListener;

    public CustomAdapter(Context context,ArrayList<User> userArrayList,CustomItemClickListener customItemClickListener) {
        this.context = context;
        this.userList = userArrayList;
        this.filteredUserList = userArrayList;
        this.customItemClickListener = customItemClickListener;
    }

    @Override
    public CustomAdapter.MyViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
        View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.list_item, viewGroup, false);
        final MyViewHolder myViewHolder = new MyViewHolder(view);
        view.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // for click item listener
                customItemClickListener.onItemClick(filteredUserList.get(myViewHolder.getAdapterPosition()),myViewHolder.getAdapterPosition());
            }
        });
        return myViewHolder;
    }

    @Override
    public void onBindViewHolder(CustomAdapter.MyViewHolder viewHolder, int position) {

        viewHolder.userName.setText(filteredUserList.get(position).getUsername());
        viewHolder.userCity.setText(filteredUserList.get(position).getAddress().getCity());
        viewHolder.userWeb.setText(filteredUserList.get(position).getWebsite());
        viewHolder.userEmail.setText(filteredUserList.get(position).getEmail());
    }

    @Override
    public int getItemCount() {
        return filteredUserList.size();
    }

    @Override
    public Filter getFilter() {

        return new Filter() {
            @Override
            protected FilterResults performFiltering(CharSequence charSequence) {

                String searchString = charSequence.toString();

                if (searchString.isEmpty()) {

                    filteredUserList = userList;

                } else {

                    ArrayList<User> tempFilteredList = new ArrayList<>();

                    for (User user : userList) {

                        // search for user name
                        if (user.getUsername().toLowerCase().contains(searchString)) {

                            tempFilteredList.add(user);
                        }
                    }

                    filteredUserList = tempFilteredList;
                }

                FilterResults filterResults = new FilterResults();
                filterResults.values = filteredUserList;
                return filterResults;
            }

            @Override
            protected void publishResults(CharSequence charSequence, FilterResults filterResults) {
                filteredUserList = (ArrayList<User>) filterResults.values;
                notifyDataSetChanged();
            }
        };
    }

    public class MyViewHolder extends RecyclerView.ViewHolder{
        private TextView userName;
        private TextView userEmail;
        private TextView userCity;
        private TextView userWeb;
        public MyViewHolder(View view) {
            super(view);
            userName = (TextView)view.findViewById(R.id.userName);
            userEmail = (TextView)view.findViewById(R.id.userEmail);
            userWeb = (TextView)view.findViewById(R.id.userWebPage);
            userCity = (TextView)view.findViewById(R.id.userCity);

        }
    }
}

Android Studio da res klasörü altında menu yapısını oluşturuyoruz. menu yapısı altına da menu_item adını verdiğimiz xml dosyasını oluşturduk burada SearchView bileşenini tanımlıyoruz.

menu_item.xml

<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:appcompat="http://schemas.android.com/apk/res-auto">


    <item
        android:id="@+id/menu_search"
        android:title="Arama"
        appcompat:actionViewClass="android.support.v7.widget.SearchView"
        appcompat:showAsAction="always"/>

</menu>

Şimdi MainActivity sınıfımızı oluşturalım ve inceleyelim; GridLayoutManager da 2 değerini verdiğimizi göreceksiniz böylece adapter sınıfında oluşturduğumuz layout ekranda ikişer ikişer item oluşturmamızı sağlamaktadır. Yukarıda oluşturduğumuz Retrofit sınıflarını aşağıdaki şekilde kodladık ve servise istek yaptığımızda eğer hiç bir sorun yok ise yapılan istek de onResponse methodu tetiklenmektedir. response.body() de servisten gelen User tipinde liste dönmektedir. Gelen json tipindeki yapıyı ayrı ayrı parse edip ilgili modellere set etmiyoruz oluşturduğumuz bu yapı ile Retrofit kendisi bu işlemleri yapmaktadır ve istediğimiz veriyi bize geri döndürmektedir. Eğer herhangi bir hata var ise de onFailure methodu tetiklenmektedir. onCreateOptionsMenu de SearchView bileşenini tanımladığımızı göreceksiniz. setOnQueryTextListener methodu ile üst kısımda herhangi bir input değişikliği olduğunda tetiklenmektedir. onQueryTextChange de girilen input değeri değiştiği anda çalışan methoddur. onQueryTextSubmit ise girilen değerden sonra arama tuşuna basıldığında çalışan methoddur.

onQueryTextChange de adapter da tanımladığımız getFilter methodunda bulunan filter fonksiyonuna girilen değeri göndermektedir.

MainActivity.java

package com.mobilhanem.listandsearchfilterexample;

import android.app.ProgressDialog;
import android.content.Context;
import android.graphics.drawable.ColorDrawable;
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.support.v7.widget.SearchView;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.WindowManager;
import android.widget.Toast;

import com.mobilhanem.listandsearchfilterexample.adapter.CustomAdapter;
import com.mobilhanem.listandsearchfilterexample.api.ApiClient;
import com.mobilhanem.listandsearchfilterexample.helper.DialogHelper;
import com.mobilhanem.listandsearchfilterexample.model.User;

import java.util.ArrayList;
import java.util.List;

import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;

public class MainActivity extends AppCompatActivity {

    private ProgressDialog progressDialog;
    private RecyclerView recyclerView;
    private CustomAdapter customAdapter;
    private ArrayList<User> userList;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);


        recyclerView = (RecyclerView)findViewById(R.id.recycler_view);
        RecyclerView.LayoutManager mLayoutManager = new GridLayoutManager(getApplicationContext(), 2);
        recyclerView.setLayoutManager(mLayoutManager);
        recyclerView.setItemAnimator(new DefaultItemAnimator());
        getUserListFromRestApi();

    }

    private void getUserListFromRestApi() {

        progressDialog = createProgressDialog(MainActivity.this);

        ApiInterface apiInterface = ApiClient.getClient().create(ApiInterface.class);


        Call<List<User>> call = apiInterface.getUsers();
                call.enqueue(new Callback<List<User>>() {
        @Override
        public void onResponse(Call<List<User>> call, Response<List<User>> response) {

            progressDialog.dismiss();
            userList = new ArrayList<>(response.body());
            customAdapter = new CustomAdapter(getApplicationContext(), userList, new CustomItemClickListener() {
                @Override
                public void onItemClick(User user, int position) {

                    Toast.makeText(getApplicationContext(),""+user.getUsername(),Toast.LENGTH_SHORT).show();

                }
            });
            recyclerView.setAdapter(customAdapter);

        }

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

            progressDialog.dismiss();
            DialogHelper.getAlertWithMessage("Hata",t.getMessage(),MainActivity.this);
        }
    });


    }


    public ProgressDialog createProgressDialog(Context mContext) {
        ProgressDialog dialog = new ProgressDialog(mContext);
        try {
            dialog.show();
        } catch (WindowManager.BadTokenException e) {

        }
        dialog.setCancelable(false);
        dialog.getWindow().setBackgroundDrawable(new ColorDrawable(android.graphics.Color.TRANSPARENT));
        dialog.setContentView(R.layout.dialog_layout);
        return dialog;
    }



    public boolean onCreateOptionsMenu(Menu menu) {
        MenuInflater menuInflater = getMenuInflater();
        menuInflater.inflate(R.menu.menu_item, menu);

        MenuItem searchItem = menu.findItem(R.id.menu_search);

        SearchView searchView = null;
        if (searchItem != null) {
            searchView = (SearchView) searchItem.getActionView();
        }
        searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
            @Override
            public boolean onQueryTextSubmit(String query) {

                return false;
            }

            @Override
            public boolean onQueryTextChange(String newText) {
                customAdapter.getFilter().filter(newText);
                return true;
            }
        });

        return super.onCreateOptionsMenu(menu);
    }
}

AndroidManifest xml dosyamızda aşağıdadır.

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.mobilhanem.listandsearchfilterexample">

    <uses-permission android:name="android.permission.INTERNET" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity" android:screenOrientation="portrait">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

Uygulamamızı çalıştırdıktan sonra ekran çıktımız aşağıdadır:

En üst kısımda bulunan arama iconuna bastığımız (SearchView) da oluşan ekran görüntüsü aşağıdadır.

Herhangi bir input yazdığımızda arama sonucunda oluşan ekran çıktımız:

 

Evet arkadaşlar bu dersimiz de RecyclerView, SearchView,Retrofit Kullanımını bir arada inceledik. Oluşturduğumuz bu uygulamayı en başından detaylıca anlatmaya çalıştım umarım herkese faydalı olur. Eğer en başından itibaren by yapıyı kendiniz oluşturmayacaksanız; dersin içinde yer alan kaynak kodu indirip incelemeniz faydalı olacaktır.

Tüm Android Ders, Proje ve Kaynak Kodlar için tıklayınız.

Mobilhanem.com üzerinden anlattığımız android uygulama geliştirme derslerine devam edeceğiz. Konu hakkında sorunuzu yorum alanından sorabilirsiniz. Konu dışı sorularınızı ve tüm yazılımsal sorularınızı sorucevap.mobilhanem.com sitemizden de sorabilirsiniz.

Bir dahaki dersimizde görüşmek dileğiyle..

12

Alper Beyler

Yüksek Lisans: Çankaya Üniversitesi / Bilgisayar Mühendisliği
Lisans: Çankaya Üniversitesi / Bilgisayar Mühendisliği (4/3.30) (2010-2014)
Lisans : Viyana Teknik Üniversitesi / Bilgisayar Bilimleri (2013)

13 Yorum

    • Merhaba, olumlu görüşleriniz ve uyarı için teşekkürler gözden kaçmış şimdi kaynak kodu indirip tekrardan deneyebilirsiniz.

  • Elinize sağlık hocam gerçekten çok iyi anlatım olmuş. derslerinizin devamını bekliyoruz.

  • Cok aciklayici ve anlamasi rahat bir makale olmus. Yabanci kaynaklarda dahi bu kadar verimlisini bulamadim. Cok tesekkurler.

    • Çok teşekkürler olumlu görüşleriniz için elimizden geldiğince yardımcı olmaya çalışıyoruz.

  • Ancak bu kadar güzel anlatılabilirdi harika olmuş .Bir sorum var internet bağlantısı kesildiğinde en son yüklenen datayı göstermek için ne yapabilirim ?

  • Elinize sağlık hocam çok güzel anlatm. Hocam benim bir sorum olacak eğer bana ulaşırsanız çok sevinir.

  • Merhaba gerçekten çok sade ve açıklayıcı bir içerik olmuş. Yabancı kaynaklardan çok araştırdığım bir konuyu burada rahatlıkla anladım. Teşekkürler, emeğinize sağlık.

Haftalık Bülten

Mobilhanem'de yayınlanan dersleri haftalık mail almak ister misiniz?