The most powerful library in this case is ORMLite. It provides some simple, lightweight functionality for persisting Java objects to SQL databases while avoiding the complexity and overhead of more standard ORM packages. Moreover, it also solved well the problems concerning the relationship between the entities/tables.
Today, in this post, I would like to build a simple project which creating/managing a database with ORMLite, resolved entities relationships by ForeignCollection object. See this DEMO VIDEO for output:
This post is part of a series called Android TOP useful libraries
Before Start
- I have 2 POJOs: Cat and Kitten. ORMLite will persist theme to 2 corresponding tables.
- Relationship: Cat : Kitten = 1 : n.
Adding dependencies to app/build.gradle befor start coding:
compile 'com.j256.ormlite:ormlite-core:4.48'
compile 'com.j256.ormlite:ormlite-android:4.48'
- Project structure:Creating Database/Tables
package info.devexchanges.ormlite.model;
import com.j256.ormlite.dao.ForeignCollection;
import com.j256.ormlite.field.DatabaseField;
import com.j256.ormlite.field.ForeignCollectionField;
import java.util.ArrayList;
import java.util.List;
public class Cat {
@DatabaseField(generatedId=true)
private int id;
@DatabaseField (columnName = "name")
private String name;
@ForeignCollectionField
private ForeignCollection<Kitten> kittens;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void setKittens(ForeignCollection<Kitten> items) {
this.kittens = items;
}
public List<Kitten> getKittens() {
ArrayList<Kitten> itemList = new ArrayList<>();
for (Kitten item : kittens) {
itemList.add(item);
}
return itemList;
}
@Override
public String toString() {
return this.name;
}
}
package info.devexchanges.ormlite.model;
import com.j256.ormlite.field.DatabaseField;
public class Kitten {
@DatabaseField(generatedId=true)
private int id;
@DatabaseField (columnName = "name")
private String name;
@DatabaseField(foreign=true, foreignAutoRefresh=true)
private Cat cat;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Cat getCat() {
return cat;
}
public void setCat(Cat cat) {
this.cat = cat;
}
}
Building Database Helper and Controller classes
package info.devexchanges.ormlite.database;
import java.util.ArrayList;
import java.util.List;
import android.content.Context;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.util.Log;
import com.j256.ormlite.android.apptools.OrmLiteSqliteOpenHelper;
import com.j256.ormlite.dao.Dao;
import com.j256.ormlite.support.ConnectionSource;
import com.j256.ormlite.table.TableUtils;
import info.devexchanges.ormlite.model.Cat;
import info.devexchanges.ormlite.model.Kitten;
public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
// name of the database file for your application -- change to something appropriate for your app
private static final String DATABASE_NAME = "cat.db";
// any time you make changes to your database objects, you may have to increase the database version
private static final int DATABASE_VERSION = 1;
// the DAO object we use to access the SimpleData table
private Dao<Cat, Integer> catDAO = null;
private Dao<Kitten, Integer> kittenDAO = null;
public DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase database, ConnectionSource connectionSource) {
try {
TableUtils.createTable(connectionSource, Cat.class);
TableUtils.createTable(connectionSource, Kitten.class);
} catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException(e);
} catch (java.sql.SQLException e) {
e.printStackTrace();
}
}
@Override
public void onUpgrade(SQLiteDatabase db, ConnectionSource connectionSource, int oldVersion, int newVersion) {
try {
List<String> allSql = new ArrayList<>();
for (String sql : allSql) {
db.execSQL(sql);
}
} catch (SQLException e) {
Log.e(DatabaseHelper.class.getName(), "exception during onUpgrade", e);
throw new RuntimeException(e);
}
}
public Dao<Cat, Integer> getCatsDAO() {
if (catDAO == null) {
try {
catDAO = getDao(Cat.class);
} catch (java.sql.SQLException e) {
e.printStackTrace();
}
}
return catDAO;
}
public Dao<Kitten, Integer> getKittenDAO() {
if (kittenDAO == null) {
try {
kittenDAO = getDao(Kitten.class);
} catch (java.sql.SQLException e) {
e.printStackTrace();
}
}
return kittenDAO;
}
}
We need one more class that will encapsulate all the interactions with the DAO in the same package, let's create a basic code for it, and then we will add methods gradually as we need them in code. Through this class, define the way to display/update/delete table records/POJOs through DAO. In Activities/Adapter code, we will mainly work with this class:
package info.devexchanges.ormlite.database;
import android.content.Context;
import com.j256.ormlite.stmt.DeleteBuilder;
import java.sql.SQLException;
import java.util.ArrayList;
import info.devexchanges.ormlite.model.Cat;
import info.devexchanges.ormlite.model.Kitten;
public class DatabaseManager {
private static DatabaseManager instance;
private DatabaseHelper helper;
public static void init(Context ctx) {
if (null == instance) {
instance = new DatabaseManager(ctx);
}
}
static public DatabaseManager getInstance() {
return instance;
}
private DatabaseManager(Context ctx) {
helper = new DatabaseHelper(ctx);
}
public DatabaseHelper getHelper() {
return helper;
}
/**
* Get all customer in db
*
* @return
*/
public ArrayList<Cat> getAllCats() {
ArrayList<Cat> cats = null;
try {
cats = (ArrayList<Cat>) getHelper().getCatsDAO().queryForAll();
} catch (SQLException e) {
e.printStackTrace();
}
return cats;
}
public void addCat(Cat cat) {
try {
getHelper().getCatsDAO().create(cat);
} catch (SQLException e) {
e.printStackTrace();
}
}
public void refreshCat(Cat cat) {
try {
getHelper().getCatsDAO().refresh(cat);
} catch (SQLException e) {
e.printStackTrace();
}
}
public void updateCat(Cat wishList) {
try {
getHelper().getCatsDAO().update(wishList);
} catch (SQLException e) {
e.printStackTrace();
}
}
public void deleteCat (int catId) {
try {
DeleteBuilder<Cat, Integer> deleteBuilder = getHelper().getCatsDAO().deleteBuilder();
deleteBuilder.where().eq("id", catId);
deleteBuilder.delete();
} catch (SQLException e) {
e.printStackTrace();
}
}
public Kitten newKitten() {
Kitten kitten = new Kitten();
try {
getHelper().getKittenDAO().create(kitten);
} catch (SQLException e) {
e.printStackTrace();
}
return kitten;
}
public Kitten newKittenAppend(Kitten kitten) {
try {
getHelper().getKittenDAO().create(kitten);
} catch (SQLException e) {
e.printStackTrace();
}
return kitten;
}
public void updateKitten(Kitten item) {
try {
getHelper().getKittenDAO().update(item);
} catch (SQLException e) {
e.printStackTrace();
}
}
public ArrayList<Kitten> getAllKittens() {
ArrayList<Kitten> kittenArrayList = null;
try {
kittenArrayList = (ArrayList<Kitten>) getHelper().getKittenDAO().queryForAll();
} catch (SQLException e) {
e.printStackTrace();
}
return kittenArrayList;
}
public void deleteKitten (int kittenId) {
try {
DeleteBuilder<Kitten, Integer> deleteBuilder = getHelper().getKittenDAO().deleteBuilder();
deleteBuilder.where().eq("id", kittenId);
deleteBuilder.delete();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
Display data to Views
DatabaseManager.init(this);Get all tables records by DAO and save to ArrayList objects:
//get all data to Lists
ArrayList<Cat> catArrayList = DatabaseManager.getInstance().getAllCats();
No more specials, we have full code for main activity:
package info.devexchanges.ormlite.activity;
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ExpandableListView;
import android.widget.ProgressBar;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.List;
import info.devexchanges.ormlite.R;
import info.devexchanges.ormlite.adapter.ExpandableListAdapter;
import info.devexchanges.ormlite.database.DatabaseManager;
import info.devexchanges.ormlite.model.Cat;
import info.devexchanges.ormlite.model.Kitten;
public class MainActivity extends AppCompatActivity {
private ProgressBar progressBar;
private ExpandableListView listView;
private TextView notice;
private List<Cat> cats;
private ExpandableListAdapter adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DatabaseManager.init(this);
notice = (TextView)findViewById(R.id.notice);
listView = (ExpandableListView)findViewById(R.id.list_item);
progressBar = (ProgressBar)findViewById(R.id.progress);
cats = new ArrayList<>();
//set data to views
adapter = new ExpandableListAdapter(this, cats);
listView.setAdapter(adapter);
}
@Override
protected void onResume() {
super.onResume();
Log.d("Main", "resume");
getDataFromDB();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == R.id.add) {
Intent i = new Intent(this, AddingActivity.class);
startActivity(i);
return true;
}
return super.onOptionsItemSelected(item);
}
public void getDataFromDB() {
if (cats != null) cats.clear();
//get all data to Lists
ArrayList<Cat> catArrayList = DatabaseManager.getInstance().getAllCats();
for (int i = 0; i < catArrayList.size(); i++) {
cats.add(catArrayList.get(i));
}
if (cats.size() == 0) {
//no data in database
listView.setVisibility(View.GONE);
notice.setText("Database is Empty");
notice.setVisibility(View.VISIBLE);
} else {
adapter.notifyDataSetChanged();
}
}
}
Layout for this activity:
Adding new items
//save new object to db DatabaseManager.getInstance().addCat(cat);And add a Kitten is more complicate:
//save to database
DatabaseManager.getInstance().newKittenAppend(kitten);
DatabaseManager.getInstance().updateKitten(kitten);
This "adding items" process has been written in an activity, and this is full code for it:
package info.devexchanges.ormlite.activity;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.Spinner;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.List;
import info.devexchanges.ormlite.R;
import info.devexchanges.ormlite.database.DatabaseManager;
import info.devexchanges.ormlite.model.Cat;
import info.devexchanges.ormlite.model.Kitten;
public class AddingActivity extends AppCompatActivity {
private View btnAddCat;
private View btnAddKitten;
private View btnOK;
private Spinner spinner;
private ViewGroup layoutAddCat;
private ViewGroup layoutAddKitten;
private ViewGroup layoutButtons;
private EditText editCat;
private EditText editKitten;
private View btnCancel;
private List<Cat> cats;
private boolean havingCat = true;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_adding);
btnAddCat = findViewById(R.id.btn_add_cat);
btnOK = findViewById(R.id.btn_ok);
layoutAddKitten = (ViewGroup) findViewById(R.id.ll_kit);
layoutAddCat = (ViewGroup) findViewById(R.id.ll_cat);
layoutButtons = (ViewGroup) findViewById(R.id.ll_buttons);
btnCancel = findViewById(R.id.btn_cancel);
spinner = (Spinner) findViewById(R.id.spinner);
btnAddKitten = findViewById(R.id.btn_add_kitten);
editCat = (EditText) findViewById(R.id.txt_name);
editKitten = (EditText) findViewById(R.id.txt_kitten_name);
btnAddKitten.setOnClickListener(onAddKittenListener());
btnAddCat.setOnClickListener(onAddCatListner());
btnCancel.setOnClickListener(onCancelListener());
btnOK.setOnClickListener(onConfirmListener());
}
private View.OnClickListener onConfirmListener() {
return new View.OnClickListener() {
@Override
public void onClick(View v) {
if (layoutAddCat.getVisibility() == View.VISIBLE) {
if (editCat.getText().toString().trim().equals("")) {
Toast.makeText(getBaseContext(), "Please input cat name", Toast.LENGTH_SHORT).show();
} else {
Cat cat = new Cat();
cat.setName(editCat.getText().toString().trim());
//save new object to db
DatabaseManager.getInstance().addCat(cat);
}
} else if (layoutAddKitten.getVisibility() == View.VISIBLE) {
if (editKitten.getText().toString().trim().equals("")) {
Toast.makeText(getBaseContext(), "Please input kitten name", Toast.LENGTH_SHORT).show();
} else {
Kitten kitten = new Kitten();
Cat cat = (Cat) spinner.getSelectedItem();
kitten.setName(editKitten.getText().toString().trim());
kitten.setCat(cat);
//save to database
DatabaseManager.getInstance().newKittenAppend(kitten);
DatabaseManager.getInstance().updateKitten(kitten);
}
}
goneLayouts();
}
};
}
private View.OnClickListener onCancelListener() {
return new View.OnClickListener() {
@Override
public void onClick(View v) {
goneLayouts();
}
};
}
private View.OnClickListener onAddCatListner() {
return new View.OnClickListener() {
@Override
public void onClick(View v) {
goneLayouts();
layoutAddCat.setVisibility(View.VISIBLE);
layoutButtons.setVisibility(View.VISIBLE);
}
};
}
private View.OnClickListener onAddKittenListener() {
return new View.OnClickListener() {
@Override
public void onClick(View v) {
if (!havingCat) {
Toast.makeText(getBaseContext(), "None Cat in DB, please add cat first", Toast.LENGTH_SHORT).show();
} else {
goneLayouts();
cats = DatabaseManager.getInstance().getAllCats();
if (cats.size() == 0) {
havingCat = false;
} else {
//set spinner adapter
ArrayAdapter<Cat> adapter = new ArrayAdapter<>(AddingActivity.this,
android.R.layout.simple_dropdown_item_1line, cats);
spinner.setAdapter(adapter);
}
layoutAddKitten.setVisibility(View.VISIBLE);
layoutButtons.setVisibility(View.VISIBLE);
}
}
};
}
private void goneLayouts() {
layoutAddCat.setVisibility(View.GONE);
layoutAddKitten.setVisibility(View.GONE);
layoutButtons.setVisibility(View.GONE);
editCat.setText("");
editKitten.setText("");
}
}
And it's layout:
Output for this screen:
Editing/Updating an item
private View.OnClickListener onEditCatListener(final Cat cat, final int position) {
return new View.OnClickListener() {
@Override
public void onClick(View view) {
AlertDialog.Builder alertDialog = new AlertDialog.Builder(activity);
alertDialog.setTitle("EDIT Cat");
alertDialog.setMessage("Please type a new cat name");
final EditText input = new EditText(activity);
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.MATCH_PARENT);
input.setLayoutParams(lp);
input.setText(cat.getName());
alertDialog.setView(input);
alertDialog.setPositiveButton("OK", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
//update database with new cat name
cat.setName(input.getText().toString().trim());
DatabaseManager.getInstance().updateCat(cat);
//update views
cats.get(position).setName(input.getText().toString().trim());
notifyDataSetChanged();
}
});
alertDialog.setNegativeButton("Cancel", null);
alertDialog.show();
}
};
}
private View.OnClickListener onEditKittenListener(final Kitten kitten, final int groupPos,
final int childPos) {
return new View.OnClickListener() {
@Override
public void onClick(View view) {
AlertDialog.Builder alertDialog = new AlertDialog.Builder(activity);
alertDialog.setTitle("EDIT Kitten");
alertDialog.setMessage("Please type a new kitten name");
final EditText input = new EditText(activity);
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.MATCH_PARENT);
input.setLayoutParams(lp);
input.setText(kitten.getName());
alertDialog.setView(input);
alertDialog.setPositiveButton("OK", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
//update database
kitten.setName(input.getText().toString().trim());
DatabaseManager.getInstance().updateKitten(kitten);
//update views
cats.get(groupPos).getKittens().get(childPos).setName(input.getText().toString());
notifyDataSetChanged();
}
});
alertDialog.setNegativeButton("Cancel", null);
alertDialog.show();
}
};
}
Output of this action:
Deleting an item
private View.OnClickListener onDeleteKittenListener(final int groupPosition, final int childPosition) {
return new View.OnClickListener() {
@Override
public void onClick(View view) {
AlertDialog.Builder alertDialog = new AlertDialog.Builder(activity);
alertDialog.setTitle("Delete?");
alertDialog.setMessage("Are you sure to delete?");
alertDialog.setPositiveButton("OK", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
//delete in database
DatabaseManager.getInstance().deleteKitten(getChild(groupPosition, childPosition).getId());
//update views
activity.getDataFromDB();
}
});
alertDialog.setNegativeButton("Cancel", null);
alertDialog.show();
}
};
}
private View.OnClickListener onDeleteCatListener(final int groupPosition) {
return new View.OnClickListener() {
@Override
public void onClick(View view) {
AlertDialog.Builder alertDialog = new AlertDialog.Builder(activity);
alertDialog.setTitle("Delete?");
alertDialog.setMessage("Are you sure to delete?");
alertDialog.setPositiveButton("OK", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
//delete in database
DatabaseManager.getInstance().deleteCat(getGroup(groupPosition).getId());
//update views
cats.remove(groupPosition);
notifyDataSetChanged();
}
});
alertDialog.setNegativeButton("Cancel", null);
alertDialog.show();
}
};
}
Output:Final code
package info.devexchanges.ormlite.adapter;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseExpandableListAdapter;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.TextView;
import java.util.List;
import info.devexchanges.ormlite.R;
import info.devexchanges.ormlite.activity.MainActivity;
import info.devexchanges.ormlite.database.DatabaseManager;
import info.devexchanges.ormlite.model.Cat;
import info.devexchanges.ormlite.model.Kitten;
public class ExpandableListAdapter extends BaseExpandableListAdapter {
private MainActivity activity;
private List<Cat> cats;
public ExpandableListAdapter(MainActivity context, List<Cat> rows) {
this.activity = context;
this.cats = rows;
}
@Override
public Kitten getChild(int groupPosition, int childPosititon) {
return this.cats.get(groupPosition).getKittens().get(childPosititon);
}
@Override
public long getChildId(int groupPosition, int childPosition) {
return childPosition;
}
@Override
public int getChildrenCount(int groupPosition) {
return getGroup(groupPosition).getKittens().size();
}
@Override
public Cat getGroup(int groupPosition) {
return this.cats.get(groupPosition);
}
@Override
public int getGroupCount() {
return cats.size();
}
@Override
public long getGroupId(int groupPosition) {
return groupPosition;
}
@Override
public View getChildView(int groupPosition, final int childPosition,
boolean isLastChild, View convertView, ViewGroup parent) {
ChildViewHolder holder;
LayoutInflater inflater = (LayoutInflater) activity.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
if (convertView == null) {
convertView = inflater.inflate(R.layout.layout_child_list, parent, false);
holder = new ChildViewHolder(convertView);
convertView.setTag(holder);
} else {
holder = (ChildViewHolder) convertView.getTag();
}
holder.textView.setText(getChild(groupPosition, childPosition).getName());
holder.btnEdit.setOnClickListener(onEditKittenListener(getChild(groupPosition, childPosition),
groupPosition, childPosition));
holder.btnDelete.setOnClickListener(onDeleteKittenListener(groupPosition, childPosition));
return convertView;
}
@Override
public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
HeaderViewHolder holder;
LayoutInflater inflater = (LayoutInflater) activity.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
if (convertView == null) {
convertView = inflater.inflate(R.layout.layout_header_list, parent, false);
holder = new HeaderViewHolder(convertView);
convertView.setTag(holder);
} else {
holder = (HeaderViewHolder) convertView.getTag();
}
holder.textView.setText(getGroup(groupPosition).getName());
holder.btnEdit.setOnClickListener(onEditCatListener(getGroup(groupPosition), groupPosition));
holder.btnDelete.setOnClickListener(onDeleteCatListener(groupPosition));
return convertView;
}
private View.OnClickListener onDeleteKittenListener(final int groupPosition, final int childPosition) {
return new View.OnClickListener() {
@Override
public void onClick(View view) {
AlertDialog.Builder alertDialog = new AlertDialog.Builder(activity);
alertDialog.setTitle("Delete?");
alertDialog.setMessage("Are you sure to delete?");
alertDialog.setPositiveButton("OK", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
//delete in database
DatabaseManager.getInstance().deleteKitten(getChild(groupPosition, childPosition).getId());
//update views
activity.getDataFromDB();
}
});
alertDialog.setNegativeButton("Cancel", null);
alertDialog.show();
}
};
}
private View.OnClickListener onDeleteCatListener(final int groupPosition) {
return new View.OnClickListener() {
@Override
public void onClick(View view) {
AlertDialog.Builder alertDialog = new AlertDialog.Builder(activity);
alertDialog.setTitle("Delete?");
alertDialog.setMessage("Are you sure to delete?");
alertDialog.setPositiveButton("OK", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
//delete in database
DatabaseManager.getInstance().deleteCat(getGroup(groupPosition).getId());
//update views
cats.remove(groupPosition);
notifyDataSetChanged();
}
});
alertDialog.setNegativeButton("Cancel", null);
alertDialog.show();
}
};
}
private View.OnClickListener onEditCatListener(final Cat cat, final int position) {
return new View.OnClickListener() {
@Override
public void onClick(View view) {
AlertDialog.Builder alertDialog = new AlertDialog.Builder(activity);
alertDialog.setTitle("EDIT Cat");
alertDialog.setMessage("Please type a new cat name");
final EditText input = new EditText(activity);
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.MATCH_PARENT);
input.setLayoutParams(lp);
input.setText(cat.getName());
alertDialog.setView(input);
alertDialog.setPositiveButton("OK", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
//update database with new cat name
cat.setName(input.getText().toString().trim());
DatabaseManager.getInstance().updateCat(cat);
//update views
cats.get(position).setName(input.getText().toString().trim());
notifyDataSetChanged();
}
});
alertDialog.setNegativeButton("Cancel", null);
alertDialog.show();
}
};
}
private View.OnClickListener onEditKittenListener(final Kitten kitten, final int groupPos,
final int childPos) {
return new View.OnClickListener() {
@Override
public void onClick(View view) {
AlertDialog.Builder alertDialog = new AlertDialog.Builder(activity);
alertDialog.setTitle("EDIT Kitten");
alertDialog.setMessage("Please type a new kitten name");
final EditText input = new EditText(activity);
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.MATCH_PARENT);
input.setLayoutParams(lp);
input.setText(kitten.getName());
alertDialog.setView(input);
alertDialog.setPositiveButton("OK", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
//update database
kitten.setName(input.getText().toString().trim());
DatabaseManager.getInstance().updateKitten(kitten);
//update views
cats.get(groupPos).getKittens().get(childPos).setName(input.getText().toString());
notifyDataSetChanged();
}
});
alertDialog.setNegativeButton("Cancel", null);
alertDialog.show();
}
};
}
@Override
public boolean hasStableIds() {
return false;
}
@Override
public boolean isChildSelectable(int groupPosition, int childPosition) {
return true;
}
private static class ChildViewHolder {
private TextView textView;
private View btnEdit;
private View btnDelete;
public ChildViewHolder(View v) {
textView = (TextView) v.findViewById(R.id.kitten_name);
btnEdit = v.findViewById(R.id.edit);
btnDelete = v.findViewById(R.id.delete);
}
}
private static class HeaderViewHolder {
private TextView textView;
private View btnEdit;
private View btnDelete;
public HeaderViewHolder(View v) {
btnDelete = v.findViewById(R.id.delete);
textView = (TextView) v.findViewById(R.id.cat_name);
btnEdit = v.findViewById(R.id.edit);
}
}
}
Now, adding some necessary files to comple our project:- ExpandableListView group layout, showing Cat name:
- ExpandableListView child layout, displaying Kitten name:
Main screen after app launching:
- Strings resource:









