Sayfa bulunamadı - Mehmet Kirazlı https://www.mehmetkirazli.com/ Yazılımcı Notları Sun, 17 May 2020 10:19:34 +0000 tr hourly 1 https://wordpress.org/?v=6.1.5 https://www.mehmetkirazli.com/wp-content/uploads/2018/04/mehmetkirazlilogo.png Sayfa bulunamadı - Mehmet Kirazlı https://www.mehmetkirazli.com/ 32 32 Android Firebase Event (not set) Hatası Çözümü https://www.mehmetkirazli.com/android-firebase-event-not-set-hatasi-cozumu/ https://www.mehmetkirazli.com/android-firebase-event-not-set-hatasi-cozumu/#comments Wed, 04 Mar 2020 07:05:57 +0000 https://www.mehmetkirazli.com/?p=3246 Merhaba. Firebase Events’e istatistik attığınızda not set şeklinde bir değer görüyorsanız olası çözümünü göstereceğim. Kod tarafında istatistikleri eğer bir HashMap oluşturup daha sonra bunu Bundle kullanarak gönderdiğinizde bu hatayı alma olasılığınız çok yüksektir. Aşağıda örnek bir kodu göstereceğim. [crayon-660528c3313d0362779671/] Eğer yukarıdaki gibi HashMap kullanıldığında, hashmap’in içindeki değerleri dönerken sorun olabiliyor. Bunun yerine doğrudan Bundle’a set …

The post Android Firebase Event (not set) Hatası Çözümü appeared first on Mehmet Kirazlı.

]]>
Merhaba. Firebase Events’e istatistik attığınızda not set şeklinde bir değer görüyorsanız olası çözümünü göstereceğim.

Kod tarafında istatistikleri eğer bir HashMap oluşturup daha sonra bunu Bundle kullanarak gönderdiğinizde bu hatayı alma olasılığınız çok yüksektir.

Aşağıda örnek bir kodu göstereceğim.

HashMap hashMap = new HashMap<String, String>();
hashMap.put("Baslik", "test");
UtilHelper.sendEventName(mContext, "EventAdi", hashMap);

Eğer yukarıdaki gibi HashMap kullanıldığında, hashmap’in içindeki değerleri dönerken sorun olabiliyor. Bunun yerine doğrudan Bundle’a set ettiğinizde bu hatadan kurtulmuş olursunuz.

Yani yazmanız gereken kod bloğu şu şekilde olmalıdır.

Bundle bundle = new Bundle();
bundle.putString("Baslik", "test");
mFirebaseAnalytics.logEvent("EventAdi", bundle);

The post Android Firebase Event (not set) Hatası Çözümü appeared first on Mehmet Kirazlı.

]]>
https://www.mehmetkirazli.com/android-firebase-event-not-set-hatasi-cozumu/feed/ 2
Namaz Vakitleri Uygulaması Yayında https://www.mehmetkirazli.com/namaz-vakitleri-uygulamasi-yayinda/ https://www.mehmetkirazli.com/namaz-vakitleri-uygulamasi-yayinda/#comments Mon, 13 May 2019 08:23:15 +0000 https://www.mehmetkirazli.com/?p=3202 Merhaba. Android cihazlar için hazırladığım Namaz Vakitleri uygulaması ile 200’e yakın ülkede tüm namaz-ezan vakitlerini görebilirsiniz. Uygulamada birçok özellik mevcuttur ve çok yakında kıble bulma, alarm ve hatırlatıcı kurma gibi özellikler eklenecektir. Siz de indirip yorumlarınızı yaparsanız memnun olurum. Diğer uygulamalarım için geliştirici sayfasına göz atabilirsiniz. Buradan İndirebilirsinizGeliştirici Sayfası Uygulama Ekran Görüntüleri Uygulama Özellikleri ★ …

The post Namaz Vakitleri Uygulaması Yayında appeared first on Mehmet Kirazlı.

]]>
Merhaba. Android cihazlar için hazırladığım Namaz Vakitleri uygulaması ile 200’e yakın ülkede tüm namaz-ezan vakitlerini görebilirsiniz.

Uygulamada birçok özellik mevcuttur ve çok yakında kıble bulma, alarm ve hatırlatıcı kurma gibi özellikler eklenecektir.

Siz de indirip yorumlarınızı yaparsanız memnun olurum.

Diğer uygulamalarım için geliştirici sayfasına göz atabilirsiniz.

Buradan İndirebilirsiniz
Geliştirici Sayfası

Uygulama Ekran Görüntüleri

Uygulama Özellikleri

★ Yaklaşık 200 Ülkenin Tüm Bölgelerinde Namaz Vakitlerine Erişebilirsiniz.
★ Geri Sayım Aracı ile En Yakın Namaz Vaktine Ne Kadar Kaldığını Görebilirsiniz.
★ Miladi ve Hicri Takvimi Görebilir, Ayın Gün İçindeki Konumuna Bakabilirsiniz.
★ Birden Fazla Lokasyon Ekleyebilir, Silebilir ve Birincil Lokasyon Olarak Belirleyebilirsiniz.
★ Namaz Vakitlerini Aylık Olarak Liste ve İmsakiye Formatında Görüntüleyebilirsiniz.
★ Önümüzdeki 4 Yılın Dini Günlerini Görebilirsiniz.
★ Vakitler 30 Günlük Alındığı İçin 30 Günde Bir Vakitleri Tekrar Almalısınız. Bunu Tek Bir Tıklama ile Yapabilirsiniz.
★ İnternetsiz Çalışabilme Özelliğine Sahiptir.

İZİNLER
Uygulamada şuan için herhangi bir izin istenmemektedir. Mümkün olduğunca işlemlerin izinsiz yapılması için gerekli geliştirmeler yapıldı.

5 YILDIZ ★★★★★ VERMEYİ UNUTMAYIN
Daha fazla kişiye ulaşabilmek ve destek olmanız amacıyla 5 yıldız vermeyi unutmayın.

Uygulamamızla ilgili istek, tavsiye ve şikayetlerinizi, uygulamadaki “Bize Yazın” butonu ile de bize iletebilirsiniz. Görüşlerinize göre uygulamada gerekli güncellemelerin yapılmasına özen gösterilecektir.

The post Namaz Vakitleri Uygulaması Yayında appeared first on Mehmet Kirazlı.

]]>
https://www.mehmetkirazli.com/namaz-vakitleri-uygulamasi-yayinda/feed/ 7
Kaza Namazı ve Oruç Takip Uygulaması https://www.mehmetkirazli.com/kaza-namazi-ve-oruc-takip-uygulamasi/ https://www.mehmetkirazli.com/kaza-namazi-ve-oruc-takip-uygulamasi/#comments Mon, 22 Apr 2019 06:33:44 +0000 https://www.mehmetkirazli.com/?p=3180 Selamlar. İnsanlar için faydalı olması amacıyla geliştirdiğim Kaza Namazı ve Oruç Takip Uygulamasını sizlere tanıtmak istiyorum. Uygulamanın amacı, kaza namazı veya oruç borcu olanların bunları otomatik hesaplayıp takibini yapabilmesidir. Bu amaçla uygulamaya alarm özelliği, grafiksel bitiş durumu, soru&cevap gibi özellikler eklenmiştir. Akıllı hesaplayıcı, vereceğiniz yanıtlara bağlı olarak kaza borçlarınızı hesaplar. Mümkün olduğunda yakın bir sayı …

The post Kaza Namazı ve Oruç Takip Uygulaması appeared first on Mehmet Kirazlı.

]]>
Selamlar. İnsanlar için faydalı olması amacıyla geliştirdiğim Kaza Namazı ve Oruç Takip Uygulamasını sizlere tanıtmak istiyorum.

Uygulamanın amacı, kaza namazı veya oruç borcu olanların bunları otomatik hesaplayıp takibini yapabilmesidir. Bu amaçla uygulamaya alarm özelliği, grafiksel bitiş durumu, soru&cevap gibi özellikler eklenmiştir.

Akıllı hesaplayıcı, vereceğiniz yanıtlara bağlı olarak kaza borçlarınızı hesaplar. Mümkün olduğunda yakın bir sayı verebilmek amacıyla tüm ihtimaller göz önünde bulundurulmaya çalışılmıştır.

Siz de indirip yorumlarınızı yaparsanız memnun olurum.

Diğer uygulamalarım için geliştirici sayfasına göz atabilirsiniz.

Buradan İndirebilirsiniz

Geliştirici Sayfası

Uygulama Ekran Görüntüleri

kaza namazı

Uygulama Özellikleri

★ Otomatik Namaz Borcu Hesaplama
★ Kaza Namazı ve Oruçlarınızı Sizin Yerinize Hesaplar.
★ Kıldığınız Namazların Bitiş Durumunu Grafiksel Olarak Görebilirsiniz.
★ Kaza Namazı ve Oruçla Alakalı Soru&Cevap Bölümünde, Sık Sorulan Soruları Görebilirsiniz.
★ Yedekleme Aracıyla Hem Cihazınıza Hem Google Drive Hesabınıza, Veritabanınızı Yedekleyebilir ve Daha Sonra Yükleyebilirsiniz. Bu Sayede Cihazınız Değiştiğinde Veri Kaybına Uğramazsınız.
★ Kaza Namazları Dışında Sık Kılınan Sünnet Namazları da Girebilir ve Takibini Yapabilirsiniz.
★ Kaza Oruçları Dışında Sünnet ve Nafile Olan Oruçları da Girebilirsiniz.
★ Kaza Namazlarınızın Ne Zaman Biteceğine Dair Size Tahmini Bir Tarih Verilir.
★ Kadın ve Erkek İçin Ayrı Ayrı Hesaplama Formülü Kullanılır.
★ Sizin İçin En Doğru Sayıyı Bulmak İçin Birçok Bilgi İster.
★ Kaza Namazlarının Nasıl Kılınacağı ve Kaza Orucunun Nasıl Tutulacağı Hakkında Bilgiler Verir.
★ İnternetsiz Çalışabilme Özelliğine Sahiptir.

