Android Studio’da Debug Püf Noktaları

Yazılım geliştiriciler, projenin hatalarını gidermek, uygulama işleyişini anlamak ve takip etmek için debug yöntemlerini sıkça kullanmaktadır.

Bu makalemde, Android Studio Ide’sinde  debug (hata ayıklama) yapma süreçlerini hızlandıran püf noktaları anlatacağım.

Android uygulama geliştirme sürecinde kullanılan 2 tip debug yöntemi bulunmaktadır.

  1. Log sınıfını kullanarak, Logcat penceresinde hata ayıklama
  2. Projenin debug modda çalıştırmasıyla, Debug penceresinde hata ayıklama

Log Kullanımı 

Projede Log sınıfını kullanarak, Logcat penceresinde kodlarımızı aşama aşama takip edebilir ya da yaptığımız işlemler sonucunda ortaya çıkan değerleri kontrol edebiliriz.

Örneğin, saniyedeki frame hızını ve her oyunda kullanıcının son puanını kaydeden bir uygulamanızın olduğunu varsayalım. Bu uygulamada, her oyunda kullanıcının son puanını, Logcat penceresinde kontrol etmek istediğinizde aşağıdaki gibi Log sınıfını kullanmalıyız.

Log.w("points","Sending" +pointV +" points to the High Score Server");

Android Studio Ide’sinin Logcat tabını seçtiğimizde, yazdığımız Log tanımlaması aşağıdaki gibi gözükecektir.

Şekil-1

Log Filtreleme Özellikleri

Üsteki görünüm en temel halidir. Şimdi ise bu log ile görüntülediğimiz verilerimize daha hızlı ulaşabilmek için nasıl Logcat ekranını sadeleştireceğimize bakalım.

Şekil-1 görselinde işlem tarihi, paket ismi ve thread ID gibi kullanmıyacağımız ve gözümüzü yoran bilgiler bulunmaktadır. Bunları istersek, görünümden kaldırabiliriz. Bu işlemi Şekil-2 resminde kırmızı belirtiğim ayar sekmesinden Configure Logcat Header bölümünü açıp, bilgilerin seçme alanlarını pasif yaparak çözebilirsiniz.

Şekil-2

Aşağıdaki resimde göründüğü gibi, artık daha temiz log çıktısı gösterebiliyoruz.

Log’ları filtreleme konusuyla ilgili güzel bir özellik daha bulunmaktadır. Şekil-3 görselinde kırmızı ile belirtiğim arama alanına, log sınıfını kullanırken yazdığınız tag ya da msg parametresindeki değerlerden birini yazarsanız, istediğiniz log dataları gelicek. Böylelikle direk istediğiniz log çıktılarını görmüş olacaksınız. Ben Şekil-3 görselinde, “High” kelimesi içeren log’ları arattım.

Şekil-3

LogCat’de Benzer Satırları Gruplama

LogCat penceresindeki veri karmaşıklığını çözmenin diğer bir yolu, projemizde benzer log çıktılarını gruplama yapmaktır. Bu olayı uygulamak için, gruplama yapmak istediğiniz satıra sağ tıklayıp, Fold Lines Like This özelliğiniz seçmeniz yeterli olacak. (Şekil-4)

Şekil-4

Fold Lines Like This özelliğini uygulamadığımızda Şekil-5 resminde olduğu gibi “frame seconds” kelimesini içeren satırları grupladı. Bir grup açık halini de resimde belirttim.

Şekil-5

Hata Ayıklayıcıyı (Debug) Ekleme

Android Studio’da bu butona tıkladığımızda, proje çalışır ve debug penceresi açılır. Bu yöntemle debug yaptığınızda, her seferinde proje yeniden başlatılacaktır. Bu durum zaman kaybına sebep olur.Eğer Attach Debugger to Android Process (Şekil-6) bu özelliği kullanırsanız böyle bir sorununuz kalmayacaktır. Çünkü uygulamanızı 1 kere çalıştırıp, Attach Debugger to Android Process butonu (Şekil-6) ile debug yaparsanız, yeniden başlamayacaktır. Olduğunuz sayfadan debug işlemine devam edebilirsiniz.

Şekil-6

Attach Debugger to Android Process butonu seçtiğinizde Choose Process penceresi açılır. Bu pencerede, debug çalıştırmak istediğiniz  projenin paketini seçip OK tuşuna basınız. Eklediğiniz debug noktalar (breakpoints) arasında geçişi sağlayabilirsiniz. Breakpoints arasında geçişi kolaylaştıran klavye kısayollarını bu linkden ulaşabilirsiniz. Örneğin; Windows da F9 .

Breakpoints Yer Değiştirme

Breakpoints noktalarına uygunsuz bir yere koyduğunuzda, silmek yerine farklı noktalara da yerleştirebilirsiniz.

moving-breakpoints

Breakpoints Grup Yapma

Projede Debug yaparken bir çok breakpoints ekleyebiliyoruz. Fakat breakpoint’leri tek tek silmek ya da pasif yapmak çok zor bir işdir. Tek tek uğraşmaktansa,  Breakpoint’leri gruplarsak, topluca silme, pasif yapma vb. işlemleri hızlıca yapabilme imkanımız bulunmaktadır. Bunu yapabilmek için, herhangi breakpoint sağ tıklayıp, açılan pencerede More seçmeniz gerekir.

Drop frame

Debug yaparken sırayla konulan tüm breakpoint’leri üzerinden testlerimizi yaparız. Fakat bazen bir sonraki adıma geçmek istemediğimiz zamanlarda, yanlışlıkla geçiş yapabiliyoruz. Bu durumda asıl çalıştırmak istediğiniz breakpoint’e tekrar gelebilmek için debug adımlarını en baştan başlatmak gerekiyor. Bu yazılımcıyı yoran bir süreçtir.

