Android Studio Hedgehog | 2023.1.1
Note: For personal reference using SearchView, Filter (text), SQLiteOpenHelper, RecyclerView and Fragment
Create new Project (No Activity)
Name CA Price List
Package Name com.dedetok.capricelist
Create Activity -> Empty View Activity
Activity Name: Main Activity
Layout Name activity_main
Laucher Activity checked
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<!-- for >= android 6 api level 23 -->
<uses-permission-sdk-23 android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission-sdk-23 android:name="android.permission.READ_EXTERNAL_STORAGE" />
<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.CAPriceList"
tools:targetApi="31">
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
build.gradle.kts(Module :app)
plugins {
id("com.android.application")
}
android {
namespace = "com.dedetok.capricelist"
compileSdk = 34
defaultConfig {
applicationId = "com.dedetok.capricelist"
minSdk = 24
targetSdk = 34
versionCode = 1
versionName = "1.0"
,,,
Resource -> Values -> strings.xml
<resources>
<string name="app_name">CA Price List</string>
<string name="t_cancel">Cancel</string>
<string name="t_save">Save</string>
<string name="t_delete">Delete</string>
<string name="t_product_name">Product Name</string>
<string name="t_product_price">Product Price</string>
<string name="t_product_code">Product Code</string>
<string name="t_product_id">Product ID</string>
<string name="t_new_product">New Product</string>
</resources>
Menu
my_menu.xml
<?xml version="1.0" encoding="utf-8"?>
<menu
xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id = "@+id/menu_add_pricelist"
android:title="@string/t_new_product"
/>
</menu>
Layout
layout_price_list.xml
<?xml version="1.0" encoding="utf-8"?>
<TextView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:id="@+id/pricelist_item"
android:minHeight="48dp"
android:layout_margin="5dp"
>
</TextView>
layout_fragment_list.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
>
<SearchView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/sv_text"
/>
<androidx.recyclerview.widget.RecyclerView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/my_recycler_view"
android:scrollbars="vertical"
/>
</LinearLayout>
layout_fragment_detail.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:id="@+id/product_id"
android:text="@string/t_product_id"
android:layout_margin="15dp"
/>
<EditText
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:id="@+id/product_name"
android:minHeight="48dp"
android:hint="@string/t_product_name"
android:autofillHints="@string/t_product_name"
android:inputType="text"
android:layout_margin="15dp"
/>
<EditText
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:id="@+id/product_price"
android:minHeight="48dp"
android:autofillHints="@string/t_product_price"
android:hint="@string/t_product_price"
android:inputType="text"
android:layout_margin="15dp"
/>
<EditText
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:id="@+id/product_code"
android:minHeight="48dp"
android:autofillHints="@string/t_product_code"
android:hint="@string/t_product_code"
android:inputType="text"
android:layout_margin="15dp"
/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_margin="15dp"
android:gravity="center_horizontal"
>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/t_cancel"
android:id="@+id/b_cancel_fragment_detail"
android:contentDescription="@string/t_cancel"
android:layout_margin="5dp"
/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/t_save"
android:id="@+id/b_save_fragment_detail"
android:contentDescription="@string/t_save"
android:layout_margin="5dp"
/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/t_delete"
android:id="@+id/b_delete_fragment_detail"
android:contentDescription="@string/t_delete"
android:layout_margin="5dp"
/>
</LinearLayout>
</LinearLayout>
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
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"
tools:context=".MainActivity">
<androidx.fragment.app.FragmentContainerView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/my_fragmentcontainerview"
android:scrollbars="vertical"
app:layoutManager="LinearLayoutManager"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
Create java package: New -> Packages : com.dedetok.capricelist.DBHelper
Java in com.dedetok.capricelist.DBHelper packages
PriceList.java
package com.dedetok.capricelist.DBHelper;
/*
* Table for price_list
*/
public class PriceList {
public static final String TABLENAME = "price_list";
/*
* column name and mapping
*/
// Primary Key
public static final String IDPRODUCT = "id_product";
public long idProduct;
public static final String NAMEPRODUCT = "name_product";
public String nameProduct;
public static final String PRICEPRODUCT = "price_product";
public String priceProduct;
public static final String CODEPRODUCT = "code_product";
public String codeProduct;
//debug
public String getText() {
return idProduct+" "+nameProduct+" "+priceProduct+" "+codeProduct;
}
}
MySQLiteHelper.java
package com.dedetok.capricelist.DBHelper;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import androidx.annotation.Nullable;
public class MySQLiteHelper extends SQLiteOpenHelper {
public static final int DATABASE_VERSION = 1;
public static final String DATABASE_NAME = "CAPriceList.db";
private static final String SQLCREATEDB = "create TABLE "+PriceList.TABLENAME +"(" +
PriceList.IDPRODUCT+ " INTEGER PRIMARY KEY AUTOINCREMENT," +
PriceList.NAMEPRODUCT+ " TEXT NOT NULL," +
PriceList.PRICEPRODUCT+ " TEXT NOT NULL," +
PriceList.CODEPRODUCT+ " Text);";
public MySQLiteHelper(@Nullable Context myAppContext, @Nullable String myDBName, @Nullable SQLiteDatabase.CursorFactory factory, int version) {
super(myAppContext, myDBName, factory, version);
}
/*
* Mandatory to create table
*/
@Override
public void onCreate(SQLiteDatabase sqLiteDatabase) {
sqLiteDatabase.execSQL(SQLCREATEDB);
}
@Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {
// TODO
}
}
BoyerMooreTextSearch.java -> fast match string better then indexOf() or contain()
package com.dedetok.capricelist.DBHelper;
public class BoyerMooreTextSearch {
/**
* https://en.wikipedia.org/wiki/Boyer%E2%80%93Moore_string-search_algorithm#Java_implementation
*
* Returns the index within this string of the first occurrence of the
* specified substring. If it is not a substring, return -1.
*
* There is no Galil because it only generates one match.
*
* @param haystack The string to be scanned
* @param needle The target string to search
* @return The start index of the substring
*/
public static int indexOf(char[] haystack, char[] needle) {
if (needle.length == 0) {
return 0;
}
int charTable[] = makeCharTable(needle);
int offsetTable[] = makeOffsetTable(needle);
for (int i = needle.length - 1, j; i < haystack.length;) {
for (j = needle.length - 1; needle[j] == haystack[i]; --i, --j) {
if (j == 0) {
return i;
}
}
// i += needle.length - j; // For naive method
i += Math.max(offsetTable[needle.length - 1 - j], charTable[haystack[i]]);
}
return -1;
}
/**
* Makes the jump table based on the mismatched character information.
*/
private static int[] makeCharTable(char[] needle) {
final int ALPHABET_SIZE = Character.MAX_VALUE + 1; // 65536
int[] table = new int[ALPHABET_SIZE];
for (int i = 0; i < table.length; ++i) {
table[i] = needle.length;
}
for (int i = 0; i < needle.length; ++i) {
table[needle[i]] = needle.length - 1 - i;
}
return table;
}
/**
* Makes the jump table based on the scan offset which mismatch occurs.
* (bad-character rule).
*/
private static int[] makeOffsetTable(char[] needle) {
int[] table = new int[needle.length];
int lastPrefixPosition = needle.length;
for (int i = needle.length; i > 0; --i) {
if (isPrefix(needle, i)) {
lastPrefixPosition = i;
}
table[needle.length - i] = lastPrefixPosition - i + needle.length;
}
for (int i = 0; i < needle.length - 1; ++i) {
int slen = suffixLength(needle, i);
table[slen] = needle.length - 1 - i + slen;
}
return table;
}
/**
* Is needle[p:end] a prefix of needle?
*/
private static boolean isPrefix(char[] needle, int p) {
for (int i = p, j = 0; i < needle.length; ++i, ++j) {
if (needle[i] != needle[j]) {
return false;
}
}
return true;
}
/**
* Returns the maximum length of the substring ends at p and is a suffix.
* (good-suffix rule)
*/
private static int suffixLength(char[] needle, int p) {
int len = 0;
for (int i = p, j = needle.length - 1;
i >= 0 && needle[i] == needle[j]; --i, --j) {
len += 1;
}
return len;
}
}
Java in com.dedetok.capricelist packages
DBCARepository.java
package com.dedetok.capricelist;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import com.dedetok.capricelist.DBHelper.MySQLiteHelper;
import com.dedetok.capricelist.DBHelper.PriceList;
import java.util.ArrayList;
// https://www.geeksforgeeks.org/singleton-class-in-android/
// https://www.androidcode.ninja/android-sqlite-transaction-tutorial/
public class DBCARepository {
private static MySQLiteHelper mySQLiteHelper = null;
// private static instance variable to hold the singleton instance
private static volatile DBCARepository myDBCARepository = null;
// private constructor to prevent instantiation of the class
private DBCARepository(Context appContext) {
if (mySQLiteHelper == null) {
mySQLiteHelper = new MySQLiteHelper(appContext,
MySQLiteHelper.DATABASE_NAME, null,
MySQLiteHelper.DATABASE_VERSION);
}
}
// public static method to retrieve the singleton instance
public static DBCARepository getInstance() {
return myDBCARepository;
}
public static void prepareDB(Context myAppContext) {
// Check if the instance is already created
if(myDBCARepository == null) {
// synchronize the block to ensure only one thread can execute at a time
synchronized (DBCARepository.class) {
// check again if the instance is already created
if (myDBCARepository == null) {
// create the singleton instance
myDBCARepository = new DBCARepository(myAppContext);
}
}
}
}
public ArrayList<PriceList> getPriceLists() {
// https://developer.android.com/training/data-storage/sqlite
SQLiteDatabase myDB = mySQLiteHelper.getReadableDatabase();
String[] projection = {
PriceList.IDPRODUCT, //0
PriceList.NAMEPRODUCT, //1
PriceList.PRICEPRODUCT, //2
PriceList.CODEPRODUCT //3
};
// Filter results WHERE "title" = 'My Title'
// String selection = FeedEntry.COLUMN_NAME_TITLE + " = ?";
String selection = null; // Not Used set null
// String[] selectionArgs = { "My Title" };
String[] selectionArgs = null; // Not used set null
// How you want the results sorted in the resulting Cursor
//String sortOrder =
// FeedEntry.COLUMN_NAME_SUBTITLE + " DESC";
String sortOrder = null; // Not used set null
Cursor cursor = myDB.query(
PriceList.TABLENAME,
projection, // The array of columns to return (pass null to get all)
selection, // The columns for the WHERE clause
selectionArgs, // The values for the WHERE clause
null, // don't group the rows
null, // don't filter by row groups
sortOrder // The sort order
);
ArrayList itemList = new ArrayList<>();
while(cursor.moveToNext()) {
PriceList mPriceList = new PriceList();
mPriceList.idProduct = cursor.getLong(0);
//Log.e("dedetok", Long.toString(cursor.getLong(0))); // debug
mPriceList.nameProduct = cursor.getString(1);
//Log.e("dedetok", cursor.getString(1)); // debug
mPriceList.priceProduct = cursor.getString(2);
mPriceList.codeProduct = cursor.getString(3);
itemList.add(mPriceList);
//Log.e("dedetok", "getPriceLists()"+ mPriceList.getText()); //debug
}
cursor.close();
myDB.close();
return itemList;
}
/*
* insert a new Price List, ID is auto number
*/
public long insertPriceList(PriceList newPriceList) {
//Log.e("dedetok", "DBACARepository insertPriceList get DB"); // debug
SQLiteDatabase myDB = mySQLiteHelper.getWritableDatabase();
ContentValues myContent = new ContentValues();
myContent.put(PriceList.NAMEPRODUCT, newPriceList.nameProduct);
myContent.put(PriceList.PRICEPRODUCT, newPriceList.priceProduct);
myContent.put(PriceList.CODEPRODUCT, newPriceList.codeProduct);
//Log.e("dedetok", "DBACARepository insertPriceList insert data"); // debug
long retValue = myDB.insert(PriceList.TABLENAME, null, myContent);
//Log.e("dedetok", "DBACARepository insertPriceList insert data result "+retValue); // debug
//Log.e("dedetok", "DBACARepository insertPriceList close db"); // debug
myDB.close();
return retValue;
}
// Save / update
/*
* To update price list after editing
*/
public int updatePriceList(PriceList myPriceList) {
SQLiteDatabase myDB = mySQLiteHelper.getWritableDatabase();
ContentValues myContent = new ContentValues();
myContent.put(PriceList.IDPRODUCT, myPriceList.idProduct);
myContent.put(PriceList.NAMEPRODUCT, myPriceList.nameProduct);
myContent.put(PriceList.PRICEPRODUCT, myPriceList.priceProduct);
myContent.put(PriceList.CODEPRODUCT, myPriceList.codeProduct);
// Filter results WHERE "title" = 'My Title'
// String selection = FeedEntry.COLUMN_NAME_TITLE + " = ?";
String selection = PriceList.IDPRODUCT + " = ?";
// String[] selectionArgs = { "My Title" };
String[] selectionArgs = {Long.toString(myPriceList.idProduct)}; // Not used set null
int retVal = myDB.update(PriceList.TABLENAME, myContent, selection, selectionArgs);
return retVal;
}
/*
* delete
*/
public int deletePriceList(PriceList myPriceList) {
SQLiteDatabase myDB = mySQLiteHelper.getWritableDatabase();
// Filter results WHERE "title" = 'My Title'
// String selection = FeedEntry.COLUMN_NAME_TITLE + " = ?";
String selection = PriceList.IDPRODUCT + " = ?";
// String[] selectionArgs = { "My Title" };
String[] selectionArgs = {Long.toString(myPriceList.idProduct)};
int retVal = myDB.delete(PriceList.TABLENAME, selection, selectionArgs);
return retVal;
}
}
PriceListsAdapter.java
package com.dedetok.capricelist;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Filter;
import android.widget.Filterable;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.fragment.app.FragmentActivity;
import androidx.recyclerview.widget.RecyclerView;
import com.dedetok.capricelist.DBHelper.BoyerMooreTextSearch;
import com.dedetok.capricelist.DBHelper.PriceList;
import java.util.ArrayList;
// https://developer.android.com/develop/ui/views/layout/recyclerview
public class PriceListsAdapter extends RecyclerView.Adapter implements Filterable {
// variable
private ArrayList<PriceList> myPriceListsFiltered;
private ArrayList<PriceList> myPriceListsOriginal;
/*
* construtor to initilize array list
*/
public PriceListsAdapter() {
myPriceListsOriginal = DBCARepository.getInstance().getPriceLists();
myPriceListsFiltered = myPriceListsOriginal;
}
/*
* mandatory extending RecyclerView.Adapter
* constructor
*/
@NonNull
@Override
public PriceListsAdapter.PriceListHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
// Create a new view, which defines the UI of the list item
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.layout_price_list, parent, false);
return new PriceListsAdapter.PriceListHolder (view);
}
/*
* mandatory extending RecyclerView.Adapter
*/
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
// Get element from your dataset at this position and replace the
// contents of the view with that element
PriceList myPriceList = myPriceListsFiltered.get(position);
String tmpString = Long.toString(myPriceList.idProduct)+" "+
myPriceList.nameProduct+" "+
myPriceList.priceProduct+" "+
myPriceList.codeProduct;
((PriceListHolder) holder).textView.setText(tmpString);
// https://www.geeksforgeeks.org/how-to-apply-onclicklistener-to-recyclerview-items-in-android/
holder.itemView.setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View view) {
PriceList mPriceList = myPriceListsFiltered.get(holder.getAdapterPosition());
FragmentDetail myFragmentDetail = new FragmentDetail(mPriceList);
((FragmentActivity) view.getContext()).getSupportFragmentManager().
beginTransaction().
replace(R.id.my_fragmentcontainerview, myFragmentDetail).
addToBackStack("List").
commit();
//Log.e("dedetok", "position "+ Integer.toString(holder.getAdapterPosition())); // debug
}
}
);
}
/*
* mandatory extending RecyclerView.Adapter
* return number of item on ArrayList<PriceList> myPriceLists
*/
@Override
public int getItemCount() {
return myPriceListsFiltered.size();
}
/*
* implements android.widget.Filterable;
* https://codingwithmitch.com/blog/filtering-recyclerview-searchview/
*/
@Override
public Filter getFilter() {
return new Filter() {
@Override
protected FilterResults performFiltering(CharSequence charSequence) {
String tmpPattern = charSequence.toString().toUpperCase();
if (tmpPattern.isEmpty()) {
myPriceListsFiltered = myPriceListsOriginal;
} else {
myPriceListsFiltered = new ArrayList<PriceList>();
for (PriceList myPriceList : myPriceListsOriginal) {
String tmpText = myPriceList.nameProduct.toUpperCase();
if (BoyerMooreTextSearch.indexOf(tmpText.toCharArray(), tmpPattern.toCharArray())> -1) {
myPriceListsFiltered.add(myPriceList);
}
}
}
FilterResults results = new FilterResults();
results.values = myPriceListsFiltered;
return results;
}
@Override
protected void publishResults(CharSequence charSequence, FilterResults results) {
myPriceListsFiltered = (ArrayList<PriceList>) results.values;
notifyDataSetChanged();
}
};
}
private class PriceListHolder extends RecyclerView.ViewHolder {
public TextView textView;
/*
* mandatory extends RecyclerView.ViewHolder
*/
public PriceListHolder(@NonNull View view) {
super(view);
textView = view.findViewById(R.id.pricelist_item);
}
}
}
FragmentDetail.java
package com.dedetok.capricelist;
import android.content.DialogInterface;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.Fragment;
import com.dedetok.capricelist.DBHelper.PriceList;
public class FragmentDetail extends Fragment {
PriceList myPriceList=null;
/*
* constructor to inflate fragment
*/
public FragmentDetail() {
super(R.layout.layout_fragment_detail);
}
public FragmentDetail(PriceList myPriceList) {
super(R.layout.layout_fragment_detail);
this.myPriceList = myPriceList;
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
// EditText
EditText etProductName = view.findViewById(R.id.product_name);
EditText etProductPrice = view.findViewById(R.id.product_price);
EditText etProductCode = view.findViewById(R.id.product_code);
if (myPriceList!=null) {
// if edit or delete data
TextView tvProductID = view.findViewById(R.id.product_id);
tvProductID.setText(myPriceList.codeProduct);
etProductName.setText(myPriceList.nameProduct);
etProductPrice.setText(myPriceList.priceProduct);
etProductCode.setText(myPriceList.codeProduct);
}
// button cancel
Button bCancelFragmentDetail = view.findViewById(R.id.b_cancel_fragment_detail);
bCancelFragmentDetail.setOnClickListener(cancelFragmentDetail -> getParentFragmentManager().popBackStack());
// button save
Button bSaveFragmentDetail = view.findViewById(R.id.b_save_fragment_detail);
bSaveFragmentDetail.setOnClickListener(saveFragmentDetail -> {
if (myPriceList ==null) {
// new data
//Log.e("dedetok", "FragmentDetail insert data"); //debug
PriceList newPriceList = new PriceList();
newPriceList.nameProduct = etProductName.getText().toString();
newPriceList.priceProduct = etProductPrice.getText().toString();
newPriceList.codeProduct = etProductCode.getText().toString();
DBCARepository.getInstance().insertPriceList(newPriceList);
//Log.e("dedetok", "FragmentDetail insert data end"); // debug
getParentFragmentManager().popBackStack();
} else {
// save existing data
myPriceList.nameProduct = etProductName.getText().toString();
myPriceList.priceProduct = etProductPrice.getText().toString();
myPriceList.codeProduct = etProductCode.getText().toString();
DBCARepository.getInstance().updatePriceList(myPriceList);
getParentFragmentManager().popBackStack();
}
});
// https://stackoverflow.com/questions/38411879/alert-confirmation-dialog-android
// https://stackoverflow.com/questions/10207206/how-to-display-alertdialog-in-a-fragment
Button bDeleteFragmentDetail = view.findViewById(R.id.b_delete_fragment_detail);
if (myPriceList == null) {
// new data, we don't have to delete
bDeleteFragmentDetail.setVisibility(View.INVISIBLE);
} else {
bDeleteFragmentDetail.setVisibility(View.VISIBLE);
bDeleteFragmentDetail.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
AlertDialog.Builder alert = new AlertDialog.Builder(getActivity());
alert.setTitle("Delete");
alert.setMessage("Are you sure you want to delete?");
alert.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
DBCARepository.getInstance().deletePriceList(myPriceList);
Log.e("dedetok", "deleted"); // debug
dialogInterface.dismiss();
}
});
alert.setNegativeButton("No", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
dialogInterface.dismiss();
}
});
alert.show();
}
});
}
}
}
FragmentList.java
package com.dedetok.capricelist;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.SearchView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
public class FragmentList extends Fragment {
/*
* constructor to inflate fragment
*/
public FragmentList() {
super(R.layout.layout_fragment_list);
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
//recyclerview
RecyclerView myRecyclerView = view.findViewById(R.id.my_recycler_view);
LinearLayoutManager myLinearLayout = new LinearLayoutManager(getActivity().getApplicationContext());
myLinearLayout.setOrientation(LinearLayoutManager.VERTICAL);
myRecyclerView.setLayoutManager(myLinearLayout);
PriceListsAdapter myPriceListAdapter = new PriceListsAdapter();
myRecyclerView.setAdapter(myPriceListAdapter);
// https://codingwithmitch.com/blog/filtering-recyclerview-searchview/
// SearchView
SearchView mySearchView = view.findViewById(R.id.sv_text);
// add listener for searchview
mySearchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String s) {
myPriceListAdapter.getFilter().filter(s);
return false;
}
@Override
public boolean onQueryTextChange(String s) {
myPriceListAdapter.getFilter().filter(s);
return false; }
});
}
}
MainActivity.java
package com.dedetok.capricelist;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Context;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// initialize database
Log.e("dedetok", "MainActivity OnCreate Initilize database"); // debug
DBCARepository.prepareDB(getApplicationContext());
Log.e("dedetok", "MainActivity OnCreate Initilize database end"); // debug
getSupportFragmentManager().beginTransaction().
add(R.id.my_fragmentcontainerview, FragmentList.class, null).
commit();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.my_menu, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId()==R.id.menu_add_pricelist) {
// open fragment Detail for new PriceList
getSupportFragmentManager().beginTransaction().
replace(R.id.my_fragmentcontainerview, FragmentDetail.class,null).
addToBackStack("List").
commit();
return true;
}
return super.onOptionsItemSelected(item);
}
}
NOTE: Some code may reference to other source code in comment (some has modified to make it run), do not remove urls if you wish to copy paste code and use the code.
No comments:
Post a Comment