The post Kaza Namazı ve Oruç Takip Uygulaması appeared first on Mehmet Kirazlı.

]]>
https://www.mehmetkirazli.com/kaza-namazi-ve-oruc-takip-uygulamasi/feed/ 8
Android Volley Kullanımı ve JSON Parse İşlemleri https://www.mehmetkirazli.com/android-volley-kullanimi-ve-json-parse-islemleri/ https://www.mehmetkirazli.com/android-volley-kullanimi-ve-json-parse-islemleri/#comments Wed, 06 Feb 2019 07:39:06 +0000 https://www.mehmetkirazli.com/?p=3153 Volley, Android uygulamalarımızda kullandığımız AsyncTask’ın alternatifi olarak ortaya çıkarılan, Google I/O 2013 sunumunda duyurulan bir Network(Http) kütüphanesidir. Volley kütüphanesi, hazırladığınız bir REST servisi ya da JSON dosyası varsa, servis URL’ine bağlanıp sonucu size daha hızlı bir şekilde döndürür. AsyncTask kullananlar bilir. doInBackground() metodunda ekran işlemleri yapılmazdı ve tasklar bazen diğerinden önce çalışırdı. Activity bittikten sonra …

The post Android Volley Kullanımı ve JSON Parse İşlemleri appeared first on Mehmet Kirazlı.

]]>
Volley, Android uygulamalarımızda kullandığımız AsyncTask’ın alternatifi olarak ortaya çıkarılan, Google I/O 2013 sunumunda duyurulan bir Network(Http) kütüphanesidir.

Volley kütüphanesi, hazırladığınız bir REST servisi ya da JSON dosyası varsa, servis URL’ine bağlanıp sonucu size daha hızlı bir şekilde döndürür. AsyncTask kullananlar bilir. doInBackground() metodunda ekran işlemleri yapılmazdı ve tasklar bazen diğerinden önce çalışırdı. Activity bittikten sonra AsyncTask kapatılırsa hata alınırdı. Volley ile bu sorunlar ortadan kalkmış oldu. Tüm işlemler asenkron olarak yapıldığı için zaten bu işi yapan AsyncTask’lara da gerek kalmadı.

Volley kütüphanesi, performansı arttırmak için en önemli işlev olarak önbellekleme özelliğini kullanır. Eğer bilgi Cache’de varsa doğrudan sonuç gösterilir. Yoksa yeni bir istek oluşturulur.

Volley kütüphanesinin avantajları :

  • Ağ isteklerinin zamanlamasını otomatik olarak yapar.
  • Cache yapısı olduğundan hızlı işlem yapar. Özellikle resim indirme ve gösterme işlemlerinde disk ya da bellekte cache’leme yapılır.
  • Eş zamanlı olarak çoklu bağlantıya izin verir.
  • İstekleri asenkron olarak işleyebildiği için AsyncTask’taki sorunlar görülmez.
  • AsyncTask’taki gibi karışık ve zorlu kontrollere gerek yoktur.
  • JSON ve resim işlemlerinde güçlü desteği mevcuttur.
  • Yapılan bir istek, istenildiğinde iptal edilebilir. İşi biten istekler otomatik olarak iptal edilir.
  • Büyük boyuttaki veri çekme işlemleri için uygun değildir. Cache sistemi yüksek boyutta veri tutmaya yetmeyecektir.

RequestQueue Sınıfı

Volley bünyesindeki RequestQueue sınıfı, önbelleğe yazma ve önbellekten okuma işlemlerini, istekleri sıraya koyma ve istek sonuçlarını dönme gibi işlemleri yapar. Her ağ isteğinden önce, bu sınıftan bir nesne oluşturulması ve daha sonrasında istenilen bağlantının sağlanması gerekir. Yapılan her isteğin, istekten sonra bu nesneye add() ile eklenmesi gerekir. Böylece istek kuyruğuna isteği eklemiş oluruz ve bu sınıf bizim için kuyruktaki isteklerin yönetimini ve cache’lemelerini yapar. AsyncTask’a göre en önemli avantajı budur.

Her activity için RequestQueue sınıfından nesne oluşturmak yerine, tüm uygulama boyunca tek bir Singleton nesne oluşturup, onun üzerinden kuyruğa ekleme ve çıkarma işlemleri yapılması Google tarafından öneriliyor. Biz uygulamalarımızda Singleton nesne kullanacağız fakat manuel olarak RequestQueue nesnesi oluşturmayı da bilelim. Konunun sonunda UYARI başlığı altında bunun detayları anlatılacaktır.

Yeni Proje Oluşturma

Volley hakkında bilgi verdikten sonra ufaktan proje oluşturalım ve Volley kullanımını görelim.

Proje oluşturduktan sonra ilk olarak build.gradle dosyasında Volley kütüphanesini tanıtıyoruz. Kütüphane ilk çıktığında jar oluşturma işlemini manuel olarak yapıyorduk. Sağolsun maven imdadımıza yetişti.

dependencies {
    implementation 'com.android.support:appcompat-v7:28.0.0'
    implementation 'com.android.support.constraint:constraint-layout:1.1.3'
    implementation 'com.android.volley:volley:1.1.0' // volley için bu satır eklenmeli
}

build.gradle dosyasının tamamı ise şu şekilde olacaktır.

apply plugin: 'com.android.application'

android {
    compileSdkVersion 28
    defaultConfig {
        applicationId "com.mehmetkirazli.volleykullanimi"
        minSdkVersion 15
        targetSdkVersion 28
        versionCode 1
        versionName "1.0"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    implementation 'com.android.support:appcompat-v7:28.0.0'
    implementation 'com.android.support.constraint:constraint-layout:1.1.3'
    implementation 'com.android.volley:volley:1.1.0' // volley için bu satır eklenmeli
}

Şimdi ise AppController sınıfını ekleyelim. Bu sınıf, tüm uygulama boyunca isteklerin takibini ve asenkron çalışmasını sağlar.

Activity tabanlı değil de Application tabanlı bu sınıfı kullanmak, uygulamanın yaşam döngüsü boyunca yönetimin tek bir sınıftan ve tek bir RequestQueue nesnesi üzerinden olması amacıyla daha avantajlıdır. Bu şekilde sınıfı yazıp Manifest içinden de tanımını yapacağız.

AsyncTask kullanırken cihaz döndürüldüğünde, Activity tekrar çalıştığı için AsyncTask da tekrar başlatılıyordu. Volley’de ise Application sınıfından türetilen AppController sınıfı üzerinden, yaşam döngüsü boyunca kuyruğa ekleme çıkarma işlemleri yapılır. Konu başında bundan bahsetmiştik.

package com.mehmetkirazli.volleykullanimi;

import android.app.Application;
import android.text.TextUtils;
import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.toolbox.ImageLoader;
import com.android.volley.toolbox.Volley;

public class AppController extends Application {

    public static final String TAG = AppController.class.getSimpleName();
    private RequestQueue mRequestQueue;
    private static AppController mInstance;
    private ImageLoader mImageLoader;

    @Override
    public void onCreate() {
        super.onCreate();
        mInstance = this;
    }

    public static synchronized AppController getInstance() {
        return mInstance;
    }

    public RequestQueue getRequestQueue() {
        if (mRequestQueue == null) {
            mRequestQueue = Volley.newRequestQueue(getApplicationContext());
        }
        return mRequestQueue;
    }

    // kuyruya istek eklemek için kullanılır (istek adıyla beraber)
    public <T> void addToRequestQueue(Request<T> request, String tag) {
        request.setTag(TextUtils.isEmpty(tag) ? TAG : tag);
        getRequestQueue().add(request);
    }

    // kuyruya istek eklemek için kullanılır (istek adı olmadan)
    public <T> void addToRequestQueue(Request<T> request) {
        request.setTag(TAG);
        getRequestQueue().add(request);
    }

    // resimleri yükleme ve cache işlemleri için çağrılır
    public ImageLoader getImageLoader() {
        getRequestQueue();
        if (mImageLoader == null) {
            mImageLoader = new ImageLoader(this.mRequestQueue,
                    new BitMapCache());
        }
        return this.mImageLoader;
    }

    // volley isteğini iptal etmek için çağrılır
    public void cancelPendingRequests(Object obj) {
        if (mRequestQueue != null) {
            mRequestQueue.cancelAll(obj);
        }
    }
}

AppController sınıfı, Application sınıfından türetilir. Konunun sonunda resim indirme işlemi de yapacağımız için getImageLoader() metodunu da ekledik. Siz kullanmayacaksanız kaldırabilirsiniz.

Resim işlemleri için Cache’leme görevini yapacak olan BitMapCache sınıfımızı da ekleyelim. getImageLoader() metodunda bu sınıfı kullanıyoruz.

package com.mehmetkirazli.volleykullanimi;

import android.graphics.Bitmap;
import android.support.v4.util.LruCache;
import com.android.volley.toolbox.ImageLoader;

public class BitMapCache extends LruCache<String, Bitmap> implements ImageLoader.ImageCache {
    public static int getDefaultLruCacheSize() {
        final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
        final int cacheSize = maxMemory / 8;

        return cacheSize;
    }

    public BitMapCache() {
        this(getDefaultLruCacheSize());
    }

    public BitMapCache(int sizeInKiloBytes) {
        super(sizeInKiloBytes);
    }

    @Override
    protected int sizeOf(String key, Bitmap value) {
        return value.getRowBytes() * value.getHeight() / 1024;
    }

    @Override
    public Bitmap getBitmap(String url) {
        return get(url);
    }

    @Override
    public void putBitmap(String url, Bitmap bitmap) {
        put(url, bitmap);
    }
}

Daha sonra AndroidManifest.xml dosyasında İnternet izni ekliyoruz. Uygulamada kullanacağımız 3 adet aktiviteyi tanımlıyoruz. Son olarak da application tag’inde name kısmında AppController‘i tanımlıyoruz.

AppController kullanmayıp her istek için RequestQueue kullansaydık bu name tanımını yapmayacaktık.

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

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

    <application
        android:name="com.mehmetkirazli.volleykullanimi.AppController"
        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=".ActivityMain">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <activity android:name=".ActivityMarkalar"/>
        <activity android:name=".ActivityKullanicilar"/>
        <activity android:name=".ActivityResimler"/>
    </application>

</manifest>


Giriş Ekranı

activity_main.xml dosyasına 3 adet buton ekleyelim. 1.sinde basit olarak JSON dosyasını okuyup listeye basalım. 2.sinde biraz daha karışık olan JSON dosyasını parse edip sonuçları bir listede gösterelim. Son butonda da Volley ile çekilen resimleri ImageView üzerinde gösterelim.

Bu işlemler yeni Activity üzerinde yapılacak o yüzden her bir buton için yeni bir Activity oluşturacağız ve her tıklamada yeni Activity açacağız.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button
        android:id="@+id/btnMarka"
        android:layout_width="183dp"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="180dp"
        android:text="Markaları Göster" />
    
    <Button
        android:id="@+id/btnKullanici"
        android:layout_width="183dp"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="230dp"
        android:text="Kullanıcıları Göster" />

    <Button
        android:id="@+id/btnResim"
        android:layout_width="183dp"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="280dp"
        android:text="Resimleri Göster" />

</RelativeLayout>

Bu ekrana bağlı olan ActivityMain.java sınıfımız ise şu şekilde olacaktır.

package com.mehmetkirazli.volleykullanimi;

import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

public class ActivityMain extends AppCompatActivity {
    Button btnKullanici, btnMarka, btnResim;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        btnKullanici = (Button) findViewById(R.id.btnKullanici);
        btnMarka = (Button) findViewById(R.id.btnMarka);
        btnResim = (Button) findViewById(R.id.btnResim);

        btnMarka.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                startActivity(new Intent(getApplicationContext(), ActivityMarkalar.class));
            }
        });

        btnKullanici.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                startActivity(new Intent(getApplicationContext(), ActivityKullanicilar.class));
            }
        });

        btnResim.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                startActivity(new Intent(getApplicationContext(), ActivityResimler.class));
            }
        });
    }
}


Markalar Ekranı

Buraya kadar Volley kullanarak bir Http isteği yapmadık. Bundan sonra istek gönderme işlemlerine başlıyoruz. İlk olarak elimizde markaları gösteren bir JSON dosyası olsun ve bu dosyayı çağırarak dönen sonucu bir listede gösterelim.

Önce markalar.json dosyasının içeriğini verelim sonra bunu Volley ile çağırıp dönen sonuçları Parse ederek gösterelim.

{
"markalar":[
    "Alfa Romeo",
    "Bmw",
    "Dacia",
    "Fiat",
    "Ford",
    "Honda",
    "Hyundai",
    "Jaguar",
    "Lada",
    "Mazda",
    "Mercedes",
    "Nissan",
    "Opel",
    "Peugeot",
    "Renault",
    "Seat",
    "Skoda",
    "Subaru",
    "Suzuki",
    "Tofaş",
    "Toyota",
    "Volkswagen",
    "Volvo"
    ]
}

Şimdi ActivityMarkalar sınıfını kodlamaya başlayalım.

package com.mehmetkirazli.volleykullanimi;

import android.app.ProgressDialog;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.Toast;

import com.android.volley.Request;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.StringRequest;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.util.ArrayList;

public class ActivityMarkalar extends AppCompatActivity {
    ListView listViewMarka;
    ProgressDialog dialog;
    String urlMarkalar = "https://www.mehmetkirazli.com/Dosya/markalar.json";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_markalar);

        listViewMarka = (ListView) findViewById(R.id.lwMarka);

        // istek bitene kadar dialog gösterilir. istek sonuçlanınca dialog kapatılacak
        dialog = new ProgressDialog(this);
        dialog.setMessage("Veriler Okunuyor...");
        dialog.setCancelable(false);
        dialog.show();

         /* StringRequest yerine JsonObjectRequest veya JsonArrayRequest de kullanılabilir.
         Fakat StringRequest hepsini kapsadığı için bunu kullandık. */
        // VOLLEY İSTEĞİ BURADA YAPILIYOR.
        StringRequest request = new StringRequest(Request.Method.GET, urlMarkalar, new Response.Listener<String>() {
            @Override
            public void onResponse(String string) { // sonuç başarılı dönerse onResponse çağrılır
                okunanlariParseEt(string);
            }
        }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError volleyError) { // hata olursa volleyError nesnesinde hata sebebi yazar
                Toast.makeText(getApplicationContext(), "Veriler Okunurken Hata Oluştu", Toast.LENGTH_SHORT).show();
                dialog.dismiss();
            }
        });

        // isteği kuyruğa ekledik. "markalar" etiketini ise isteği iptal etmek istediğimizde kullanacağız. Zorunlu değildir
        AppController.getInstance().addToRequestQueue(request, "markalar"); 
    }

    void okunanlariParseEt(String okunanJson) { // dönen sonucu parse ediyoruz
        try {
            JSONObject jsonObj = new JSONObject(okunanJson);
            JSONArray arrayMarka = jsonObj.getJSONArray("markalar");
            ArrayList<String> sonucList = new ArrayList<>();

            for (int i = 0; i < arrayMarka.length(); ++i) { // markaları tek tek listeye ekledik
                sonucList.add(arrayMarka.getString(i));
            }

            // oluşturduğumuz sonucList listesini, listview'ın adaptörüne verdik ve listede gösterilmesini sağladık
            ArrayAdapter<String> adapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, sonucList);
            listViewMarka.setAdapter(adapter);
        } catch (JSONException e) {
            e.printStackTrace();
        }
        dialog.dismiss();
    }
}

Burada yapılan işlemleri açıklama satırlarında anlatmaya çalıştım. Yine üzerinden geçelim.

Bir StringRequest nesnesi oluşturduk. İlk parametresi, isteğin tipidir. Biz GET isteğinde bulunduk. Sonraki parametre, bağlanacağımız URL‘dir. Diğer 2 parametre ise başarılı ve başarısız sonuç döndüğünde çalışacak Listener‘lardır.

Sonuç dönerse onResponse() metodu çalışır. Bu metotta dönen JSON değeri parse edilir ve değerler tek tek listeye eklenir. Son olarak liste, ListView‘a adaptör olarak verilir ve ekranda gösterilir.

Eğer dönen JSON değeri, doğrudan bir JSON Array‘i ise StringRequest yerine JsonArrayRequest de kullanabilirsiniz. O zaman Listener’a ait metotlar da değişecektir. JSON Objesi ise JsonObjectRequest sınıfı kullanılabilir. StringRequest ikisini de kapsadığı için ben bunu kullandım.

Bu sınıfa ait xml dosyasını da oluşturalım.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ListView
        android:id="@+id/lwMarka"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
</RelativeLayout>

Markaları Göster butonuna tıkladığımızda ekran görüntüsü şu şekilde olacaktır.


Kullanıcılar Ekranı

ActivityKullanicilar.java sınıfında ise biraz daha detaylı bir JSON dosyası okuyacağız ve parse edip ListView’da göstereceğiz.

Öncelikle URL’imizde bulunan JSON dosyasının içeriğini paylaşalım. JSON dosyasında şu bilgiler bulunmaktadır.

[{
  "id": 1,
  "ad": "Mehmet",
  "soyad": "Kirazli",
  "sehir": "Istanbul",
  "cinsiyet": "Erkek",
  "ip_adres": "36.48.233.2"
}, {
  "id": 2,
  "ad": "Faruk",
  "soyad": "Kalkan",
  "sehir": "Edirne",
  "cinsiyet": "Erkek",
  "ip_adres": "212.111.4.222"
}, {
  "id": 3,
  "ad": "Salih",
  "soyad": "Aydin",
  "sehir": "Samsun",
  "cinsiyet": "Erkek",
  "ip_adres": "120.33.112.111"
}, {
  "id": 4,
  "ad": "Okan",
  "soyad": "Eren",
  "sehir": "Giresun",
  "cinsiyet": "Erkek",
  "ip_adres": "77.77.222.11"
}]

Şimdi bu JSON dosyasına Volley ile erişip okuma işlemi yapalım.

Şuan elimde JSON bilgisi dönen bir servis olmadığı için hazır bir JSON dosyasına erişiyorum. Eğer JSON dönen www.mehmetkirazli.com/apis/getusers.php gibi bir servis olsaydı, URL kısmında bunu yazacaktım. Fakat siz test amaçlı olarak :
https://maps.googleapis.com/maps/api/place/textsearch/xml?query=restaurants+in+Sydney&key=API_KEY 
URL’ini test edebilirsiniz. Api key girerek servisten dönen JSON değerini görebilirsiniz.

ActivitiyKulanicilar.java

package com.mehmetkirazli.volleykullanimi;

import android.app.ProgressDialog;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.Toast;

import com.android.volley.Request;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.StringRequest;

import org.json.JSONArray;
import org.json.JSONException;

import java.util.ArrayList;

public class ActivityKullanicilar extends AppCompatActivity {
    ListView listViewMarka;
    String urlKullanicilar = "https://www.mehmetkirazli.com/Dosya/kullanicilar.json";
    ProgressDialog dialog;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_kullanicilar);

        listViewMarka = (ListView) findViewById(R.id.lwMarka);

        // istek bitene kadar dilaog gösterilir. istek sonuçlanınca dialog kapatılacak
        dialog = new ProgressDialog(this);
        dialog.setMessage("Veriler Okunuyor...");
        dialog.setCancelable(false);
        dialog.show();

        /* StringRequest yerine JsonObjectRequest veya JsonArrayRequest de kullanılabilir.
         Fakat StringRequest hepsini kapsadığı için bunu kullandık. */
        // VOLLEY İSTEĞİ BURADA YAPILIYOR.
        StringRequest request = new StringRequest(Request.Method.GET, urlKullanicilar, new Response.Listener<String>() {
            @Override
            public void onResponse(String sonuc) { // sonuç başarılı dönerse onResponse çağrılır
                ArrayList<Kullanicilar> kullaniciList = okunanlariParseEt(sonuc); // parse metodu çağrıldı
                ArrayAdapter<Kullanicilar> adapter = new ArrayAdapter<>(ActivityKullanicilar.this, android.R.layout.simple_list_item_1, kullaniciList);
                listViewMarka.setAdapter(adapter);
            }
        }, new Response.ErrorListener() { // hata oluşursa burası çağrılır
            @Override
            public void onErrorResponse(VolleyError volleyError) {
                Toast.makeText(getApplicationContext(), "Veriler Okunurken Hata Oluştu", Toast.LENGTH_SHORT).show();
                dialog.dismiss();
            }
        });

        AppController.getInstance().addToRequestQueue(request, "kullanicilar");
    }

    ArrayList<Kullanicilar> okunanlariParseEt(String okunanJson) {
        ArrayList<Kullanicilar> kullaniciList = new ArrayList<>();
        try {
            JSONArray arrayKullanici = new JSONArray(okunanJson);
            for (int i = 0; i < arrayKullanici.length(); ++i) {
                kullaniciList.add(new Kullanicilar(Integer.valueOf(arrayKullanici.getJSONObject(i).get("id").toString()), arrayKullanici.getJSONObject(i).get("ad").toString(),
                        arrayKullanici.getJSONObject(i).get("soyad").toString(), arrayKullanici.getJSONObject(i).get("sehir").toString(),
                        arrayKullanici.getJSONObject(i).get("cinsiyet").toString(), arrayKullanici.getJSONObject(i).get("ip_adres").toString()));
            }
        } catch (JSONException e) {
            e.printStackTrace();
        }

        dialog.dismiss();
        return kullaniciList;
    }
}

Genel olarak Markalar sınıfındaki benzer işlemleri yaptık. Parse işlemleri biraz daha karışık oldu. AppController sınıfında addToRequestQueue() metoduna, isteğimizi parametre olarak verdik ve kuyruğa ekledik. Yanında bir de “kullanicilar” metnini verdik. Bunu, isteği iptal etmek istediğimizde kullanacağız ve bu isimle iptal edeceğiz. Bunu kendisi yapıyor fakat örnek olması açısından yazdım. Bu parametreyi yazmak zorunlu değildir.

Burada Markalar sınıfından farklı olarak, dönen JSON’ı parse edip Kullanicilar adında bir model sınıfına ekledik. Kullanicilar sınıfını da verelim.

Kullanicilar Model sınıfı:

package com.mehmetkirazli.volleykullanimi;

public class Kullanicilar {
    private int id;
    private String ad;
    private String soyad;
    private String sehir;
    private String cinsiyet;
    private String ip_adres;

    public Kullanicilar(int id, String ad, String soyad, String sehir, String cinsiyet, String ip_adres) {
        this.id = id;
        this.ad = ad;
        this.soyad = soyad;
        this.sehir = sehir;
        this.cinsiyet = cinsiyet;
        this.ip_adres = ip_adres;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getAd() {
        return ad;
    }

    public void setAd(String ad) {
        this.ad = ad;
    }

    public String getSoyad() {
        return soyad;
    }

    public void setSoyad(String soyad) {
        this.soyad = soyad;
    }

    public String getSehir() {
        return sehir;
    }

    public void setSehir(String sehir) {
        this.sehir = sehir;
    }

    public String getCinsiyet() {
        return cinsiyet;
    }

    public void setCinsiyet(String cinsiyet) {
        this.cinsiyet = cinsiyet;
    }

    public String getIp_adres() {
        return ip_adres;
    }

    public void setIp_adres(String ip_adres) {
        this.ip_adres = ip_adres;
    }

    @Override
    public String toString() {
        return ad + " " + soyad + "\n" + cinsiyet + "-" + sehir + "-" + ip_adres;
    }
}

Bu model sınıfında en son toString() metodunu override ettik. Çünkü ListView’a bu modele ait listeyi parametre olarak verdiğimizde, her satırda görülmesi istenen metni yazdık. Custom bir Adapter‘e gerek kalmadı.

activity_kullanicilar.xml dosyası :

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ListView
        android:id="@+id/lwMarka"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
</RelativeLayout>

“Kullanıcıları Göster” butonuna tıkladığımızda ActivityKullanicilar ekranı açılacak ve sonuç alınıp ekrana aşağıdaki gibi bilgiler yazılacak. Tabi bu arada ProgressBar da dönecek ve sonuç döndüğünde progress kapanacak.


POST İSTEĞİ GÖNDERME

Bu zamana kadar örneklerde GET isteği gönderdik.

StringRequest request = new StringRequest(Request.Method.GET, urlKullanicilar, new Response.Listener<String>() {

Satırında da GET isteği gönderdiğimizi belirttik. Hazırladığınız servisin özelliğine göre POST isteği de göndermek isteyebilirsiniz. POST isteklerinde servise parametre gönderirsiniz ve size sonuç döner. URL kısmında ise gönderdiğiniz parametreler yazmaz. GET isteğinde ise bu parametreler yazar. Parametreden kastımız örnek olarak id = 1 gönderirsiniz ve id değeri 1 olan kayıtlar serviste okunur ve sonuç JSON olarak size döner.

Yani GET işleminde URL’de parametreleri yazarız (Örneklerimizde parametre yoktu). POST işleminde ise parametreleri URL’e yazmayız, arkaplanda göndeririz.

Volley ile POST isteği oluşturduğunuzda, her şey aynı sadece StringRequest‘i oluşturduğunuz satırda aşağıdaki gibi ufak bir değişiklik yapıyorsunuz.

StringRequest request = new StringRequest(Request.Method.POST, urlKullanicilar, new Response.Listener<String>() {

Daha sonra da isteğin sonuna parametreleri ekliyorsunuz. Parametre ekleme metodu olan getParams() metodundaki süslü parantezlerin sırasına dikkat ediniz. Çünkü bu bölüm biraz karışık. Kod bloğumuz son olarak şu şekilde olur:

StringRequest request = new StringRequest(Request.Method.POST, urlKullanicilar, new Response.Listener<String>() {
            @Override
            public void onResponse(String string) {
                ArrayList<Kullanicilar> kullaniciList = okunanlariParseEt(string);
                ArrayAdapter<Kullanicilar> adapter = new ArrayAdapter<>(ActivityResimler.this, android.R.layout.simple_list_item_1, kullaniciList);
                listViewMarka.setAdapter(adapter);
            }
        }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError volleyError) {
                Toast.makeText(getApplicationContext(), "Veriler Okunurken Hata Oluştu", Toast.LENGTH_SHORT).show();
                dialog.dismiss();
            }
        }) {
            @Override
            protected Map<String, String> getParams() {
                Map<String, String> params = new HashMap<>();
                params.put("id", "2");
                return params;
            }
        };

        AppController.getInstance().addToRequestQueue(request);

Burada id değeri 2 ye eşit olan kaydı bize getirir. Tabi servisin de buna uygun kontrolleri yapmış olması gerekiyor. Örnek olarak eğer servisimiz PHP ile hazırlanmışsa şu şekilde kontrol olacaktır.

if($_SERVER['REQUEST_METHOD']=="POST"){
	$id= @$_POST['id'];
}

Bunu GET ile yapsaydık urlKullanicilar URL’inin sonunda ?id=2 gibi bir ekleme yapılacaktı ve getParams() olmayacaktı.

Header Ekleme

Eğer POST isteğinize bir Header bilgisi eklemek istiyorsanız, isteğinizi aşağıdaki gibi güncellemeniz gerekmektedir.

StringRequest request = new StringRequest(Request.Method.POST, urlKullanicilar, new Response.Listener<String>() {
            @Override
            public void onResponse(String string) {
                ArrayList<Kullanicilar> kullaniciList = okunanlariParseEt(string);
                ArrayAdapter<Kullanicilar> adapter = new ArrayAdapter<>(ActivityResimler.this, android.R.layout.simple_list_item_1, kullaniciList);
                listViewMarka.setAdapter(adapter);
            }
        }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError volleyError) {
                Toast.makeText(getApplicationContext(), "Veriler Okunurken Hata Oluştu", Toast.LENGTH_SHORT).show();
                dialog.dismiss();
            }
        }) {
            @Override
            public Map<String, String> getHeaders() throws AuthFailureError {
                HashMap<String, String> headers = new HashMap<>();
                headers.put("Content-Type", "application/json");
                headers.put("apiKey", "abcdefghijklmn");
                return headers;
            }
        };


ÖNEMLİ BİR UYARI

Konu başında belirtmiştim. Volley isteği oluşturduktan sonra isteği, AppController üzerinden kuyruğa ekliyoruz. Bu işlem şu şekilde de yapılabiliyor fakat önerilmiyor.

İsteği oluşturmadan önce :

RequestQueue rQueue = Volley.newRequestQueue(ActivityMarkalar.this);

Kod bloğu ile bir kuyruk oluşturuluyor. İstek oluşturulduktan sonra da aşağıdaki gibi isteğimiz kuyruğa ekleniyor.

İsteği oluşturduktan sonra :

rQueue.add(request);

Eğer uygulamada çokça Volley isteği olacaksa, bu işlemlerin tek bir SingletonClass üzerinden yapılması (AppController) daha doğrudur ve Google da bunu önermektedir. Fakat az sayıda istek olması durumunda manuel olarak her istek için RequestQueue nesnesi de oluşturulabilir. Bu şekilde bir yapı kullanılacaksa, RequestQueue nesnesi, istek yapılmadan önce oluşturulmalıdır.

Resim İşlemleri

Son olarak Volley ile resim bilgisini okuyup ImageView üzerinde gösterim işlemini yapalım. Okunan resim bilgisini Bitmap‘e çevirip ImageView içerisine set edeceğiz.

İlk olarak xml tarafını yazalım. Basit bir ImageView olması yeterli. activity_resimler:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ImageView
        android:id="@+id/imgView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_alignParentTop="true" />
</RelativeLayout>

Şimdi de ActivityResimler sınıfını kodlayalım.

package com.mehmetkirazli.volleykullanimi;

import android.app.ProgressDialog;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.widget.ImageView;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.ImageLoader;

public class ActivityResimler extends AppCompatActivity {
    String urlResimler = "https://www.mehmetkirazli.com/wp-content/uploads/2017/03/islami-hafiza-oyunu-310x165.png";
    ProgressDialog dialog;
    ImageView imgView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_resimler);

        imgView = (ImageView) findViewById(R.id.imgView);

        dialog = new ProgressDialog(this);
        dialog.setMessage("Veriler Okunuyor...");
        dialog.setCancelable(false);
        dialog.show();

        ImageLoader imageLoader = AppController.getInstance().getImageLoader();
        // resim indirilirken ve hata olması durumunda gösterilecek resimleri ayarladık.
        imageLoader.get(urlResimler, ImageLoader.getImageListener(imgView, R.drawable.yukleniyor, R.drawable.hata));
        // resim alınıyor
        imageLoader.get(urlResimler, new ImageLoader.ImageListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                dialog.dismiss(); // hata olursa dialog kapansın ve hata mesajı loga basılsın
                Log.d("hata",error.toString());
            }

            @Override
            public void onResponse(ImageLoader.ImageContainer response, boolean arg1) {
                if (response.getBitmap() != null) {
                    imgView.setImageBitmap(response.getBitmap()); // bitmap'e çevirip set ettik
                }
                dialog.dismiss();
            }
        });
    }
}

Burada resim indirilirken aşağıdaki YÜKLENİYOR resmi ImageView’da gösterilecek.

Eğer resim indirilirken hata alınırsa da ImageView’da aşağıdaki hata resmi gösterilecek. Volley ile bunları ayarlayabilmek iyi oluyor.

Ekran çıktımız ise şu şekilde olacaktır.


Cache Okuma ve Silme

Volley kütüphanesinde Cache mekanizması olduğunu ve bu yüzden hız konusunda avantaj sağladığını söylemiştik. Cache’de tutulan bilgileri görmek, eğer cache boşsa yeni bir istek yapmak isteyebiliriz. Bunun kullanımı ise şu şekildedir.

Cache cache = AppController.getInstance().getRequestQueue().getCache();
        Cache.Entry entry = cache.get("https://www.mehmetkirazli.com/Dosya/markalar.json");
        if (entry != null) {
            try {
                String cacheBilgisi = new String(entry.data, "UTF-8");
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
        } else {
            // cache boş. yeni istek yapılabilir
        }

Daha önce gidilmiş bir URL varsa, Cache‘de tutulan dönüş bilgisini bu şekilde görebiliriz. Debug yapıldığında, cacheBilgisi değişkeninde, henüz istek yapılmadan JSON değeri görülür.

Url’deki JSON bilgisinin değiştiğini düşünürsek, Cache bilgisini silmek için ise aşağıdaki kod kullanılabilir.

AppController.getInstance().getRequestQueue().getCache().remove("https://www.mehmetkirazli.com/Dosya/markalar.json");


İstek İptal Etme

Örneklerde kuyruğa eklerken bir parametre daha eklemiştik hatırlarsanız. Bunu daha sonra istek iptal etmek istediğimizde KEY olarak kullanacağımızı söylemiştik.

Eğer kullanıcıları aldığımız isteği herhangi bir sebeple iptal etmek istersek:

AppController.getInstance().getRequestQueue().cancelAll("kullanicilar");

Komutunu kullanmalıyız. Volley bunu bizim için yapıyor fakat bir yerde işleyişe müdahale etmek istediğimizde işimize yarayacaktır.

Volley kütüphanesinin kullanımı bu şekildedir. Uzun bir yazı oldu umarım anlatabilmişimdir.

Geliştiriciler için Volley bir nimettir. En azından AsyncTask belasından kurtulmuş olduk 🙂 Görüşmek üzere…

KAYNAK KODLAR

The post Android Volley Kullanımı ve JSON Parse İşlemleri appeared first on Mehmet Kirazlı.

]]>
https://www.mehmetkirazli.com/android-volley-kullanimi-ve-json-parse-islemleri/feed/ 2
Android ButterKnife Kütüphanesi Kullanımı https://www.mehmetkirazli.com/android-butterknife-kutuphanesi-kullanimi/ https://www.mehmetkirazli.com/android-butterknife-kutuphanesi-kullanimi/#comments Mon, 04 Feb 2019 10:42:03 +0000 https://www.mehmetkirazli.com/?p=3136 Merhaba. Bu yazımda Android platformunda kullanıma sunulan, bazı kod bloklarını basitleştiren ve okunabilirliği arttıran ButterKnife kütüphanesinden bahsedeceğim. ButterKnife, Square firmasında Jake Wharton tarafından geliştirilmiş kullanışlı bir kütüphanedir. ButterKnife ile Xml yani tasarım tarafında oluşturduğumuz bazı elemanları, Java tarafına geçirmemizi ve kullanabilmemizi sağlar. Xml tarafından kastım Button, TextView, ListView, Drawable, Color, Strings vs. ButterKnife kütüphanesinin kullanımını …

The post Android ButterKnife Kütüphanesi Kullanımı appeared first on Mehmet Kirazlı.

]]>
Merhaba. Bu yazımda Android platformunda kullanıma sunulan, bazı kod bloklarını basitleştiren ve okunabilirliği arttıran ButterKnife kütüphanesinden bahsedeceğim.

ButterKnife, Square firmasında Jake Wharton tarafından geliştirilmiş kullanışlı bir kütüphanedir.

ButterKnife ile Xml yani tasarım tarafında oluşturduğumuz bazı elemanları, Java tarafına geçirmemizi ve kullanabilmemizi sağlar. Xml tarafından kastım Button, TextView, ListView, Drawable, Color, Strings vs.

ButterKnife kütüphanesinin kullanımını basit bir örnek üzerinde gösterelim.

İlk olarak build.gradle dosyamızı hazırlayalım. ButterKnife kütüphanesini kullanabilmek için build.gradle dosyasında en tepeye aşağıdaki satır eklenir.

apply plugin: 'com.android.application'

En altta dependencies kısmına ise şu 2 satır kod eklenmelidir. Son hali:

apply plugin: 'com.android.application'

android {
    compileSdkVersion 28
    defaultConfig {
        applicationId "com.mehmetkirazli.butterknife"
        minSdkVersion 15
        targetSdkVersion 28
        versionCode 1
        versionName "1.0"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'com.android.support:appcompat-v7:28.0.0'
    implementation 'com.android.support.constraint:constraint-layout:1.1.3'

    // butterknife için bu satırlar eklenmelidir
    implementation 'com.jakewharton:butterknife:8.8.1'
    annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1'
}

Örnek olarak ekranımıza basit bir buton ekleyelim ve tıklama olayına 1-2 satırlık kod yazalım.

Normalde klasik olarak butonun tıklama eventi için önce butonu findViewById ile bağlıyoruz ve bir Listener kullanarak işlemi yapıyoruz.

Şu anki yapıda, klasik olarak bildiğimiz kod şu şekildedir:

package com.mehmetkirazli.butterknife;

import android.graphics.Color;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {

    Button btnTest;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        btnTest = findViewById(R.id.button);

        btnTest.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Toast.makeText(MainActivity.this, "Butona Basıldı", Toast.LENGTH_SHORT).show();

                // butonun metni ve arka planı değiştirildi
                btnTest.setText("Tıklandı");
                btnTest.setBackgroundColor(Color.RED);
            }
        });
    }
}

Basit olarak bir adet butonumuz var ve tıklandığında mesaj verip, görselle ilgili değişiklikler yaptık.

ButterKnife kullandığımızda ise biraz daha anlaşılabilir ve kısa bir kod yapısı karşımıza çıkıyor. findViewById yerine BindView annotationunu kullanıyoruz. Üzerinde işlem yaptığımız bileşen bir View bileşeni olduğu için BindView yazıyoruz. Drawable dosyası için olsaydı BindDrawable yazacaktık.

Aynı kodu ButterKnife ile yazarsak:

package com.mehmetkirazli.butterknife;

import android.graphics.Color;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.Button;
import android.widget.Toast;

import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // bind işlemi yapıldı
        ButterKnife.bind(this);
    }

    // buton tanımlandı
    @BindView(R.id.button) Button btnTest;

    // click eventi yazıldı
    @OnClick(R.id.button) void tikla() {
        Toast.makeText(this, "Butona Basıldı", Toast.LENGTH_SHORT).show();

        // butonun metni ve arka planı değiştirildi
        btnTest.setText("Tıklandı");
        btnTest.setBackgroundColor(Color.RED);
    }
}

2 YÖNTEMDE DE ORTAK OLAN ÇIKTIMIZ:

Butona tıklamadan önce:

Butona tıklandıktan sonra:

Burada dikkat ettiyseniz şu anki yapıda(findViewById), butonu oluşturma ve tıklama kodlarımızı onCreate() metodu içerisine yazıyoruz. ButterKnife kullandığımızda ise bu kodları onCreate() dışına yazıyoruz.

Aynı şekilde sadece görsel bileşenleri değil de strings.xml, colors.xml gibi dosyalar için tanımlama yaparsak :

@BindDrawable(R.drawable.icon) Drawable icon; // drawable 
@BindString(R.string.age) String yas; // string 
@BindColor(R.color.yellow) int renk; // color

Şeklinde kullanmamız gerekir. Oluşturduğunuz değişken adını da istediğiniz yerde kullanabilirsiniz. Örnek kullanım:

tvBaslik.setTextColor(renk);
imvProfil.setImageDrawable(icon);

Örnekte sadece buton üzerinden gösterdik fakat TextView, EditText gibi bileşenler de tamamen aynı şekilde kullanılır. Bununla ilgili de basit bir örnek verelim.

public class MainActivity extends AppCompatActivity {

    // bileşenler tanımlandı
    @BindView(R.id.btnArttir) Button btnSayiArttir;
    @BindView(R.id.btnAzalt) Button btnSayiAzalt;
    @BindView(R.id.edtSayi) EditText edtSayi;

    @OnClick(R.id.btnArttir)
    void arttir() {
        edtSayi.setText(String.valueOf(Integer.valueOf(edtSayi.getText().toString()) + 1));
    }

    @OnClick(R.id.btnAzalt)
    void azalt() {
        edtSayi.setText(String.valueOf(Integer.valueOf(edtSayi.getText().toString()) - 1));
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        ButterKnife.bind(this);
    }
}

Örneğimizde 2 adet buton kullanarak, EditText içerisine girilen sayıyı arttırıp azaltma işlemi yaptık. İki butonun da tanımlamalarını ve click eventini ayrı ayrı yaptık.

KAYNAK KOD İNDİR

Nasıl Çalışır ?

ButterKnife, Annotation tabanlıdır ve Annotation’lar da CompileTime (derleme zamanında) dikkate alınıp çalıştırılır. Bunu sağlayan yapı Annotation Processor‘dur. Siz de AbstractProcessor sınıfından türetilen(extends) bir Processor ve bunun Binding’lerini yazarsanız, siz de kendinize özel bir ButterKnife benzeri bir kütüphane oluşturabilirsiniz ve açık kaynak olarak kullanıma sunabilirsiniz 🙂 Hazırlanan bu tarz kütüphanelere ViewInjector kütüphanesi denir.

Projeyi derlediğinizde (henüz çalıştırmadan), Annotation’un bulunduğu satırlar, şuan bildiğimiz ve uyguladığımız Java kodlarına(findViewById) dönüştürülür. Bunu sağlayan yapı, kütüphane içindeki Annotation Prosessor‘dür. Hangi bileşenin hangi koda dönüştürüleceği ise bu kütüphanede tanımlanmıştır.

The post Android ButterKnife Kütüphanesi Kullanımı appeared first on Mehmet Kirazlı.

]]>
https://www.mehmetkirazli.com/android-butterknife-kutuphanesi-kullanimi/feed/ 1
Admob TikTok Reklamları Engelleme https://www.mehmetkirazli.com/admob-tiktok-reklamlari-engelleme/ https://www.mehmetkirazli.com/admob-tiktok-reklamlari-engelleme/#comments Wed, 09 Jan 2019 13:35:00 +0000 https://www.mehmetkirazli.com/?p=3111 Merhaba. Bu yazımda artık baş belası olmuş TikTok reklamlarını, Android uygulamalarımızdaki Admob reklamlarından nasıl kaldıracağımızı anlatacağım. Bir gençliğin nasıl çökertilebileceğini bizlere gösteren, çoğu zaman ahlak sınırlarını aşan TikTok uygulamasının, kendi uygulamalarımda reklam olarak gösterildiğini farkettim. Bunu nasıl engelleyebileceğimi araştırdım ve kendimce bulduğum çözümleri derledim. Bu reklamları engellemenin birkaç yolu var. Ben tümünü birden gösterip uygulayacağım. …

The post Admob TikTok Reklamları Engelleme appeared first on Mehmet Kirazlı.

]]>
Merhaba. Bu yazımda artık baş belası olmuş TikTok reklamlarını, Android uygulamalarımızdaki Admob reklamlarından nasıl kaldıracağımızı anlatacağım.

Bir gençliğin nasıl çökertilebileceğini bizlere gösteren, çoğu zaman ahlak sınırlarını aşan TikTok uygulamasının, kendi uygulamalarımda reklam olarak gösterildiğini farkettim. Bunu nasıl engelleyebileceğimi araştırdım ve kendimce bulduğum çözümleri derledim.

Bu reklamları engellemenin birkaç yolu var. Ben tümünü birden gösterip uygulayacağım. Şuan için işe yaramış görünüyor. Şimdi bunları listeleyelim.

Video Engelleme

Aslında en garanti yol budur. Fakat TikTok haricinde gösterilmesini istediğiniz video reklamlar varsa, bu seçenek size göre değil. Ben tüm video reklamlarını bir şekilde sakıncalı bulduğum için bu şekilde ayarlama yaptım. Tercih sizin.

Bunun için ilk olarak Admob panelimize geliyoruz ve soldaki Uygulamalar menüsünden uygulamamızı seçiyoruz ve Reklam Birimleri sekmesini açıyoruz.

Burada uygulamamıza eklediğimiz reklam türleri var. Ben banner ve tam ekran reklamları eklemiştim. İlk olarak Banner seçeneğine tıklayın ve Gelişmiş Ayarlar menüsünden Video seçeneğini aşağıdaki gibi kaldırın.

Geçiş reklamı için:

Bu seçeneği kaldırmak gelirinizi azaltabilir. Çünkü video reklamlar daha çok kazandırır. Fakat videolarda illa ki ahlaken sakıncalı bir reklam geldiği için ben bu şekilde tamamen video reklamları engelledim.

Not: Bu işlemi tüm uygulamalar ve tüm reklam tipleri (Banner, Tam Ekran vs.) için ayrı ayrı yapmalısınız.

Reklam Ağları

Eğer video reklam açık kalsın sadece TikTok reklamları engellensin istiyorsanız başka bir seçeneğiniz var. Bunun için yine Admob panelinden soldaki Engelleme Kontrolleri menüsünü açın ve gelen ekranda Reklam Ağları sekmesine tıklayın.

Arama penceresine “TouTiao” yazın ve arama butonuna basın. Karşınıza gelen sonuçtaki switch’e tıklayın ve bu ağdan gelen reklamları engelleyin.

Not : Bu şekilde yapılan engelleme, admob hesabınızdaki tüm uygulamalar için geçerli olacaktır. Tek tek her biri için ayarlamaya gerek yoktur.

Not 2 : Bu şekilde yapılan engelleme hem video hem de tam ekran reklamı engelleyecektir diye umuyorum. Çünkü TikTok için reklam ağı aynıdır.

Reklam İçeriği Derecelendirme

TouTiao engellemesi yapılsa bile başka kanallardan bu reklamın gelme ihtimaline karşı bir ayar daha yapacağız.

Burada uygulamanızda gösterilecek reklamları, kime hitap ettiğine göre kısıtlayabiliyorsunuz. Eğer en sağdaki “MA” seçiliyse, yaş kısıtlaması olmaksızın her kullanıcıya reklamlarınız gösterilir. Alkol, cinsel içerik vs. türündeki reklamların gösterilme olasılığı fazladır.

Eğer en soldaki “G” seçeneğini işaretlerseniz, aile ve çocuklar için uygun içerikler gösterilir. Bunu seçmenizde fayda var. Google’nin, TikTok videolarını bu kategoride göstermeyeceğini düşünüyorum.

Reklam Veren URL’leri

Url bazında da engelleme yapabilirsiniz. TikTok reklamına tıkladığınızda adres çubuğunda çıkan Url’e kısıtlama koyabilir, bu URL’den verilen reklamları engelleyebilirsiniz.

Uygulama Yükleme Reklamları

En sağlam engellemelerden birisi de budur. Burada uygulama bazında engelleme yapabilirsiniz. Tam ekran verdiğiniz reklamlarda, TikTok yüklemek için Google Play reklamı gösteriliyorsa, buradan engelleme yapılabilir.

Arama çubuğuna TikTok yazıp aşağıdaki gibi karşınıza gelen sonuçlara tıklarsanız, tek tek engelleme yapabilirsiniz.

Uygulamanın Google Play sayfasının reklamını yapılmasını istemediğimiz uygulamalar aşağıda listelenmiştir.

Burada video bazında değil de Google Play’de yapılan reklamlar engellenir.

Reklam İnceleme Merkezi

İçiniz yine de rahat etmediyse son olarak uygulamanızda çıkan tüm reklamları görebildiğiniz Reklam İnceleme Merkezi üzerinden engelleme yapabilirsiniz.

Sağdaki arama kısmında yine TouTiao yazarak, uygulamanızda ne kadar TikTok reklamı hangi tarihlerde gösterilmiş görebiliyorsunuz. Arattığınızda karşınıza reklamlar gelecektir. Reklamın sol altındaki engelleme butonuna tıklayıp engelleme yapabilirsiniz. Ya da aşağıdaki gibi reklamın üzerine tıklayıp detayına gittikten sonra, hem Hesabı Engelle hem de Reklamı Engelle butonu ile reklamı engelleyebilirsiniz.

Reklam Detayı :

Sonuç

Bu TikTok öyle bir illet ki insan nasıl engelleyeceğini şaşırıyor. Bunun için farklı uygulamalar vardır elbet fakat bunu kullanıcı isterse telefonuna yükler ve engelleme yapar. Biz bunu uzaktan ve tüm kullanıcılara uygulamak istediğimiz için bu şekilde yaptık.

Sadece TikTok değil, tüm reklamları bu şekilde engelleyebilir ve gösterilmesini istemediğiniz reklamları kısıtlayabilirsiniz.

Not : Adsense kullanıyorsanız yine bu şekilde Adsense Panelinden engellemeler yapabilirsiniz.

The post Admob TikTok Reklamları Engelleme appeared first on Mehmet Kirazlı.

]]>
https://www.mehmetkirazli.com/admob-tiktok-reklamlari-engelleme/feed/ 2
Google API OVER_QUERY_LIMIT Hatası ve Cloud Hesabı Tanımlama https://www.mehmetkirazli.com/google-api-over_query_limit-hatasi-ve-cloud-hesabi-tanimlama/ https://www.mehmetkirazli.com/google-api-over_query_limit-hatasi-ve-cloud-hesabi-tanimlama/#respond Wed, 09 Jan 2019 06:36:43 +0000 https://www.mehmetkirazli.com/?p=3100 Merhaba. Play Store’ da yüklü olan En Yakın uygulamamda, yakınlardaki mekanları bulma ve rota çizme, yorumları getirme gibi işlemlerde Google’ dan kaynaklı olarak OVER_QUERY_LIMIT hatası aldım. Bu yazımda hatanın çözümünden bahsedeceğim. Eğer Google Map kullanan bir uygulamanız varsa ve bu uygulamada, konumunuza yakın yerleri bulmak, sokak görünümüne geçmek, rota çizmek, yorumları almak gibi işlemler yapıyorsanız …

The post Google API OVER_QUERY_LIMIT Hatası ve Cloud Hesabı Tanımlama appeared first on Mehmet Kirazlı.

]]>
Merhaba. Play Store’ da yüklü olan En Yakın uygulamamda, yakınlardaki mekanları bulma ve rota çizme, yorumları getirme gibi işlemlerde Google’ dan kaynaklı olarak OVER_QUERY_LIMIT hatası aldım. Bu yazımda hatanın çözümünden bahsedeceğim.

Eğer Google Map kullanan bir uygulamanız varsa ve bu uygulamada, konumunuza yakın yerleri bulmak, sokak görünümüne geçmek, rota çizmek, yorumları almak gibi işlemler yapıyorsanız bir Google API Key gerekir. Bunu kullananlar bilir. Birkaç ay önce Google, Cloud Platform‘a geçtiği için elinizdeki API key ile bu işlemleri yalnızca 1 defa yapabiliyorsunuz. Sonrasında ise OVER_QUERY_LIMIT hatası alırsınız ve API çalışmaz. Ancak bir müddet sonra denediğinizde tekrar 1 defalığına çalışır.

Uzun uğraşlar ve araştırmalar sonucunda sebebin, Google Cloud Platform‘da bir fatura hesabının açılması gerektiğini öğrendim. Fatura hesabı açtığınızda 1 yıllık 300$ değerinde kredi veriliyor. 1 sene sonunda isterseniz ücretli kullanıma devam edebiliyorsunuz. Elinizdeki API key’ i değiştirmeniz gerekmiyor. Böylece OVER_QUERY_LIMIT hatasını artık almamış oluyorsunuz.

Google Cloud Fatura Hesabı Tanımlama

Bunun için öncelikle bir gmail adresinizin olması gerekiyor. Bu adresten platformu ücretsiz denemeye başlayabilirsiniz.

Kabul ettikten sonra açılan sayfada kullanıcı ve adres bilgilerini girerek son olarak kredi kartı bilgileri de girmeniz gerekiyor.

Kart tanımlaması yaparken banka kartı ekleme çalıştım fakat “Bu kart bilgilerini düzeltin veya farklı bir kart deneyin” hatası (OR-CCSEH-05) aldım. Bunun için de bir müddet çözüm aradım. Acaba adres mi yanlış yoksa 3D ödemeyi mi kapatmak gerekiyor vs. diye. Sonunda çözümü buldum. Kart tanımı yaparken KREDİ KARTI olması gerekiyor ve SANAL KART ile tanımlama yapılmalı. Sanal kart olmadan doğrudan kredi kartı ile olur mu bilmiyorum. Sonuç olarak kredi kartı özelliği olmayan kartlarda kesinlikle olmuyor. Olayın 3D veya kartı yurt dışına açma ile de alakası yok.

Kart bilgilerini de doğru girdikten sonra Google Cloud Platformuna giriş yapabilirsiniz ve artık API Key’iniz çalışacaktır. Fakat senelik 300$ kotanız olduğu için uygulamanızda kısıtlama koymalısınız. Herkes istediği kadar istek göndermemeli ve kota hızlıca dolmamalı.

The post Google API OVER_QUERY_LIMIT Hatası ve Cloud Hesabı Tanımlama appeared first on Mehmet Kirazlı.

]]>
https://www.mehmetkirazli.com/google-api-over_query_limit-hatasi-ve-cloud-hesabi-tanimlama/feed/ 0
Uygulamanın Play Store’da Tabletler için Görünmemesi https://www.mehmetkirazli.com/uygulamanin-play-storeda-tabletler-icin-gorunmemesi/ https://www.mehmetkirazli.com/uygulamanin-play-storeda-tabletler-icin-gorunmemesi/#comments Mon, 31 Dec 2018 13:40:53 +0000 https://www.mehmetkirazli.com/?p=3094 Merhaba. Geliştirdiğiniz bir uygulamayı Play Store’a attıktan sonra uygulamanızı bir tabletten arattığınızda göremiyorsanız bunun birkaç çözümü vardır. Normalde geliştirdiğiniz bir uygulama tabletler için de uyumlu olsun, markette tabletler tarafından aratıldığında sonuçlarda çıksın isteniliyorsa, yapılması gereken belli başlı şeyler vardır. 1 – Google Play Console’da Mağaza Girişi ekranında, 7 ve 10 inç tabletler için de ekran …

The post Uygulamanın Play Store’da Tabletler için Görünmemesi appeared first on Mehmet Kirazlı.

]]>
Merhaba. Geliştirdiğiniz bir uygulamayı Play Store’a attıktan sonra uygulamanızı bir tabletten arattığınızda göremiyorsanız bunun birkaç çözümü vardır.

Normalde geliştirdiğiniz bir uygulama tabletler için de uyumlu olsun, markette tabletler tarafından aratıldığında sonuçlarda çıksın isteniliyorsa, yapılması gereken belli başlı şeyler vardır.

1 – Google Play Console’da Mağaza Girişi ekranında, 7 ve 10 inç tabletler için de ekran görüntüsü eklenir

2 – Uygulamanın manifest dosyasına aşağıdaki kod eklenir.

<supports-screens
        android:anyDensity="true"
        android:largeScreens="true"
        android:normalScreens="true"
        android:resizeable="true"
        android:smallScreens="true"
        android:xlargeScreens="true" />

3 – Uygulamanızın “res” klasörü altındaki “drawable” dosyaları, 4 farklı ekran çözünürlüğü için ayrı ayrı oluşturulur ve ilgili resim dosyaları boyutlandırılarak bu klasörlere atılır

Bunları yaptığınız halde uygulamanız telefonlarda aratıldığında markette arama sonuçlarında çıkıyor fakat tabletlerde arattığınızda çıkmıyorsa son olarak yapmanız gereken şudur.

Çözüm

Uygulamanızın Manifest dosyasında izinler eklediğinizi düşünelim. Örnek olarak:

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

Uygulamanız bu izne bakarak, uygulama içinden telefon aramasına izin verecektir. Fakat … !!!

Bir tablette telefonla arama özelliği olmadığı zaman uygulamanız markette arama sonuçlarında çıkmaz. Sim kart destekli bir tablet olması gerekir. Çoğu tablet de bunu desteklemez.

Başka bir örnek verirsek:

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

Konum alma izni verdiğinizde, tabletinizde Gps modülü DONANIMSAL olarak mevcut olmadığında yine arama sonuçlarında uygulamanız çıkmaz. (Tabletler için)

Çözüm olarak, bu 2 izni verdiğinizi var sayarsak aşağıdaki kod bloğunu da AndroidManifest.xml dosyanıza eklemeniz gerekir.

<uses-feature android:name="android.hardware.telephony" android:required="false" tools:node="replace" />
    <uses-feature android:name="android.hardware.location.gps" android:required="false" tools:node="replace" />

android:required özelliğinde, cihazda bu modülün olma mecburiyeti yoktur deriz. Hardware yani donanım özelliklerinde Gps ya da telefonla arama modülleri olmasa bile Play Store’ da arama sonuçlarında çıksın diyebiliriz.

Bu kod bloğu olmadığı zaman, donanımsal olarak bazı istenen özellikleri olmayan cihazları Google Play filtreler ve uygulamayı, bu cihazlar üzerinden yapılan arama sonuçlarında göstermez.

Not : Eğer donanımsal olarak ihtiyaç olmayan internet, okuma yazma gibi işlemler için bu eklemeleri yapmanız gerekmez.

Kendi uygulamamda böyle bir sorunla karşılaştığım için kendime de not düşmek amacıyla bu yazıyı yazdım. Umarım sorununuzu çözmüştür.

The post Uygulamanın Play Store’da Tabletler için Görünmemesi appeared first on Mehmet Kirazlı.

]]>
https://www.mehmetkirazli.com/uygulamanin-play-storeda-tabletler-icin-gorunmemesi/feed/ 1
Android 6.0 (Marshmallow) İzin Ayarları – Runtime Permissions https://www.mehmetkirazli.com/android-6-0-marshmallow-izin-ayarlari/ https://www.mehmetkirazli.com/android-6-0-marshmallow-izin-ayarlari/#comments Mon, 24 Dec 2018 14:00:05 +0000 https://www.mehmetkirazli.com/?p=3072 Merhaba. Şuan 9.0 versiyonu çıkmış olsa da Android 6.0 (Marshmallow)’da gelen ve birçok uygulamanın hata vermesine sebep olan bir yenilikten bahsedeceğim. Android 6.0 (Marshmallow) öncesinde, Google Play’ den uygulama indirirken izinler, indirme esnasında toptan kabul ediliyordu ve bunların arasından erişmesini istemediğimiz izinleri iptal etme gibi bir lüksümüz yoktu. Başta kabul edildiğinde artık izinler kaldırılamıyordu. 4.4.2 …

The post Android 6.0 (Marshmallow) İzin Ayarları – Runtime Permissions appeared first on Mehmet Kirazlı.

]]>
Merhaba. Şuan 9.0 versiyonu çıkmış olsa da Android 6.0 (Marshmallow)’da gelen ve birçok uygulamanın hata vermesine sebep olan bir yenilikten bahsedeceğim.

Android 6.0 (Marshmallow) öncesinde, Google Play’ den uygulama indirirken izinler, indirme esnasında toptan kabul ediliyordu ve bunların arasından erişmesini istemediğimiz izinleri iptal etme gibi bir lüksümüz yoktu. Başta kabul edildiğinde artık izinler kaldırılamıyordu.

4.4.2 versiyonlu bir cihazda, indirilmiş bir uygulamanın izinleri:

Versiyonu 6.0 ve üzeri olan cihazlarda ise artık uygulamayı indirirken değil uygulama açıkken, ihtiyaç olduğu sürece izin isteniyor ve dilerseniz izin vermeyebiliyorsunuz.

Mesela indirdiğiniz bir uygulama kameranızı açmak istiyor diyelim. O an bir uyarı penceresi ile uygulamanın kameranıza erişmek istediği söyleniyor. İzin verirseniz kamera açılıyor, vermezseniz açılmıyor. İzin vermediğinizde uygulama tam olarak işlevini görmüyor fakat en azından hangi izne nerede ve niçin erişmek istediğini bilebiliyorsunuz ve tüm izinleri, 6.0’dan önceki gibi peşinen kabul etmemiş oluyorsunuz. 6.0 altındaki cihazlarda ise uygulama içinde izin pencereleri açılmaz. Uygulamayı indirirken verdiğiniz izinler uygulama boyunca kullanılır.

Android 6.0 İzin İşlemi – Örnek

Örnek üzerinde gösterelim. Örneğimizde butona tıklandığında kameranın açılmasını isteyelim. Cihazın API versiyonu 23 ve üzeriyse (Android 6.0’a denk gelir) izin istesin. Değilse, izinsiz doğrudan kamera açsın.

AndroidManifest.xml dosyamıza ilk olarak kamera izni ekleyelim.

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

Daha sonra activity_main.xml layout dosyasına bir buton ekleyelim.

<?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"
    tools:context=".MainActivity">

    <Button
        android:id="@+id/btnKameraAc"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:text="Kamera Aç" />
    
</RelativeLayout>

Şimdi ise bu tasarıma bağlı olan MainActivity.java dosyasına gelerek, butonun click eventini dolduralım.

public class MainActivity extends AppCompatActivity {
    Button btnKameraAc;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        btnKameraAc = findViewById(R.id.btnKameraAc);
        btnKameraAc.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                // Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
                if (Build.VERSION.SDK_INT >= 23) {
                    String[] KAMERA_IZNI = {Manifest.permission.CAMERA};
                    if (!izinKontrol(MainActivity.this, KAMERA_IZNI)) { // izin verilmiş mi
                        requestPermissions(KAMERA_IZNI, 100); // verilmediyse, izin isteme penceresi aç
                    } else
                        kameraAc(); // zaten izin verilmişse kamera aç
                } else
                    kameraAc(); // api 6.0 altındaysa izne bakmadan doğrudan kamera aç
            }
        });
    }
}

Kamera açan bir uygulamanız var ve butona basıldığında ya da herhangi bir işlemden sonra doğrudan kamera açmak istiyorsunuz. Yukarıdaki gibi kontrol koymanız gerekiyor. Cihazın Android versiyonu 6.0 altında ise doğrudan kamera açılır. 6.0 ve üzeri ise önce izin verilmiş mi bakılır. İzin verilmemişse izin istenir (16.satırdaki ünlem işaretine dikkat!!). Verilmişse yine doğrudan kamera açılır.

Burada izin isterken 100 değeri gönderdik. Aşağıdaki gibi bir izin penceresi açıldı.

Bu izin penceresinde bir seçeneğe tıklayacağız. Tıkladıktan sonra istek gönderirken verdiğimiz 100 değeri ile yanıtımızı handle edeceğiz. Handle yani kontrol etmek için ise onRequestPermissionsResult metodu kullanılır. 100 yerine herhangi bir sayı veya sabit verilebilir.

@Override
    public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
        switch (requestCode) {
            case 100:
                if (grantResults.length > 0) {
                    boolean kameraIzniVerildiMi = grantResults[0] == PackageManager.PERMISSION_GRANTED;
                    if (kameraIzniVerildiMi) {
                        kameraAc();
                    } else {
                        Toast.makeText(getApplicationContext(), "İzin verilmediği için kamera açılamıyor", Toast.LENGTH_SHORT).show();
                    }
                } else {
                    Toast.makeText(getApplicationContext(), "İzin verilmediği için kamera açılamıyor", Toast.LENGTH_SHORT).show();
                }
                break;
        }
    }

Pencerede Reddet veya İzin Ver butonlarından birine tıklayınca onRequestPermissionsResult metodu çalışır. Metod içerisinde, önce kamera iznine ait olan 100 değeri switch içerisine yazılır. İzin verildiyse yine kameraAc() metodu çağrılır. Verilmediyse ekrana uyarı mesajları verilir.

ÖNEMLİ!!!

Eğer bir sefer izin verirsek, 2.tıklamada artık requestPermissions() metodu çağrılmayacak doğrudan kamera açılacaktır. Çünkü izin verilmediyse izin isteği gönderiyorduk. İzin verildikten sonra kişi eğer huylanır da cihazın Ayarlar sekmesinden uygulama izinlerini manuel olarak iptal ederse, uygulamaya girip butona tıkladığında tekrar requestPermissions() metodu çağrılır. O yüzden her tıklamada izin verilmiş mi kontrolü yapılmalı yoksa uygulama hata vererek durur.

Aşağıdaki gibi kişinin manuel olarak izinleri kapatma ihtimali vardır.

Dikkat ettiyseniz değinmediğimiz bir metot var. O da izinKontrol() metodu. Bu metot şu işe yarar:

-Bu uygulama için istenilen izinler kullanıcı tarafından verilmiş mi ?

Bu metot, aynı anda birden fazla izin alacağımız durumlarda işimize yarayacaktır. Tek izin için de işimizi görür. Hemen o metodu da yazalım.

public static boolean izinKontrol(Context context, String... izinler) {
        if (context != null && izinler != null) {
            for (String izin : izinler) {
                if (ActivityCompat.checkSelfPermission(context, izin) != PackageManager.PERMISSION_GRANTED)
                    return false;
            }
        }
        return true;
    }

Aynı Ekranda 2.İzni İsteme

Örneğimizde 1 adet izin istedik. Şimdi ise aynı activity içinde 2.buton ekleyip, bu buton ile de cihazın konumunu alalım.

<?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"
    tools:context=".MainActivity">

    <Button
        android:id="@+id/btnKameraAc"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:text="Kamera Aç" />

    <Button
        android:id="@+id/btnKonumAl"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/btnKameraAc"
        android:text="Konum Al" />

</RelativeLayout>

Manifest dosyamıza izinleri de ekleyelim.

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

    <uses-permission android:name="android.permission.CAMERA" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

    <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">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

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

</manifest>

MainActivity.java dosyasına, konum alma butonu için click eventi oluşturalım.

btnKonumAl = findViewById(R.id.btnKonumAl);
        btnKonumAl.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                // Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
                if (Build.VERSION.SDK_INT >= 23) {
                    String[] KONUM_IZNI = {Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION};
                    if (!izinKontrol(MainActivity.this, KONUM_IZNI)) { // izin verilmiş mi
                        requestPermissions(KONUM_IZNI, 200); // verilmediyse, izin isteme penceresi aç
                    } else
                        konumAl(); // zaten izin verilmişse konum al
                } else
                    konumAl(); // api 6.0 altındaysa izne bakmadan doğrudan konum al
            }
        });

Cihazlarda 2 tür konum olduğu için 2 tür izin istemek zorundayız. İzin isterken bu defa 100 değil 200 değeri gönderdik ve aşağıdaki onRequestPermissionsResult() metodunda da 200 için ayrı bir case oluşturarak, konum izni verildiğinde yapılacakları yazdık.

@Override
    public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
        switch (requestCode) {
            case 100:
                if (grantResults.length > 0) {
                    boolean kameraIzniVerildiMi = grantResults[0] == PackageManager.PERMISSION_GRANTED;
                    if (kameraIzniVerildiMi) {
                        kameraAc();
                    } else {
                        Toast.makeText(getApplicationContext(), "İzin verilmediği için devam edilemiyor", Toast.LENGTH_SHORT).show();
                    }
                } else {
                    Toast.makeText(getApplicationContext(), "İzin verilmediği için devam edilemiyor", Toast.LENGTH_SHORT).show();
                }
                break;

            case 200:
                if (grantResults.length > 0) {
                    boolean konumIzniVerildiMi1 = grantResults[0] == PackageManager.PERMISSION_GRANTED;
                    boolean konumIzniVerildiMi2 = grantResults[1] == PackageManager.PERMISSION_GRANTED;
                    if (konumIzniVerildiMi1 && konumIzniVerildiMi2) {
                        konumAl();
                    } else {
                        Toast.makeText(getApplicationContext(), "İzin verilmediği için konum alınamıyor", Toast.LENGTH_SHORT).show();
                        finish();
                    }
                } else {
                    Toast.makeText(getApplicationContext(), "İzin verilmediği için konum alınamıyor", Toast.LENGTH_SHORT).show();
                    finish();
                }
                break;
        }
    }

Buradaki grantResults[0] ve grantResults[1] içerisinde, lokasyon için istediğimiz izinler vardır. İlkinde ACCESS_COARSE_LOCATION, ikincisinde de ACCESS_FINE_LOCATION izni için bilgiler bulunmaktadır. Yani izin verildi mi bilgisi tutulur.

Sonuç olarak eğer izin gerektiren bir işlem yaptırmak istiyorsak, hem cihaz için API 23 kontrolü yapmalıyız hem de izin verilmediyse izin penceresi açarak, seçilen seçeneğe göre aynı işlemleri orada da yapmalıyız. Yani her tıklamada ve izin penceresi açıldığı her durumda…

Son olarak şunu da söyleyelim. Android SDK’sı, tehlikeli bulduğu izinler için bu işlemi yapar. Yani bir internet ve bluetooth açma işlemi için API 23 kontrolüne gerek yoktur. Sadece AndroidManifest.xml dosyasına izin eklenir ve kodda doğrudan işlem yapılır. Dosya okuma yazma, kamera açma, mikrofon açma, konum alma gibi işlemler için kullanıcıdan izin isteme mecburiyeti vardır. Bu yaptıklarımız da tehlikeli olan izinler içindir.

Tehlikeli ve normal izinlerin listesine buradan ulaşabilirsiniz.

KAYNAK KODLARI İNDİR

The post Android 6.0 (Marshmallow) İzin Ayarları – Runtime Permissions appeared first on Mehmet Kirazlı.

]]>
https://www.mehmetkirazli.com/android-6-0-marshmallow-izin-ayarlari/feed/ 5
Android Oreo (8.0) Resim Ekleme Sorununun Çözümü https://www.mehmetkirazli.com/android-oreo-8-0-resim-ekleme-sorunu/ https://www.mehmetkirazli.com/android-oreo-8-0-resim-ekleme-sorunu/#comments Mon, 24 Dec 2018 07:45:16 +0000 https://www.mehmetkirazli.com/?p=3058 Merhaba. Hazırladığım bir uygulamada Android Oreo (8.0) ve üzeri cihazlarda kameradan ya da galeriden resim eklemeye çalışıldığında hata alındığını farkettim. API 26 ve üzerinde alınan hatanın çözümünü anlatacağım. Öncelikle hata alınan örnek bir kod bloğu gösterelim. [crayon-660528c33785b147212963/] Bu kod aşağıdaki gibi bir hata verecektir [crayon-660528c337867953172209/] Burada Uri.fromFile() metodu hata verecektir ve eğer Try-Catch mekanizmanız yoksa …

The post Android Oreo (8.0) Resim Ekleme Sorununun Çözümü appeared first on Mehmet Kirazlı.

]]>
Merhaba. Hazırladığım bir uygulamada Android Oreo (8.0) ve üzeri cihazlarda kameradan ya da galeriden resim eklemeye çalışıldığında hata alındığını farkettim. API 26 ve üzerinde alınan hatanın çözümünü anlatacağım.

Öncelikle hata alınan örnek bir kod bloğu gösterelim.

Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
File photo = new File(Environment.getExternalStorageDirectory(),
      "/DCIM/Camera/" + timeStamp + ".jpg");
SingletonClass.setimageUri(Uri.fromFile(photo));
intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(photo));
Uri imageUri = Uri.fromFile(photo);
startActivityForResult(intent, CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE);

Bu kod aşağıdaki gibi bir hata verecektir

android.os.FileUriExposedException: file:///storage/emulated/0/DCIM/Camera/beyan.jpg exposed beyond app through ClipData.Item.getUri()

Burada Uri.fromFile() metodu hata verecektir ve eğer Try-Catch mekanizmanız yoksa resim eklerken uygulama durdurulacaktır.

Çözümü için ilk olarak 6.satırı aşağıdaki gibi satırı güncelliyoruz.

Uri imageUri = FileProvider.getUriForFile(MyActivity.this, BuildConfig.APPLICATION_ID + ".provider",photo);

Daha sonra AndroidManifest dosyamızın en altına application etiketinden hemen önce şu satırları ekliyoruz.

<provider
    android:name="android.support.v4.content.FileProvider"
    android:authorities="${applicationId}.provider"
    android:exported="false"
    android:grantUriPermissions="true">
    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/provider_paths"/>
</provider>

Daha sonra res klasörü altında xml adında bir klasör oluşturup bu klasörün içine de provider_paths adında bir xml dosyası oluşturarak içerisine şu kodları yazıyoruz.

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path
    name="storage/emulated/0"
    path="." />
</paths>

Son olarak bu işlemleri yaptığınız class içerisineki setContentView() metodundan sonra aşağıdaki kodları yazıyoruz.

StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();
StrictMode.setVmPolicy(builder.build());

The post Android Oreo (8.0) Resim Ekleme Sorununun Çözümü appeared first on Mehmet Kirazlı.

]]>
https://www.mehmetkirazli.com/android-oreo-8-0-resim-ekleme-sorunu/feed/ 1