Android 10 ve üst sürümlerdeki cihazlarda debug yaparken Drop frame butonuna (Şekil-8) tıklayarak, bir önceki breakpoint noktasına geçiş yapabiliyorsunuz. Böylelikle debug adımlarını en baştan başlatma sorununuz basit bir şekilde çözülmüş oluyor.

Şekil-8

Suspend thread

Çok iş parçacıklı bir uygulamada hata ayıklıyorsanız, breakpoints’in varsayılan olarak tüm iş parçacıklarını askıya aldığını göreceksiniz. Ancak, bu davranışı istemeyebilirsiniz. Örneğin, bir iş parçacığını engelleyebileceğinizi ve uygulamanızın geri kalanının hala çalıştığını doğrulamak veya bir arka plan görevini araştırırken kullanıcı arayüzünüzün işlemeye devam etmesini istiyorsunuz.

Hangi iş parçacağını askıya almak istiyorsanız, o noktaya koyduğunuz breakpoint’e sağ tıklama yapın ve Şekil-9 gibi  Suspend ve Thread bölümlerini seçip, Done butonuna tıklayın.

Şekil-9

Evaluate expression

Bazen debug satırı, Breakpoint üzerindeyken ilgili değişkenin değerini kontrol edip, öğrenmek isteyebilirsiniz. Devamında diğer Breakpoint’leri normal akış da çalıştırmak istediğiniz durumlar olabilir.

Proje kodlarken bu yapıları kullandığınızda, test süreçlerinizin daha hızlanacağını düşünüyorum.

Kaynaklar

1- Android Studio: Debugging Tips n’ Tricks (Android Dev Summit ’19)

2- https://medium.com/androiddevelopers/debugging-in-android-studio-dfbbf8a8d03c

Android’de Directions API ile Rota Çizme

Günümüzde konum bilgisi kullanarak hayatımızı birçok alanda kolaylaştırması sağlayan yazılımlar bulunmaktadır. Mobil uygulamalarda GPS, araba kullanırken ya da yaya olarak yürürken, ulaşmak istediğimiz noktaya gidebilmek için yol tarifi yapması, bulunduğunuz konum çevresinde en yakın eczaneye ulaşmak gibi birçok konuda hayatımızı kolaylaştırmaktadır.

Bu makalemde, bir Android uygulamasında Google Directions API ‘yi kullanarak haritada belirlenen iki nokta arasında nasıl bir rota çizileceğini ve bu rotaya ne kadar sürede varılacağını göstereceğim.

Örnek projemizi kodlamaya başlamadan önce bazı işlemler yapmamız gerekmektedir.Bu işlemleri sırayla yapmaya başlayalım.

1- Google Play Services Yükleme

Google haritayla ilgili bir geliştirme yapacağımızdan dolayı, Google Play Services yüklememiz gerekmektedir. Bunun için Tools->Sdk manager’ı açıp Sdk Tools bölümünden Google Play Services işaretleyip, yükleme işlemini gerçekleştirin.

2- Google Maps API Key Oluşturma

3-Gerekli Kütüphanelerin Eklenmesi

Android Studio Ide ile oluşturduğum projemin app dizinin altındaki build.gradle dosyasını açıyoruz. Dependencies kod bloklarının arasına aşağıdaki kodları yerleştirerek Google Play services kütüphanesini yüklüyoruz.

implementation 'com.google.android.gms:play-services-maps:17.0.0'

4-AndroidManifest Dosyasına İlgili Ayarları Ekleme

Kullanıcının konumu belirlemek için izin tanımlamamız gerekir. Aşağıdaki izin kodunu da AndroidManifest.xml dosyasında application tag’nin üst kısmına yerleştirin.

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

AndroidManifest dosyasına, daha önce üretmiş olduğumuz Google API Key’i ekleme işlemini yapacağız. Application tag arasına aşağıda görmüş olduğunuz meta-data tag kodunun içindeki value özelliğine Google API Key’i ekleyeniz.

<meta-data android:name="com.google.android.geo.API_KEY"
   android:value="AIzaSyBconZdqpSflHNcs6t-btfk0Rlo1Lex7wo" />

5-Xml Kodları

Haritayı gösterebilmek için SupportMapFragment sınıfını fragment ile kullanıyoruz.

<?xml version="1.0" encoding="utf-8"?>
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:map="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/map"
    android:name="com.google.android.gms.maps.SupportMapFragment"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

4-Java Kodları

İlgili rotayı çizebilmek için ilk önce Google Map Directions web servisine API Key, başlangıç ve varış noktalarının konum bilgilerini bir url ile göndermeniz gerekir. İlgili url ile web servise bağlandığınızda, rotayı ne kadar sürede bitirebileceğiniz, rotanın kaç km olduğu, yol tarifleri hakkında detaylı bilgiler json verisi halinde gelecektir. Bu kısmı ve rotanın harita çizilmesi MainActivity sınıfında yapılmıştır. Detaylı anlatım kodlarda bulunmaktadır.

import androidx.fragment.app.FragmentActivity;
import android.content.SharedPreferences;
import android.graphics.Color;
import android.os.*;
import android.preference.PreferenceManager;
import android.widget.Toast;
import com.google.android.gms.maps.*;
import com.google.android.gms.maps.model.*;
import org.json.JSONObject;
import java.io.*;
import java.net.*;
import java.util.*;

public class MainActivity extends FragmentActivity implements OnMapReadyCallback {

    private GoogleMap mMap;
    private LatLng mOrigin;
    private LatLng mDestination;
    private Polyline mPolyline;
    ArrayList<LatLng> mMarkerPoints;

    @Override
    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // SupportMapFragment ile haritayı yükleyeceğimiz arayüz elemanını tanımlıyoruz
        SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
                .findFragmentById(R.id.map);

