Android işletim sistemli cihazlarda, verileri kalıcı olarak saklamanın birkaç yolu vardır. SQLite, uygulama verilerini depolama yöntemlerinden birisidir. Android işletim sistemi ile birlikte gelen çok hafif bir veritabanıdır. Eğer uygulamanızda basit veri nesneleri depolaması gerekiyorsa SQLite sistemini kullanmaya çalışın. SQLite kullanımı size hız, performans ve modülerlik sağlayacaktır.
Bu makalede, Android işletim sistemli cihazlarda veritabanının temellerini SQLite kullanarak oluşturacağımız Notlarım uygulaması ile öğreneceğiz.
1. The Notlarım Uygulaması
Veri tabanı depolamasının Android uygulamalarda nasıl çalıştığını göstermek üzere basit bir Notlarım uygulaması oluşturacağız. Bu uygulama kullanıcının yeni not girebildiği, silebildiği veya güncelleme yapabildiği bir ekrandan oluşan basit bir uygulamadan oluşacaktır. Uygulama ile alakalı ekran görüntüleri şu şekildedir;
Hadi Android Studio'da notlarım uygulamasını oluşturmaya başlayalım.
2. Yeni Android Uygulama Oluşturulması
1. Android Studio'da File ⇒ New Project seçeneğini seçip, templates olarak görüntülenen seçeneklerden Basic Activity olanı seçerek yeni bir Android proje oluşturun.
2. app dizini altında bulunan build.gradle dosyasını açın ve RecyclerView kütüphanesini ekleyin. Bu kütüphane notların listelenmesinde kullanılacaktır.
dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) // .. implementation 'com.android.support:recyclerview-v7:26.1.0' }
3. colors.xml, dimens.xml ve strings.xml dosyalarına aşağıdaki kod parçalarını ekleyin.
<?xml version="1.0" encoding="utf-8"?> <resources> <color name="colorPrimary">#455399</color> <color name="colorPrimaryDark">#455399</color> <color name="colorAccent">#00c6ae</color> <color name="msg_no_notes">#999</color> <color name="hint_enter_note">#89c3c3c3</color> <color name="timestamp">#858585</color> <color name="note_list_text">#232323</color> </resources>
<resources> <dimen name="fab_margin">16dp</dimen> <dimen name="activity_margin">16dp</dimen> <dimen name="dot_margin_right">10dp</dimen> <dimen name="msg_no_notes">26sp</dimen> <dimen name="margin_top_no_notes">120dp</dimen> <dimen name="lbl_new_note_title">20sp</dimen> <dimen name="dimen_10">10dp</dimen> <dimen name="input_new_note">20sp</dimen> <dimen name="dot_height">30dp</dimen> <dimen name="dot_text_size">40sp</dimen> <dimen name="timestamp">14sp</dimen> <dimen name="note_list_text">18sp</dimen> </resources>
<resources> <string name="app_name">Notlarım</string> <string name="action_settings">Ayarlar</string> <string name="activity_title_home">Notlar</string> <string name="msg_no_notes">Hernangi bir not bulunamadı!</string> <string name="lbl_new_note_title">Yeni Not</string> <string name="lbl_edit_note_title">Notu Güncelle</string> <string name="hint_enter_note">Notunu gir!</string> </resources>
4. Projede database, database/model, utils ve view isimlerinde dosya paketleri oluşturun. Yapılan düzenlemelerden son projenin son hali şu şekilde olacaktır;
2.1. SQLite Helper Sınıfının Oluşturulması
Android'in official kütüphanesi olan SQLiteOpenHelper sınıfı miras alınarak yeni bir sınıf oluşturalım. Bu sınıf CRUD(Create, Read, Update, Delete) yani notlarımız için gerekli olan ekleme, okuma, güncelleme ve silme işlemlerini kapsayacak şekilde ayarlanacaktır.
Veritabanına kayıt edilen notları daha kolay yönetebilmek için Notes modelini oluşturalım.
5. database/model paketi altında, Note.java sınıfı oluşturun. Bu sınıf içerisinde tablo ismi, sütunlar, bu tabloya ait SQL sorgularını ve getter/setter metodlarını içermektir.
- `notes` tablosu `id`, `note` and `timestamp` gibi sütunları içermektedir.
- `id` sütunu eklenen notların tekil olmasını sağlamada kullanılan alandır.
- `note` sütunu yazılan notların tutulduğu alandır.
- `timestamp` sütunu eklenen notların kayıt tarihini tutmada kullanılan alandır.
public class Note { public static final String TABLE_NAME = "notes"; public static final String COLUMN_ID = "id"; public static final String COLUMN_NOTE = "note"; public static final String COLUMN_TIMESTAMP = "timestamp"; private int id; private String note; private String timestamp; // Create table SQL query public static final String CREATE_TABLE = "CREATE TABLE " + TABLE_NAME + "(" + COLUMN_ID + " INTEGER PRIMARY KEY AUTOINCREMENT," + COLUMN_NOTE + " TEXT," + COLUMN_TIMESTAMP + " DATETIME DEFAULT CURRENT_TIMESTAMP" + ")"; public Note() { } public Note(int id, String note, String timestamp) { this.id = id; this.note = note; this.timestamp = timestamp; } public int getId() { return id; } public String getNote() { return note; } public void setNote(String note) { this.note = note; } public String getTimestamp() { return timestamp; } public void setId(int id) { this.id = id; } public void setTimestamp(String timestamp) { this.timestamp = timestamp; } }
6. database paketi altında, DatabaseHelper.java adında ve SQLiteOpenHelper sınıfını miras alan bir sınıf oluşturun. Bu sınıf veritabanı için yapılacak tüm işlemlerde kullanılacaktır.
- onCreate() fonksiyonu uygulama yüklendiğinde sadece bir kere çağrılmaktadır. Bu metod, uygulamada kullanılacak veritabanı ve bu veritabanında kullanılacak olan tabloların oluşturulmasında kullanılmaktadır.
- Tablolarda herhangi bir güncelleme gerektiğinde onUpgrade() fonksiyonu kullanılmaktadır. Herhangi bir güncelleme olup olmadığını DATABASE_VERSION numarasına göre gerçekleştirebilirsiniz. Tabloda herhangi bir yeni sütun eklenmesi veya yeni tabloların oluşturulması durumunda bu numaranın yükseltilmesi yeterli olacaktır. Örneğimizde mevcut olan tabloların tümünün silinmesi ve yeniden oluşturulması sağlanmıştır.
import android.content.ContentValues; import android.content.Context; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; import java.util.ArrayList; import java.util.List; import info.yazilimdersi.sqlite.database.model.Note; public class DatabaseHelper extends SQLiteOpenHelper { // Veritabanı versiyonu private static final int DATABASE_VERSION = 1; // Veritabanı adı private static final String DATABASE_NAME = "notes_db"; public DatabaseHelper(Context context) { super(context, DATABASE_NAME, null, DATABASE_VERSION); } // Tabloların oluşturulması @Override public void onCreate(SQLiteDatabase db) { // notes tablosunu oluştur db.execSQL(Note.CREATE_TABLE); } // Veritabanının güncellenmesi @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { // Mevcut notes tablosunu kaldır. db.execSQL("DROP TABLE IF EXISTS " + Note.TABLE_NAME); // Veritabanını tekrardan oluştur. onCreate(db); } }
Artık notları kayıt etmede kullanılacak olan veritabanı oluşturuldu. Şimdi aynı sınıfa aşağıdaki fonksiyonları ekleyelim;
a. Not Eklenmesi
Bu fonksiyon veritabanına yazma imkanı sunan getWritableDatabase() metoduna erişim gerektirmektedir. Aşağıdaki kodlamada veritabanına yeni bir notun nasıl kayıt edildiğini görebilirsiniz;
- ContentValues() sütun isimlerinin belirlenmesi ve verilerin kayıt edilmesinde kullanılmaktadır. Burada, `id` and `timestamp` sütunları otomatik olarak setleneceği için bunları ekleme işleminde tanımlamıyoruz.
- Her zaman veritabanında yapılacak işlemin bitirilmesinin ardından db.close() metodunun çağrılması gerekmektedir. db.close() metodunun çağrılması aktif olan bağlantının kapatılmasını sağlamaktadır.
- Herhangi bir yeni kayıt oluşturulduğunda eklenen kayda ait `id` verisi dönecektir.
public long insertNote(String note) { // veritabanına erişimde kullanılacak nesne SQLiteDatabase db = this.getWritableDatabase(); ContentValues values = new ContentValues(); // `id` and `timestamp` otomatik oluşturulduğu için eklemeye gerek yoktur. values.put(Note.COLUMN_NOTE, note); // yeni kayıt oluştur long id = db.insert(Note.TABLE_NAME, null, values); // bağlantıyı kapat db.close(); // yeni eklenen kaydın id bilgisini dönebilirsin. return id; }
b. Notların Listelenmesi
Bu fonksiyon veritabanına okuma imkanı sunan getReadableDatabase() metoduna erişim gerektirmektedir. Aşağıdaki kodlamada veritabanında kayıtlı olan tüm notların ve sadece istenilen nota erişimi görebilirsiniz;
- getNote() metodu ile iletilen `id` parametresine bağlı olarak ilişkili notun döndürülmesi sağlanmıştır.
- getAllNotes() metodunun çağrılması ile veritabanında kayıtlı tüm notların getirilmesi sağlanmıştır.
- getNotesCount() metodu ile veritabanında kayıtlı bulunan notların sayısını dönmektedir.
public Note getNote(long id) { SQLiteDatabase db = this.getReadableDatabase(); Cursor cursor = db.query(Note.TABLE_NAME, new String[]{Note.COLUMN_ID, Note.COLUMN_NOTE, Note.COLUMN_TIMESTAMP}, Note.COLUMN_ID + "=?", new String[]{String.valueOf(id)}, null, null, null, null); if (cursor != null) cursor.moveToFirst(); Note note = new Note( cursor.getInt(cursor.getColumnIndex(Note.COLUMN_ID)), cursor.getString(cursor.getColumnIndex(Note.COLUMN_NOTE)), cursor.getString(cursor.getColumnIndex(Note.COLUMN_TIMESTAMP))); // veritabanı bağlantısını kapatalım cursor.close(); return note; } public ListgetAllNotes() { List notes = new ArrayList<>(); // Select Sorgusu String selectQuery = "SELECT * FROM " + Note.TABLE_NAME + " ORDER BY " + Note.COLUMN_TIMESTAMP + " DESC"; SQLiteDatabase db = this.getWritableDatabase(); Cursor cursor = db.rawQuery(selectQuery, null); if (cursor.moveToFirst()) { do { Note note = new Note(); note.setId(cursor.getInt(cursor.getColumnIndex(Note.COLUMN_ID))); note.setNote(cursor.getString(cursor.getColumnIndex(Note.COLUMN_NOTE))); note.setTimestamp(cursor.getString(cursor.getColumnIndex(Note.COLUMN_TIMESTAMP))); notes.add(note); } while (cursor.moveToNext()); } // veritabanı bağlantısını kapatalım db.close(); // notların tümünü döner return notes; } public int getNotesCount() { String countQuery = "SELECT * FROM " + Note.TABLE_NAME; SQLiteDatabase db = this.getReadableDatabase(); Cursor cursor = db.rawQuery(countQuery, null); int count = cursor.getCount(); cursor.close(); // notların sayısını döner return count; }
c. Notun Güncellenmesi
Bu fonksiyon veritabanına yazma imkanı sunan getWritableDatabase() metoduna erişim gerektirmektedir. Aşağıdaki kodlamada veritabanında kayıtlı bir notun nasıl güncellenebildiğini görebilirsiniz;
public int updateNote(Note note) { SQLiteDatabase db = this.getWritableDatabase(); ContentValues values = new ContentValues(); values.put(Note.COLUMN_NOTE, note.getNote()); // notunu güncelleyelim return db.update(Note.TABLE_NAME, values, Note.COLUMN_ID + " = ?", new String[]{String.valueOf(note.getId())}); }
c. Notun Silinmesi
Bu fonksiyon veritabanına yazma imkanı sunan getWritableDatabase() metoduna erişim gerektirmektedir. Aşağıdaki kodlamada veritabanında kayıtlı bir notun nasıl silindiğini görebilirsiniz;
public void deleteNote(Note note) { SQLiteDatabase db = this.getWritableDatabase(); db.delete(Note.TABLE_NAME, Note.COLUMN_ID + " = ?", new String[]{String.valueOf(note.getId())}); db.close(); }
7. utils paketi altında, RecyclerTouchListener.java ve MyDividerItemDecoration.java adında sınıflar oluşturun.
- RecyclerTouchListener sınıfı ile listelemede tıklanan alan ile alakalı alınacak aksiyonlar tanımlanır.
- MyDividerItemDecoration sınıfı ile listeler arasına çizilmesi istenen çizgilerin oluşturulmasında kullanılmaktadır.
import android.content.Context; import android.support.v7.widget.RecyclerView; import android.view.GestureDetector; import android.view.MotionEvent; import android.view.View; public class RecyclerTouchListener implements RecyclerView.OnItemTouchListener { private ClickListener clicklistener; private GestureDetector gestureDetector; public RecyclerTouchListener(Context context, final RecyclerView recycleView, final ClickListener clicklistener) { this.clicklistener = clicklistener; gestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() { @Override public boolean onSingleTapUp(MotionEvent e) { return true; } @Override public void onLongPress(MotionEvent e) { View child = recycleView.findChildViewUnder(e.getX(), e.getY()); if (child != null && clicklistener != null) { clicklistener.onLongClick(child, recycleView.getChildAdapterPosition(child)); } } }); } @Override public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) { View child = rv.findChildViewUnder(e.getX(), e.getY()); if (child != null && clicklistener != null && gestureDetector.onTouchEvent(e)) { clicklistener.onClick(child, rv.getChildAdapterPosition(child)); } return false; } @Override public void onTouchEvent(RecyclerView rv, MotionEvent e) { } @Override public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) { } public interface ClickListener { void onClick(View view, int position); void onLongClick(View view, int position); } }
import android.content.Context; import android.content.res.Resources; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.util.TypedValue; import android.view.View; public class MyDividerItemDecoration extends RecyclerView.ItemDecoration { private static final int[] ATTRS = new int[]{ android.R.attr.listDivider }; public static final int HORIZONTAL_LIST = LinearLayoutManager.HORIZONTAL; public static final int VERTICAL_LIST = LinearLayoutManager.VERTICAL; private Drawable mDivider; private int mOrientation; private Context context; private int margin; public MyDividerItemDecoration(Context context, int orientation, int margin) { this.context = context; this.margin = margin; final TypedArray a = context.obtainStyledAttributes(ATTRS); mDivider = a.getDrawable(0); a.recycle(); setOrientation(orientation); } public void setOrientation(int orientation) { if (orientation != HORIZONTAL_LIST && orientation != VERTICAL_LIST) { throw new IllegalArgumentException("invalid orientation"); } mOrientation = orientation; } @Override public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) { if (mOrientation == VERTICAL_LIST) { drawVertical(c, parent); } else { drawHorizontal(c, parent); } } public void drawVertical(Canvas c, RecyclerView parent) { final int left = parent.getPaddingLeft(); final int right = parent.getWidth() - parent.getPaddingRight(); final int childCount = parent.getChildCount(); for (int i = 0; i < childCount; i++) { final View child = parent.getChildAt(i); final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child .getLayoutParams(); final int top = child.getBottom() + params.bottomMargin; final int bottom = top + mDivider.getIntrinsicHeight(); mDivider.setBounds(left + dpToPx(margin), top, right - dpToPx(margin), bottom); mDivider.draw(c); } } public void drawHorizontal(Canvas c, RecyclerView parent) { final int top = parent.getPaddingTop(); final int bottom = parent.getHeight() - parent.getPaddingBottom(); final int childCount = parent.getChildCount(); for (int i = 0; i < childCount; i++) { final View child = parent.getChildAt(i); final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child .getLayoutParams(); final int left = child.getRight() + params.rightMargin; final int right = left + mDivider.getIntrinsicHeight(); mDivider.setBounds(left, top + dpToPx(margin), right, bottom - dpToPx(margin)); mDivider.draw(c); } } @Override public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { if (mOrientation == VERTICAL_LIST) { outRect.set(0, 0, 0, mDivider.getIntrinsicHeight()); } else { outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0); } } private int dpToPx(int dp) { Resources r = context.getResources(); return Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, r.getDisplayMetrics())); } }
1. Notlarım Uygulamasının Arayüzünün Tasarlanması
Veritabanı ile alakalı işlemler gerçekleştirildi. Şimdi sıra uygulamanın arayüzünün oluşturulması ve bunun veritabanı ile ilişkilendirilmesinde;
Öncelikle notlarımız listelendiği bir layout sayfasına ve bununla ilişkili adapter sınıfına ihtiyacımız bulunmakta.
9. Her notun tek başına görüntülenebildiği arayüzü oluşturmak için note_list_row.xml adında bir layout oluşturun.
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:clickable="true" android:foreground="?attr/selectableItemBackground" android:paddingBottom="@dimen/dimen_10" android:paddingLeft="@dimen/activity_margin" android:paddingRight="@dimen/activity_margin" android:paddingTop="@dimen/dimen_10"> <TextView android:id="@+id/dot" android:layout_width="wrap_content" android:layout_height="@dimen/dot_height" android:layout_marginRight="@dimen/dot_margin_right" android:layout_marginTop="@dimen/dimen_10" android:includeFontPadding="false" android:textColor="@color/colorAccent" android:lineSpacingExtra="0dp" android:textSize="@dimen/dot_text_size" /> <TextView android:id="@+id/timestamp" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_toRightOf="@id/dot" android:textColor="@color/timestamp" android:textSize="@dimen/timestamp" /> <TextView android:id="@+id/note" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@id/timestamp" android:layout_toRightOf="@id/dot" android:textColor="@color/note_list_text" android:textSize="@dimen/note_list_text" /> </RelativeLayout>
10. view paketi altında, NotesAdapter.java adında bir sınıf oluşturalım. Bu adapter arayüz ile alakalı yapılması planlanan gösterimlerde kullanılacaktır. Ayrıca listelemede tıklanan notun hangisi olduğunu belirlemeye de yaramaktadır.
import android.content.Context; import android.support.v7.widget.RecyclerView; import android.text.Html; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.List; import info.androidhive.sqlite.R; import info.androidhive.sqlite.database.model.Note; public class NotesAdapter extends RecyclerView.Adapter{ private Context context; private List notesList; public class MyViewHolder extends RecyclerView.ViewHolder { public TextView note; public TextView dot; public TextView timestamp; public MyViewHolder(View view) { super(view); note = view.findViewById(R.id.note); dot = view.findViewById(R.id.dot); timestamp = view.findViewById(R.id.timestamp); } } public NotesAdapter(Context context, List notesList) { this.context = context; this.notesList = notesList; } @Override public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View itemView = LayoutInflater.from(parent.getContext()) .inflate(R.layout.note_list_row, parent, false); return new MyViewHolder(itemView); } @Override public void onBindViewHolder(MyViewHolder holder, int position) { Note note = notesList.get(position); holder.note.setText(note.getNote()); // Her notun başında nokta simgesinin gösterimi holder.dot.setText(Html.fromHtml("•")); // Oluşturulduğu zaman diliminin formatlanması ve görüntülenmesi holder.timestamp.setText(formatDate(note.getTimestamp())); } @Override public int getItemCount() { return notesList.size(); } private String formatDate(String dateStr) { try { SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); Date date = fmt.parse(dateStr); SimpleDateFormat fmtOut = new SimpleDateFormat("MMM d"); return fmtOut.format(date); } catch (ParseException e) { } return ""; } }
3.1 Yeni Not Ekleme/Güncellemede Kullanılacak Dialogların Oluşturulması
Oluşturulacak dialogda sadece not girilmesi veya notun editlenebilmesi gibi özellik içerdiğinden EditText elementinin layouta eklenmesi yeterli olacaktır. Burada daha hızlı aksiyon almak adına direkt olarak Dialog elementini kullanabiliriz.
10. Yeni not girmede kullanılacak olan note_dialog.xml adında bir layout oluşturun.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:paddingLeft="@dimen/activity_margin" android:paddingRight="@dimen/activity_margin" android:paddingTop="@dimen/activity_margin"> <TextView android:id="@+id/dialog_title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="@dimen/dimen_10" android:fontFamily="sans-serif-medium" android:lineSpacingExtra="8sp" android:text="@string/lbl_new_note_title" android:textColor="@color/colorAccent" android:textSize="@dimen/lbl_new_note_title" android:textStyle="normal" /> <EditText android:id="@+id/note" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@android:color/transparent" android:gravity="top" android:hint="@string/hint_enter_note" android:inputType="textCapSentences|textMultiLine" android:lines="4" android:textColorHint="@color/hint_enter_note" android:textSize="@dimen/input_new_note" /> </LinearLayout>
11. activity_main.xml ve content_main.xml dosyalarını açın ve içerisine RecyclerView widgetini ekleyin.
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/coordinator_layout" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="info.androidhive.sqlite.view.MainActivity"> <android.support.design.widget.AppBarLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:theme="@style/AppTheme.AppBarOverlay"> <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" android:background="?attr/colorPrimary" app:popupTheme="@style/AppTheme.PopupOverlay" /> </android.support.design.widget.AppBarLayout> <include layout="@layout/content_main" /> <android.support.design.widget.FloatingActionButton android:id="@+id/fab" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="bottom|end" android:layout_margin="@dimen/fab_margin" app:srcCompat="@drawable/ic_add_white_24dp" /> </android.support.design.widget.CoordinatorLayout>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" app:layout_behavior="@string/appbar_scrolling_view_behavior" tools:context="info.androidhive.sqlite.view.MainActivity" tools:showIn="@layout/activity_main"> <android.support.v7.widget.RecyclerView android:id="@+id/recycler_view" android:layout_width="match_parent" android:layout_height="match_parent" /> <TextView android:id="@+id/empty_notes_view" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerHorizontal="true" android:layout_marginTop="@dimen/margin_top_no_notes" android:fontFamily="sans-serif-light" android:text="@string/msg_no_notes" android:textColor="@color/msg_no_notes" android:textSize="@dimen/msg_no_notes" /> </RelativeLayout>
12. Son olarak MainActivity.java sınıfını açıp aşağıdaki düzenlemeleri yapın;
- showNoteDialog() metodu yeni bir not girilmesi için dialog açmaktadır.
- createNote() veritabanına yeni kayıt eklenmesi ve eklenen yeni kaydın notların listelendiği arayüzde gözükmesini sağlamaktadır.
- showActionsDialog() fonksiyonu `Güncelle` ve `Sil` seçeneklerinin görüntülenmesini sağlamaktadır. Bu arayüze ulaşmak için listelemede bulunan notlardan herhangi birisine uzun süre basılı tutmanız gerekmektedir.
- Güncelle seçeneğine tıklanıldığında, tıklanılan notun text kısmı dialog içerisinde editlenecek şekilde görüntülenmektedir. updateNote() metodu çağrılarak, mevcut kaydın veritabanında güncellenmesi ve arayüze yansıması sağlanmaktadır.
- deleteNote() metodu veritabanında ilgili notun silinmesini sağlamaktadır. Listelemede görüntülenen kaydın silinmesi için adaptere ait notifyItemRemoved() metodunun çağrılması gerekmektedir.
- toggleEmptyNotes() metodu ise notların sayısına bağlı olarak eğer herhangi bir not bulunmuyorsa ona göre farklı bir arayüz gösterimine gidilmesini sağlamaktadır.
import android.content.DialogInterface; import android.os.Bundle; import android.support.design.widget.CoordinatorLayout; import android.support.design.widget.FloatingActionButton; import android.support.v7.app.AlertDialog; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.DefaultItemAnimator; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.Toolbar; import android.text.TextUtils; import android.view.LayoutInflater; import android.view.View; import android.widget.EditText; import android.widget.TextView; import android.widget.Toast; import java.util.ArrayList; import java.util.List; import info.androidhive.sqlite.R; import info.androidhive.sqlite.database.DatabaseHelper; import info.androidhive.sqlite.database.model.Note; import info.androidhive.sqlite.utils.MyDividerItemDecoration; import info.androidhive.sqlite.utils.RecyclerTouchListener; public class MainActivity extends AppCompatActivity { private NotesAdapter mAdapter; private ListBöylelikle SQLite kullanarak Android uygulamada basit bir not uygulaması hazırlanmış oldu.notesList = new ArrayList<>(); private CoordinatorLayout coordinatorLayout; private RecyclerView recyclerView; private TextView noNotesView; private DatabaseHelper db; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(toolbar); coordinatorLayout = findViewById(R.id.coordinator_layout); recyclerView = findViewById(R.id.recycler_view); noNotesView = findViewById(R.id.empty_notes_view); db = new DatabaseHelper(this); notesList.addAll(db.getAllNotes()); FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab); fab.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { showNoteDialog(false, null, -1); } }); mAdapter = new NotesAdapter(this, notesList); RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(getApplicationContext()); recyclerView.setLayoutManager(mLayoutManager); recyclerView.setItemAnimator(new DefaultItemAnimator()); recyclerView.addItemDecoration(new MyDividerItemDecoration(this, LinearLayoutManager.VERTICAL, 16)); recyclerView.setAdapter(mAdapter); toggleEmptyNotes(); recyclerView.addOnItemTouchListener(new RecyclerTouchListener(this, recyclerView, new RecyclerTouchListener.ClickListener() { @Override public void onClick(View view, final int position) { } @Override public void onLongClick(View view, int position) { showActionsDialog(position); } })); } private void createNote(String note) { // yeni not ekleyin long id = db.insertNote(note); // veritabanına eklenen yeni notun id bilgisini alın. Note n = db.getNote(id); if (n != null) { // listeye yeni not ekleyin notesList.add(0, n); // listelemeyi güncelleyin mAdapter.notifyDataSetChanged(); toggleEmptyNotes(); } } private void updateNote(String note, int position) { Note n = notesList.get(position); // notun text kısmını setleyin n.setNote(note); // notu veritabanında güncelleyin db.updateNote(n); // listeyi güncelleyin notesList.set(position, n); mAdapter.notifyItemChanged(position); toggleEmptyNotes(); } private void deleteNote(int position) { // veritabanından notu silin db.deleteNote(notesList.get(position)); // listeden notu kaldırın notesList.remove(position); mAdapter.notifyItemRemoved(position); toggleEmptyNotes(); } private void showActionsDialog(final int position) { CharSequence colors[] = new CharSequence[]{"Güncelle", "Sil"}; AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle("Seçeneği seçin"); builder.setItems(colors, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { if (which == 0) { showNoteDialog(true, notesList.get(position), position); } else { deleteNote(position); } } }); builder.show(); } private void showNoteDialog(final boolean shouldUpdate, final Note note, final int position) { LayoutInflater layoutInflaterAndroid = LayoutInflater.from(getApplicationContext()); View view = layoutInflaterAndroid.inflate(R.layout.note_dialog, null); AlertDialog.Builder alertDialogBuilderUserInput = new AlertDialog.Builder(MainActivity.this); alertDialogBuilderUserInput.setView(view); final EditText inputNote = view.findViewById(R.id.note); TextView dialogTitle = view.findViewById(R.id.dialog_title); dialogTitle.setText(!shouldUpdate ? getString(R.string.lbl_new_note_title) : getString(R.string.lbl_edit_note_title)); if (shouldUpdate && note != null) { inputNote.setText(note.getNote()); } alertDialogBuilderUserInput .setCancelable(false) .setPositiveButton(shouldUpdate ? "güncelle" : "kaydet", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialogBox, int id) { } }) .setNegativeButton("iptal", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialogBox, int id) { dialogBox.cancel(); } }); final AlertDialog alertDialog = alertDialogBuilderUserInput.create(); alertDialog.show(); alertDialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // Herhangi bir not girilmediğinde hata mesajının gösterilmesi if (TextUtils.isEmpty(inputNote.getText().toString())) { Toast.makeText(MainActivity.this, "Not Girin!", Toast.LENGTH_SHORT).show(); return; } else { alertDialog.dismiss(); } // eğer kullanıcı notlarda güncelleme yapıyorsa if (shouldUpdate && note != null) { // kayıtlı notu id verisi ile güncellemek updateNote(inputNote.getText().toString(), position); } else { // yeni not oluşturma createNote(inputNote.getText().toString()); } } }); } /** * Eğer kayıtlı not bulunmuyorsa layout değişikliğinin sağlanması */ private void toggleEmptyNotes() { if (db.getNotesCount() > 0) { noNotesView.setVisibility(View.GONE); } else { noNotesView.setVisibility(View.VISIBLE); } } }