        mapFragment.getMapAsync(this);

        mMarkerPoints = new ArrayList<>();
    }
    //Harita üzerinde yolun başlangıç ve bitiş noktasını imleçler ile işaretleyerek seçme
    @Override
    public void onMapReady(GoogleMap googleMap) {
        mMap = googleMap;
        mMap.setOnMapClickListener(new GoogleMap.OnMapClickListener() {
            @Override
            public void onMapClick(LatLng point) {
                // Her lokasyon yolunu çizme işleminden sonra yeni yol çizimi için harita refresh yapılıyor
                if(mMarkerPoints.size()>1){
                    mMarkerPoints.clear();
                    mMap.clear();
                }
                mMarkerPoints.add(point);

                //İmleçleri oluşturan sınıfı tanımladık
                MarkerOptions options = new MarkerOptions();
                //İmleci, haritada belirtilen noktalara eklenmesi için ilgili yerin değerini atadık
                options.position(point);
                //DirectionsJSONParser sınıfında, yol süresi değerini SharedPreferences ile taşıyıp
                // imleçde gösterdik
                SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(MainActivity.this);
                options.title("Duration: " +preferences.getString("duration", null));

                /**
                 * İmleçlerin görsellerini belirleme, Başlangıç imlecini yeşil
                 * lokasyonu bitişini belirten imleç ise kırmızı olarak belirledim
                 */
                if(mMarkerPoints.size()==1){
                    options.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_GREEN));
                }else if(mMarkerPoints.size()==2){
                    options.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_RED));
                }

                // Haritada marker(imleç) ekleniyor
                mMap.addMarker(options);

                // Google Directions web servis urlsini hazırlayan ve web servisi kullanan metodu çağırdık
                if(mMarkerPoints.size() >= 2){
                    mOrigin = mMarkerPoints.get(0);
                    mDestination = mMarkerPoints.get(1);
                    drawRoute();
                }

            }
        });
    }
    // Google Directions API den konum datalarını kullanabilmek için web servis ile
    //bağlantı kuracağımız url hazırlayan metodu çağırdık ve web servisi çalıştırdık
    private void drawRoute(){
        String url = getDirectionsUrl(mOrigin, mDestination);

        DownloadTask downloadTask = new DownloadTask();
        downloadTask.execute(url);
    }

    //Haritada belirttiğiniz başlangeç ve bitiş imleçlerinin koordinatlarını API Key ile kullanarak
    //çizilecek düzergah ile ilgili bilgileri elde etmek adına url olusturan metod
    private String getDirectionsUrl(LatLng origin,LatLng dest){

        String str_origin = "origin="+origin.latitude+","+origin.longitude;
        String str_dest = "destination="+dest.latitude+","+dest.longitude;

        // API Key parametre olarak hazırlama
        String key = "key=" +"AIzaSyBconZdqpSflHNcs6t-btfk0Rlo1Lex7wo";

        String parameters = str_origin+"&"+str_dest+"&"+key;
        String output = "json";

        // Oluşturduğumuz parametreleri kullanarak url yi oluşturuyoruz
        String url = "https://maps.googleapis.com/maps/api/directions/"+output+"?"+parameters;
        return url;
    }

    private String downloadUrl(String strUrl) throws IOException {
        String data = "";
        InputStream iStream = null;
        HttpURLConnection urlConnection = null;
        try{
            // Hazırladığımız url yi kullanarak web servise Http bağlantısı ile sağlıyoruz
            URL url = new URL(strUrl);
            urlConnection = (HttpURLConnection) url.openConnection();
            urlConnection.connect();

            // webservisden gelen json datayı okuyup, data değişkenine atadık
            iStream = urlConnection.getInputStream();

            BufferedReader br = new BufferedReader(new InputStreamReader(iStream));
            StringBuffer sb  = new StringBuffer();
            String line = "";
            while( ( line = br.readLine())  != null){
                sb.append(line);
            }
            //json veriyi data değişkenine atadıkve metodda return yaptık
            data = sb.toString();
            br.close();

        }catch(Exception e){
            //Log.d("Exception on download", e.toString());
        }finally{
            iStream.close();
            urlConnection.disconnect();
        }
        return data;
    }

    /** Bu sınıf da, Google Directions URL kullanarak, rotanın kaç km. olduğu, ne kadar sürede gidilebildiği
     * gibi bilgileri barındıran json datayı çektik */
    private class DownloadTask extends AsyncTask<String, Void, String> {
        @Override
        protected String doInBackground(String... url) {
            String data = "";
            try{
                data = downloadUrl(url[0]);

            }catch(Exception e){
                //Log.d("Background Task",e.toString());
            }
            return data;
        }

        @Override
        protected void onPostExecute(String result) {
            super.onPostExecute(result);
            //Google Directions bilgisini, JSON formatını parse ederek almayı sağlayan sınıf
            ParserTask parserTask = new ParserTask();
            parserTask.execute(result);
        }
    }

    /** Bu sınıf Google Directions bilgisini, JSON formatını parse ederek almayı sağlar  */
    private class ParserTask extends AsyncTask<String, Integer, List<List<HashMap<String,String>>> >{
        @Override
        protected List<List<HashMap<String, String>>> doInBackground(String... jsonData) {
            JSONObject jObject;
            List<List<HashMap<String, String>>> routes = null;

            try{
                jObject = new JSONObject(jsonData[0]);
                //DirectionsJSONParser sınıfında tüm json çözümlenir.
                DirectionsJSONParser parser = new DirectionsJSONParser();
                routes = parser.parse(jObject,MainActivity.this);
            }catch(Exception e){
                e.printStackTrace();
            }
            return routes;
        }

        // Json çözümlendikten sonra, harita üzerinde rotayı(path) çizmeyi sağlayan metod
        @Override
        protected void onPostExecute(List<List<HashMap<String, String>>> result) {
            ArrayList<LatLng> points = null;
            PolylineOptions lineOptions = null;

            for(int i=0;i<result.size();i++){
                points = new ArrayList<LatLng>();
                lineOptions = new PolylineOptions();

                List<HashMap<String, String>> path = result.get(i);

                for(int j=0;j<path.size();j++){
                    HashMap<String,String> point = path.get(j);

                    double lat = Double.parseDouble(point.get("lat"));
                    double lng = Double.parseDouble(point.get("lng"));
                    LatLng position = new LatLng(lat, lng);
                    points.add(position);
                }

                //PolylineOptions ile rota üzerinde noktalar ekleyerek, çizginin rengini ve genişliğini belirleme
                lineOptions.addAll(points);
                lineOptions.width(8);
                lineOptions.color(Color.RED);
            }

            if(lineOptions != null) {
                if(mPolyline != null){
                    mPolyline.remove();
                }
                mPolyline = mMap.addPolyline(lineOptions);

            }else
                Toast.makeText(getApplicationContext(),"Rota bulanamadı", Toast.LENGTH_LONG).show();
        }
    }

}

DirectionsJSONParser sınıfında ise web servisden gelen Json veriyi çözümleyip, içindeki bilgileri ArrayList yapısına ekleyerek MainActivity sınıfında kullanılması sağlanmıştır. Ek olarak DirectionsJSONParser sınıfında Json veriden gelen polyline değerini (rota yolunun şifrelenmiş çizgileri) çözümleyen bir metod yazılmıştır. Bu metod sayesinde  rota yolunun çizilebilmesi için gerekli enlem, boylam değerleri elde edilir. Detaylı anlatım kodlarda bulunmaktadır.

import android.content.*;
import android.preference.PreferenceManager;
import com.google.android.gms.maps.model.LatLng;
import org.json.*;
import java.util.*;
public class DirectionsJSONParser {
    /** Google Directions URL kullanarak web servisden elde edilen JSONObject çözümlenerek,
     rotayı ne kadar sürede bitirebileceğiniz, rotanın kaç km olduğu, yol tarifleri hakkında detaylı bilgiler elde edilir   */
    public List<List<HashMap<String,String>>> parse(JSONObject jObject, Context context){

        List<List<HashMap<String, String>>> routes = new ArrayList<>() ;
        JSONArray jRoutes = null;
        JSONArray jLegs = null;
        JSONArray jSteps = null;

        try {
            jRoutes = jObject.getJSONArray("routes");

            for(int i=0;i<jRoutes.length();i++){
                jLegs = ( (JSONObject)jRoutes.get(i)).getJSONArray("legs");

                JSONObject c = jLegs.getJSONObject(i);
                JSONObject vo = c.getJSONObject("duration");
                //Rotaya varış süresini, SharedPreferences nesnesine atadım. Haritada gösterimi, MainActivity sınıfında.
                SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
                SharedPreferences.Editor editor = prefs.edit();
                editor.putString("duration", vo.getString("text"));
                editor.commit();

                List path = new ArrayList<HashMap<String, String>>();
                for(int j=0;j<jLegs.length();j++){
                    jSteps = ( (JSONObject)jLegs.get(j)).getJSONArray("steps");
                    for(int k=0;k<jSteps.length();k++){
                     //Polyline çözümleyerek, rota noktalarının enlem, boylam bilgisi alma
                        String polyline = "";
                        polyline = (String)((JSONObject)((JSONObject)jSteps.get(k)).get("polyline")).get("points");
                        List<LatLng> list = decodePoly(polyline);

                        for(int l=0;l<list.size();l++){
                            HashMap<String, String> hm = new HashMap<String, String>();
                            hm.put("lat", Double.toString(((LatLng)list.get(l)).latitude) );
                            hm.put("lng", Double.toString(((LatLng)list.get(l)).longitude) );
                            path.add(hm);
                        }
                    }
                    routes.add(path);
                }
            }

        } catch (JSONException e) {
            e.printStackTrace();
        }catch (Exception e){
        }
        return routes;
    }

    /**
     * Polyline (rota yolunun şifrelenmiş çizgileri) çözümleyerek, rota noktalarının enlem, boylam bilgisini döner
     */
    private List<LatLng> decodePoly(String encoded) {

        List<LatLng> poly = new ArrayList<LatLng>();
        int index = 0, len = encoded.length();
        int lat = 0, lng = 0;

        while (index < len) {
            int b, shift = 0, result = 0;
            do {
                b = encoded.charAt(index++) - 63;
                result |= (b & 0x1f) << shift;
                shift += 5;
            } while (b >= 0x20);
            int dlat = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1));
            lat += dlat;

            shift = 0;
            result = 0;
            do {
                b = encoded.charAt(index++) - 63;
                result |= (b & 0x1f) << shift;
                shift += 5;
            } while (b >= 0x20);
            int dlng = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1));
            lng += dlng;

            LatLng p = new LatLng((((double) lat / 1E5)),
                    (((double) lng / 1E5)));
            poly.add(p);
        }
        return poly;
    }
}

Örneklediğim projemin kodlarını indirmek isterseniz; yapmanız gereken tek şey aşağıya koyduğum KODLARI İNDİR resmine tıklamak.

AndroidX Kütüphanesine Geciş

Bir yazılımcı proje geliştirirken, yazılımı daha işlevsel hale getirmek, iş yükünü hafifletmek ve aynı kodu tekrar yazmasına gerek kalmadan hazır bir kalıp sunmayı sağlayan birçok kütüphane kullanmaktadır.

Android uygulama geliştiricilerinin, uzun zamandır hemen her yazılımda kullandıkları temel olan Destekleme Kütüphanesi (Support Library) bulunmaktadır. Google, bir çok kütüphanenin güncel hali olan AndroidX kütüphanesini duyurdu. AndroidX, en gelişmiş Jetpack bileşenlerini ve Support Library’i kapsayan bir kütüphanedir.

Bu makalemde, Android uygulamalarda neden AndroidX kütüphanesini kullanmanız gerektiğini ve var olan uygulamalarınızı, AndroidX kütüphanesine geçişini nasıl yapacağınızı anlatacağım.

Neden AndroidX kütüphanesini kullanmalıyız?

  • Android Support Library kullanımı, ömrünün sonuna geldi. Support Library, Android 28.0 sdk sürümünden sonra geliştirilmeyecektir. Support Library kullandığınızda karşılaşacağınız hataları düzeltebilmek istiyorsanız, AndroidX’e geçmeniz gerekir.
  • Google Play hizmetleri, Firebase, SQLite, Activity ve Fragment gibi önemli yapılar AndroidX kütüphanesine taşındı.
  • Support Library’de adlandırma çok uzun olması ve çok sık sürüm çıkartılması geliştiricileri yormaktaydı. AndroidX ile kütüphane adlandırmaları ve sürümler standartlaştırıldı.

    Örneğin; Support Library’de var olan appcompat yapısını kullanmak için aşağıdaki kodu kullanmalıyız.

    com.android.support:appcompat-v7

    Support Library’de com.android.support değeri ile adlandırmaya başlanırken, AndroidX yapısını kullanacağımızda direk androidx şeklinde başlar.

    androidx.appcompat:appcompat

Projenizin AndroidX ‘e Geçişi Nasıl Yapılır

Var olan projemizi AndroidX’e geçirmek için bazı işlemler yapmamız gerekmektedir. Yalnız Android Studio’nun “Migrate to AndroidX” özelliği sayesinde, bu geçiş süreci hayli kolaydır.

AndroidX’e geçiş için yapmamız gereken bazı adımlar:

    1. App dizinin içindeki build.gradle dosyasındaki, compileSdkVersion (en az) 28 olarak ayarlanmalıdır.
    2.  Android Gradle Build Version 3.2 veya üstü olarak ayarlanmalıdır.

      build.gradle(Project: ) → dependencies → classpath ayarları yapılmalıdır.

      dependencies {
          classpath 'com.android.tools.build:gradle:3.2.1'
      }
    3. Temel ayarlarımızı yaptıktan sonra, Android Studio menüde, Refactor → Migrate to AndroidX seçeneğine tıklamalısınız.

      İşlem yüklendikten sonra Android Studio’nun alt kısmında aşağıda belirttiğim bölüm açılacaktır. Bu bölümde Do Refactor butonuna tıklayıp, AndroidX’e geçiş işlemini tamamlamalısınız.

Böylelikle geçmişte oluşturduğunuz projeleri 3 adımda AndroidX kütüphane yapısına geçirmiş olduk.

Kaynaklar

1- https://medium.com/androiddevelopers/migrating-to-androidx-tip-tricks-and-guidance-88d5de238876

2- https://developer.android.com/jetpack/androidx

 

AndroidX Biometric API ile Parmak İzi Doğrulama

Hepimiz mobil cihazlarımızda birçok bilgiyi saklıyoruz. İnsanlar, uygulama içi ödemeler yapmak gibi hassas işlemleri gerçekleştirmek için düzenli olarak akıllı telefonlar ve tabletler kullanıyor.Bu yüzden mobil uygulamalarda güvenlik çok önemli bir konumdadır. Güvenliği sağlamak için çeşitli yöntemleri uygulayabilirsiniz. Kullanıcının sisteme erişirken kim olduğunu kanıtlama işlemi olan kimlik doğrulama, güvenlik yöntemlerden biridir. PIN, şifre, güvenlik anahtarı ve biyometrik (parmak izi, yüz algılama) kimlik doğrulama çeşitlerinden birini kullanarak uygulamanızın bazı bölümlerini veya tüm uygulamanızı kilitlemeyi düşünebilirsiniz.

Parola ve PIN  kimlik doğrulama yöntemlerinde, giriş bilgilerini unutma ya da karıştırma ihtimaliniz yüksektir. Fakat Biyometrik parmak izi doğrulama, parmak ucunuzu dokunmatik sensöre basarak yapılan bir işlem olduğu için uygulaması daha kolaydır. Parola ve PIN kimlik doğrulama gibi yöntemleri kullandığınızda birisinin şifreleri tahmin edemeyeceğinin veya kullanıcının cihazına casus yazılım gibi araçlar yoluyla şifresini sızdırmayacağına dair bir garanti yoktur. Parmak izi ise benzersiz ve tahmin edilmesi imkansız olduğundan güvenliği daha yüksek bir yöntemdir.

Bu makalemde, bir Android uygulamasında AndroidX Biometric kütüphanesini kullanarak, parmak izi kimlik doğrulama yöntemini örnekleyeceğim.

Örneğimizi uyguladığımızda aşağıdaki gibi bir ekran görüntüsünü elde edeceğiz.

androidx-biometric

Örneklediğim projemin kodlarını indirmek isterseniz; yapmanız gereken tek şey aşağıya koyduğum KODLARI İNDİR resmine tıklamak.

Birkaç adımda bir Android uygulamasında AndroidX Biometric kütüphanesini kullanarak, parmak izi kimlik doğrulamayı nasıl yapacağımızı görelim.

1-Gerekli Kütüphanelerin Eklenmesi

Biometric API ile parmak izi doğrulama yapabilmek için AndroidX kütüphanesine geçmeniz gerekir.Bu yüzden projedeki appcompat, constraintlayout ve biometric kütüphanelerinin tanımlamaları androidx ile başlayacaktır.

Dilerseniz AndroidX Kütüphanesine Geciş adlı makalemi okuyarak, var olan projelerinizi AndroidX yapısına kolaylıkla geçişini sağlayabilirsiniz.

Android Studio Ide ile oluşturduğum projemin app dizinin altındaki build.gradle dosyasını açıyoruz. Dependencies kod bloklarının arasına aşağıdaki kodları yerleştirerek Biometric kütüphanesini yüklüyoruz.

implementation "androidx.appcompat:appcompat:1.1.0"
implementation "androidx.constraintlayout:constraintlayout:2.0.0-beta4"
implementation "androidx.biometric:biometric:1.0.1"

2-Projede İzinlerin Tanımlanması

Cihazın desteklediği tüm farklı biyometrik kimlik doğrulama işlemlerini kullanabilmek için bir tane izin tanımlamamız gerekir. Aşağıdaki izin kodunu da AndroidManifest.xml dosyasında application tag’nin üst kısmına yerleştirin.

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

3-Arayüz Kodlaması

Örneğimizdeki görüntüyü elde etmek içim, 1 tane xml dosyasında kodlama yapmamız gerekmektedir. activity_main xml kodlarımızda, constraintlayout içine Button ekledim.

activity_main xml kodlarımız;

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <Button
        android:id="@+id/launchAuthentication"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/auth"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.038" />

</androidx.constraintlayout.widget.ConstraintLayout>

4-Java kodlama ile işlevsellik oluşturma

AndroidX Biometric API’nin içinde bulunan BiometricPrompt sınıfını kullanarak, parmağı sensöre dokundurduğunuz anda, telefonda kayıtlı iz ile karşılaştırma yaparak uygulama içinde kimlik doğrulama yapar.Daha detaylı kod açıklamaları, yorum tagları içinde bulunmaktadır.

import androidx.appcompat.app.AppCompatActivity;
import androidx.biometric.BiometricPrompt;
import android.os.Bundle;
import java.util.concurrent.*;
import android.util.Log;
import android.view.View;
import androidx.annotation.NonNull;

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Executor newExecutor = Executors.newSingleThreadExecutor();
        //Parmağı sensöre dokundurduğunuz anda, telefonda kayıtlı iz ile
        //karsılastırma için BiometricPrompt sınıfının içindeki işlem durumu metodları oluşturulur
        final BiometricPrompt myBiometricPrompt = new BiometricPrompt(this, newExecutor, new BiometricPrompt.AuthenticationCallback() {

            //Bu metodda sensöre dokundurduğunuzda, bir hatayla karsılaşıp karşılaşmadığınızın kontrolunu yaptık
            //Örnek hatalar; cihazın dokunmatik sensörü kir kaplıdır, kullanıcı bu cihaza herhangi bir parmak izi kaydetmemiştir veya tam biyometrik tarama yapmak için yeterli bellek yoktur
            @Override
            public void onAuthenticationError(int errorCode, @NonNull CharSequence errString) {
                super.onAuthenticationError(errorCode, errString);
                if (errorCode == BiometricPrompt.ERROR_NEGATIVE_BUTTON) {
                } else {
                    Log.d("MainActivity", "bir hata oluştu");
                }
            }
            //Bu metod, parmak izi cihazda kayıtlı parmak izlerinden biriyle başarılı bir şekilde eşleştiğinde çağrılır.
            @Override
            public void onAuthenticationSucceeded(@NonNull BiometricPrompt.AuthenticationResult result) {
                super.onAuthenticationSucceeded(result);
                Log.d("MainActivity", "Parmak izi başarıyla tanındı");
            }
            //Bu metodda parmak izi tanıma işlemi başarılı olmadığında, yapılacak işlemler yazılmalı
            @Override
            public void onAuthenticationFailed() {
                super.onAuthenticationFailed();
                Log.d("MainActivity", "Parmak izi tanınmadı");
            }

        });
        //kimlik doğrulama iletişim kutusunda görünmesi gereken metni tanımlamanız ve kimlik doğrulamasını iptal etmesini sağlayan metoda isim atama
        final BiometricPrompt.PromptInfo promptInfo = new BiometricPrompt.PromptInfo.Builder()
                .setTitle("Başlık yazılacak alan")
                .setSubtitle("Altbaşlık yazılacak alan")
                .setDescription("Açıklama yazılacak alan")
                .setNegativeButtonText("İptal")
                .build();

        findViewById(R.id.launchAuthentication).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                myBiometricPrompt.authenticate(promptInfo);
            }
        });

    }
}

 

 

Vektörel İllüstrasyon Temelleri- Part 3: Boolean Operations

Oluşturacağınız mobil uygulamalardaki özel şekiller ve vektörel illüstrasyonlar için işinizi kolaylaştıran kavramlardan biri olan boolean operatörlerini anlattığım makaledir. Bir önceki makalelerimde Primitive Şekiller, Stroke ve Paths den bahsettim. Makaleleri sırasıyla okumanızı tavsiye ediyorum. Eğer PART 1 ve PART 2’yi okumadıysanız buradan ulaşabilirsiniz.

İşte daha önce tasarladığım bir şekil. Peki bu nedir? Öncelikle bunun bir daire olduğunu hepimiz biliyoruz. Fakat üst kısımda yıldız şeklinde bir parça ve alt kısımda da elips şeklinde bir parça eksik duruyor. Yani, bu illüstrasyon da o şekilleri çemberden çıkartım. Bu da boolean operatörlerinden biri olan substration yöntemidir.

Substration, çoğu vektör grafik yazılımı tarafından önerilen dört ana boolean operatörlerinden biridir. Bakalım substration ve diğer üç işlemi nasıl yapacağım.

Subtraction

Çıkarmayı gerçekleştirmek için, iki (veya daha fazla) şeklin çakıştığından emin olun. Ardından, “Shift” tuşunu basılı tutarak boolean işlemini gerçekleştirmek istediğiniz tüm şekilleri seçin.

Gravit Designer’da, boolean işlemlerini en üstteki araç çubuğunda açıldığını göreceksiniz. Şöyle görünüyor:

 

Yukarıda gördüğünüz ikona tıklayın ve açılır menüden Subtract’ı seçin. Bu, çakışan iki şekil arasında üst şeklin bir kısmını alttaki şekilden çıkaracaktır. Aşağıdaki görselde daha iyi anlayacaksınız.

Z sıralamasını henüz açıklamadım, ancak şu anda bilmeniz gereken şey şu şekildedir: İlk önce çizdiğiniz şekli, ikinci çizdiğiniz şeklin altında bir seviyeye oturmaktadır. Bu durumda, ilk önce kare çizilmiş ve kare şeklinin üzerine oturacak şekilde bir daire çizildi.

Intersection

Insersection, dört ana boolean operatörlerinden biridir ve yine aynı şekilde, Shift tuşunu basılı tutarak, çakışan şekiller arasından çoklu seçim yapın. Ardından boolean işlemleri açılır menüsünden Insersect’ı seçin.

Bu, nesnelerin kesişen kısımlarını korur ve diğer kısımları kaldırır. Aşağıdaki resimde daha iyi görecekseniz.

Difference

Bir diğer boolean operatörlerden biri ise fark operatörüdür. Burda da yine aynı şekilde çakışan şekilleri seçip, ardından Difference seçin.

Difference, intersection işleminin tam tersidir. Yani çakışan kısımları çıkarıp, geri kalan kısımları korur. Aşağıdaki resimde ne demek istediğimi daha iyi anlayacaksınız.

Union

Son olarak union; boolean birleştirme operatörüdür.

Evet, burada da şekilleri birleştiriyoruz.

Genel olarak toparlamak gerekirse, boolean operatörleri, basit şekillerden, karmaşık şekiller oluşturmak için mükemmel bir yoldur.

Vektörel İllüstrasyon Temelleri- Part 2: Stroke and Paths

“Vektörel İllüstrasyon Temelleri” başlıklı makalelerimizden bir yenisini daha sizlerle paylaşmak istiyorum.Bu makale, 5 bölümden oluşan serisinin 2. kısmıdır. Bir önceki makalede (Part 1), vektörel illüstrasyonlar oluşturmak için bilmeniz gereken 5 önemli kavramdan biri olan Primitive Shapes’den bahsettim. Bu makalede de Stroke ve Paths’lerden bahsedeceğim. Makaleleri sırasıyla okumanızı tavsiye ediyorum. Eğer PART 1’i okumadıysanız buradan ulaşabilirsiniz.

Stroke, bir şekli çevreleyen ya da açık yollarda bir yolu izleyen bir çizgidir.

Şekiller gibi, stroke’larda görünüşlerini tanımlayan niteliklere sahiplerdir. Xml’de çizilebilir bir şekil oluşturduğunuzda, bazı stroke niteliklerini tanımlayabilirsiniz. Örneğin, aşağıdaki kod bloğu, çevresindeki turuncu kesik çizgi ve dolgu içermeyen bir dikdörtgeni temsil eder.

<shape
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
    
    <stroke
        android:width="2dp"
        android:color="#FB8C00"
        android:dashWidth="4dp"
        android:dashGap="1dp" />
</shape>

Stroke’un özellikleri;

  • Width
  • Color
  • Dashwidth
  • Dashgab

Android SDK, özellikler açısında bundan daha fazla ilerlemese de Gravit Designer, bize isteğimize göre strokeları nitelendirmek için çok daha fazla özellikler sunuyor.

Caps

Caps,stroke’un bitişidir. Açıkçası, kapalı yollarda (daire ve dikdörtgenler gibi) bitiş yoktur ancak açık yollar vardır.

Gördüğünüz gibi, özellikle geniş darbeler söz konusu olduğunda, caps’in stili, görünüm açısından çok fark yaratabilir.

Örneğin, aşağıdaki gibi “liquidstyle” resimler, büyük oranda yuvarlak caps’lerle yapılan stroke’lara bağlıdır ve sanata bu “dripping/moving”” hissi verir.

GravitDesigner’da caps stilini değiştirmek son derece kolaydır: Bir stroke çizdikten sonra sağ bölmeye gidin ve “border” bölümündeki “fader” simgesini tıklayarak caps i özelleştirebilirsiniz. Aşağıda nasıl olduğunu gösterdim.

Burada, diğer şeylerin yanı sıra bitiş noktalarını bulacaksınız ve istediğiniz stili seçebileceksiniz.

Stroke’ların başlangıcındaki ve sonundaki şekiller

Gravit Designer, stroke un başlangıç ve bitiş noktalarına çeşitli şekiller eklemenizi sağlar. Aşağıdaki örnek illüstrasyonunda kavisli turuncu bir ok görecekseniz.

Ok’un sağına eklenen üçgen işareti eklemek için border bölümündeki fader simgesine tıklayıp ve üçgen işareti seçerek ekleyebilirsiniz. Ayrıca, daire, mermi, elmas, çift ok vb. şekiller de ekleyebilirsiniz.

Daha fazla stroke özellikleri

Border bölümündeki, “fader” simgesini tıkladıktan sonra çıkan pop up’taki çizgi genişliğini ve çizgi boşluğunu da ayarlayabileceğinizi fark etmişsinizdir.

Son olarak, stroke renklerini border bölümündeki, border başlığının hemen altında ayarlayabilirsiniz. Daireye dokunup ve önceden ayarlanmış renk örneğinden istediğiniz rengi seçebilir veya kendi renklerinizi kullanabilirsiniz. Ayrıca, illüstrasyonunuzun diğer bir kısımları için renginizi seçmeye olanak tanıyan bir eye dropper da vardır.

Peki, nasıl stroke oluşturabilirim?

Bir stroke oluşturmak için, basitçe bir şekil çizin ve dolguyu kaldırın (şekil önceden st ve roke ayarına sahip değilse, border bölümüne gidip “+” simgesine tıklayarak ekleyebilirsiniz). Dolguları kaldırmak için, border bölümünün hemen üstünde fills bölümünü göreceksiniz. Seçilen dolguları kaldırmak için çöp kutusu simgesine tıklayabilirsiniz.

Stroke oluşturmanın bir başka yolu peltool u kullanmaktır. Pentool, her vektör grafik yazılımında bulunan çok güçlü bir araçtır ancakişi kavramasınız için bazı pratikler yapmanız gerekir.

Stroke oluşturmak zor değil, ancak bu konuyla ilgili bir video dersi izlemeniz daha iyi olacağına inanıyorum.

Gravit Designer da kalem aracını kullanma konusunda bir video önerim bulunmaktadır. Dilerseniz izleyebilirsiniz. https://youtu.be/DgJjB7GjsuI

Stroke ve Paths arasındaki fark

Path, bir dizi noktadır ve bir şekli tanımlayan bir koordinat kümesidir. Path’in kendisi yalnızca bir sayı kümesidir ve matematiksel bir tanımdır. Ekranda gördüğünüz her şey, o path’in görsel bir temsilidir.

Stroke, bir path’e uygulayabileceğiniz görsel bir özelliktir. Stroke, tanımlanmış bir genişlik, renk veya bir dizi diğer özelliklere sahip olabilir ve path’e bağlı görsel bir efekttir.

Stroke olmadan bir path oluşturabilirsiniz, ancak path olmadan bir stroke oluşturamazsınız.

 

Bir sonra ki makale de Part3:Boolean Operations’dan bahsedeceğim. Takipte kalın!

 

 

DAF Platform

DaF Yayın Grubu‘nun Basılı Yayın olarak hazırladıkları ürünlerin bir bölümünü dijital olarak “Almanca Dili Öğrencilerine” ücretsiz sunan bir IOS uygulamasıdır. Bu platformda, yayınlarımızın testlerini (ödevlerini) online çözüp öğretmenlerinize gönderebilir, hazırlamış olduğumuz interaktif alıştırmaları çözüp kendinizi sınayabilir, eğitim videolarımız ile bilginizi genişletebilir ve ses dosyaları ile telaffuzlarınızı düzeltebilirsiniz.
daf1daf1
daf2daf2
daf3daf3

BANKO İDDAA TAHMİNLERİ

Bu uygulamayı indirdiğiniz de Türkiye’nin en tecrübeli analiz ekibinin, en çok kazandıran iddaa tahminleri banko maç ve banko kuponlarına sahip olacaksınız. 8 yıldır sizlere iddaatahmin.com olarak hizmet vermekteyiz ve 500.000 kullanıcıyla Türkiye’nin lider iddaa tahminleri uygulamasıyız.

Bizi en iyi iddaa tahminleri uygulaması yapan en çok kullanıcıya sahip olmamızın yanında; Verdiğimiz iddaa tahmin ve banko kuponların başarı yüzdesi. Tek yapmanız gereken uygulamamızı indirmek ve her gün size verdiğimiz banko maç ve banko kuponları bahis oyunlarınızda değerlendirmeniz.

Bu uygulamayı indirdiğinizde iddaa tahminlerimiz ve banko kuponlarımızın yanında sahip olacağınız diğer özellikler;

  • Uzman tahmincilerimizin analizleri ve banko maç yorumları.
  • Uzman tahmincilerimizin hazırladığı günlük analizli iddaa kuponları.
  • İddaa maç programı.
  • Canlı maç sonuçları.
  • Kupon yükle özelliği ile sizlerden gelen banko maç ve banko kupon paylaşımları.

Uygulama hakkındaki görüş ve önerileriniz bizim için önemli.
Yıllardır en iyi iddaa tahmin ekibi olmamızda sizlere verdiğimiz güvenin yanında; Sizlerden gelen önerileri ekip olarak değerlendirmemiz, her zaman daha iyisini yapmamıza katkı sağlıyor.

i1i1
i2i2
i3i3
i4i4

İSTANBUL CODERS “MATERİAL DESİGN İLE ANDROİD DESİGN SUPPORT LİBRARY KULLANIMI” SUNUMU

İstanbul Coders adlı toplulukda “Material Design ile Android Design Support Library Kullanımı” konusu hakkında sunum yaptım. Material Design konusunun içerdiği Android 5.1.1 sürümüyle gelen Android Design Support Library kullanarak çok basit bir şekilde, android projeye farklı animasyonlar ve arayüzler oluşturmayı anlatığım bir sunumdu.

ORGANİZASYON GRUBU
İstanbul Coders

SUNUM YERİ
İstanbul Teknik Üniversitesi

GDG WOMEN TECHMAKERS KOCAELİ “ANDROİD THREAD VE ASYNCTASK” SUNUMU

Women Techmakers Kocaeli adlı topluluk da “Android Thread ve Asynctask” konusu hakkında sunum yaptım. Sunumda, arka planda bazı işler yapılırken, arayüz tarafında kullanıcının programı kullanmaya devam etmesini sağlayan Asynctask adlı android nesnesinin nasıl oluşturulduğunu örnekleyerek anlattım.

ORGANİZASYON GRUBU
GDG Women Techmakers Kocaeli

SUNUM YERİ
Kocaeli Üniversitesi