In this second part of our series on how to build an Android Excel Converter app from scratch, we will focus on android contacts to Excel converter feature.
If you have not seen the first part of this series, I suggest you go through it. It details the scope of the project and step-by-step processes involved in creating an Android project from scratch.
Download the sample app example on the Google Play Store.
Android Contacts to Excel Feature
Converting Android contacts into Excel format involves transforming contact information from its original form into a structured and organised format.
Android contacts to excel converter feature helps app users to achieve the following on the app.
- Select any of your Android device contacts or all.
- Add the name of the Excel file you want to create.
- Click on the convert button to convert the selected contacts to Excel.
Android Contacts to Excel Converter Structure
To better understand what we will cover in this tutorial, I have listed the below topics for easy comprehension.
- Create an Option / Menu Page.
- Create a Contact Page.
- Open the Android device contact list using a thirty-party library.
- Display contact list in Android Recyclcerview.
- Select and deselect Android contacts.
- Convert selected contacts to Excel.
- View the created Excel view.
- Share and Export Excel File.
Now that we have explained what we will learn, we will create a new menu page for the app.
Create an Option / Menu Page
We will create a new Tabbed Activity page. The tabbed page will contain 2 Fragments.
- Features Page – List of all the formats to convert to Excel
- Spreadsheet Page – List of all the Excel files on your device.
Create a new Tabbed Activity page and use a name of your choice.
Page Name: HomeActivity.java
Open the activity page and paste the code below.
You can see from the code that Android Studio has generated most of the Tabbed code and the corresponding Fragment pages.
We have added two more methods on the page.
checkHardwarePermission()
– To check if Read and Write Permissions.- OverrideÂ
onBackPressed()
–Â add an option to close the app when the user clicks the back button three times.
public class HomeActivity extends AppCompatActivity implements BottomNavigationView.OnItemSelectedListener {
private ActivityHomeBinding binding;
private int backCounter = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivityHomeBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
BottomNavigationView navView = findViewById(R.id.nav_view);
// Passing each menu ID as a set of Ids because each
// menu should be considered as top level destinations.
AppBarConfiguration appBarConfiguration = new AppBarConfiguration.Builder(
R.id.navigation_home, R.id.navigation_dashboard, R.id.navigation_notifications)
.build();
NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment_activity_home);
NavigationUI.setupActionBarWithNavController(this, navController, appBarConfiguration);
NavigationUI.setupWithNavController(binding.navView, navController);
binding.navView.setOnItemSelectedListener(this);
}
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
int linkId = item.getItemId();
NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment_activity_home);
if(linkId == R.id.navigation_home){
navController.navigate(R.id.navigation_home);
}
if(linkId == R.id.navigation_dashboard){
navController.navigate(R.id.navigation_dashboard);
}
if(linkId == R.id.navigation_notifications){
navController.navigate(R.id.navigation_notifications);
}
return true;
}
@Override
public void onBackPressed() {
backCounter++;
if(backCounter < 3){
DisplayUtils.showToast(HomeActivity.this, backCounter + " you need 3 clicks to leave");
}else{
//super.onBackPressed();
Intent startMain = new Intent(Intent.ACTION_MAIN);
startMain.addCategory(Intent.CATEGORY_HOME);
startMain.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(startMain);
finish();
}
}
private void checkHardwarePermission(){
Dexter.withContext(HomeActivity.this)
.withPermissions(Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.READ_CONTACTS, Manifest.permission.WRITE_CONTACTS)
.withListener(new MultiplePermissionsListener() {
@Override
public void onPermissionsChecked(MultiplePermissionsReport report) {
if (!report.areAllPermissionsGranted()){
Toast.makeText(HomeActivity.this, "All permission is needed for the app to work well", Toast.LENGTH_SHORT).show();
}
}
@Override
public void onPermissionRationaleShouldBeShown(List<PermissionRequest> permissions, PermissionToken token) {
}
}).check();
}
}
Create activity_home.xml Layout File
The layout file is simple and does not need any explanation.
<?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"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:id="@+id/intro_page_overlay"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent">
<RelativeLayout
android:id="@+id/main_page_content"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="@+id/nav_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="0dp"
android:layout_marginEnd="0dp"
android:background="?android:attr/windowBackground"
android:layout_alignParentBottom="true"
app:menu="@menu/bottom_nav_menu" />
<fragment
android:id="@+id/nav_host_fragment_activity_home"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentTop="true"
app:defaultNavHost="true"
app:navGraph="@navigation/mobile_navigation" />
</RelativeLayout>
</FrameLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
Now that we have done with the Tabbed Page, we will move further to create the list of features the app will contain. We will add a RecyclerView to the fragment page layout file.
Create fragment_home.xml
Open the fragment_home.xml file, copy and paste the code below.
<?xml version="1.0" encoding="utf-8"?>
<androidx.appcompat.widget.LinearLayoutCompat 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"
android:orientation="vertical"
android:descendantFocusability="beforeDescendants"
android:focusableInTouchMode="true"
android:focusable="true"
android:background="#4C53B5"
android:paddingBottom="48dp"
tools:context=".ui.home.HomeFragment">
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="none">
<androidx.appcompat.widget.LinearLayoutCompat
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<androidx.appcompat.widget.LinearLayoutCompat
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="8dp"
android:orientation="horizontal">
<androidx.cardview.widget.CardView
android:layout_width="0dp"
android:layout_height="wrap_content"
app:cardElevation="3dp"
android:layout_weight="1"
android:layout_margin="12dp"
app:cardCornerRadius="4dp"
app:cardUseCompatPadding="true">
<androidx.appcompat.widget.LinearLayoutCompat
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="12dp"
android:gravity="center"
android:background="#DCEED1"
android:orientation="vertical">
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/contacts_to_excel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:drawableTop="@drawable/contactbook"
android:text="Contacts To Excel"
android:textStyle="bold"
android:textSize="13sp"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
android:drawablePadding="12dp"/>
</androidx.appcompat.widget.LinearLayoutCompat>
</androidx.cardview.widget.CardView>
<androidx.cardview.widget.CardView
android:layout_width="0dp"
android:layout_height="wrap_content"
app:cardElevation="3dp"
android:layout_weight="1"
android:layout_margin="12dp"
app:cardCornerRadius="4dp"
app:cardUseCompatPadding="true">
<androidx.appcompat.widget.LinearLayoutCompat
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="12dp"
android:gravity="center"
android:background="#ffe8d6"
android:orientation="vertical">
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/import_excel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:drawableTop="@drawable/downloadexcel"
android:text="Import Excel"
android:textStyle="bold"
android:textSize="13sp"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
android:drawablePadding="12dp"/>
</androidx.appcompat.widget.LinearLayoutCompat>
</androidx.cardview.widget.CardView>
</androidx.appcompat.widget.LinearLayoutCompat>
<View
android:layout_width="match_parent"
android:layout_height="3dp"
android:background="#b388eb"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="18dp"/>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/excel_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginStart="12dp"
android:layout_marginEnd="12dp"
android:layout_marginBottom="12dp"/>
</androidx.appcompat.widget.LinearLayoutCompat>
</androidx.core.widget.NestedScrollView>
</androidx.appcompat.widget.LinearLayoutCompat>
HomeFragment.java Page
We will get the instances of the UI Views we add in the fragment_home.xml layout file.
For the RecyclerView adapter, we will use a third-party library named SmartRecyclerAdapter. Add the code to your project build.gradle file.
implementation 'io.github.manneohlund:smart-recycler-adapter:3.0.0'
With the RecyclerView adapter added, we will create a model class and a ViewHolder class. The adapter class uses these classes to populate and manage our RecyclerView.
Open the HomeFragment file and add the below code to it.
public class HomeFragment extends Fragment {
@BindView(R.id.excel_list)
RecyclerView excelList;
private SmartRecyclerAdapter smartRecyclerAdapter;
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.fragment_home, container, false);
ButterKnife.bind(this, root);
List<ExcelModel> data = DataUtils.getConversionTypes();
setUpConverterTypes(data);
return root;
}
public void setUpConverterTypes(List<ExcelModel> excelConversionTypesDataList){
smartRecyclerAdapter = SmartRecyclerAdapter
.items(excelConversionTypesDataList)
.map(ExcelModel.class, ExcelViewHolder.class)
.setLayoutManager(new GridLayoutManager(requireActivity(), 2))
.addViewEventListener((OnConvertFileListener) (view, actionId, position) -> {
ExcelModel excelModel = (ExcelModel) excelConversionTypesDataList.get(position);
String param = excelModel.getExt();
List<String> imageExtList = Arrays.asList("jpg","jpeg","png");
if(imageExtList.contains(param)){
//this.navigateToImage();
this.openImagePicker();
}else if(param == "table"){
this.navigateToTable();
}else {
this.pageNavigation(excelModel);
}
})
.into(excelList);
}
private void openImagePicker() {
String[] mimeTypes = {"image/*"};
Intent imagePickerIntent = new Intent(Intent.ACTION_GET_CONTENT);
imagePickerIntent.addCategory(Intent.CATEGORY_OPENABLE);
imagePickerIntent.setDataAndType(Uri.parse(Environment.getExternalStorageDirectory().getPath()+ File.separator), "*/*");
imagePickerIntent.setType("*/*");
imagePickerIntent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
imagePickerIntent.putExtra("multi-pick", true);
imagePickerIntent.putExtra(Intent.EXTRA_MIME_TYPES, mimeTypes);
imagePickerActivityResultLauncher.launch(imagePickerIntent);
Bungee.slideLeft(requireActivity());
}
ActivityResultLauncher<Intent> imagePickerActivityResultLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), result -> {
if(result.getResultCode() == Activity.RESULT_OK){
if(result.getData() != null){
ExtractImageText extractImageText = new ExtractImageText(requireActivity(), result.getData().getData());
extractImageText.processImageTextExtraction((success, extractedImage) -> {
DisplayUtils.showToast(requireActivity(),"Hello "+success+" "+extractedImage);
});
}
}
});
private void navigateToImage(){
Intent dbIntent = new Intent(requireActivity(), DatabaseActivity.class);
startActivity(dbIntent);
Bungee.slideLeft(requireActivity());
}
private void navigateToTable(){
Intent tableIntent = new Intent(requireActivity(), TableActivity.class);
startActivity(tableIntent);
Bungee.slideLeft(requireActivity());
}
private void pageNavigation(ExcelModel excelModel){
String excelModelString = new Gson().toJson(excelModel);
Intent extIntent = new Intent(requireActivity(), ListDeviceFileActivity.class);
extIntent.putExtra(AppConstants.EXCEL_CONVERSION_TYPES_OBJECT, excelModelString);
startActivity(extIntent);
Bungee.slideLeft(requireActivity());
}
@OnClick(R.id.contacts_to_excel)
public void readDeviceContact(View view){
Intent contactIntent = new Intent(requireActivity(), ContactToExcelActivity.class);
startActivity(contactIntent);
Bungee.slideLeft(requireActivity());
}
@OnClick(R.id.import_excel)
public void readExcelFile(View view){
Intent importIntent = new Intent(requireActivity(), ImportExcelActivity.class);
startActivity(importIntent);
Bungee.slideLeft(requireActivity());
}
}
Create ExcelModel Class
Now that we have added classes that do not exist yet, Android Studio will use a red line to highlight them. First, we will create a model class.
I will name the model ExcelModel. Feel free to choose a name of your choice. Open the create file and paste the code below.
public class ExcelModel {
private String conversionName;
private String ext;
private int conversionIcon;
public ExcelModel(String conversionName, int conversionIcon) {
this("", conversionName, conversionIcon);
}
public ExcelModel(String ext, String conversionName, int conversionIcon) {
this.ext = ext;
this.conversionName = conversionName;
this.conversionIcon = conversionIcon;
}
public String getConversionName() {
return conversionName;
}
public void setConversionName(String conversionName) {
this.conversionName = conversionName;
}
public int getConversionIcon() {
return conversionIcon;
}
public void setConversionIcon(int conversionIcon) {
this.conversionIcon = conversionIcon;
}
public String getExt() { return ext; }
public void setExt(String ext) { this.ext = ext; }
}
Create a ViewHolder Class
Create a ViewHolder class and use a name of your choice. I will use ExcelViewHolder.java.
This class will contain instances of two Views that appear in each RecyclerView item. We will create the layout file soon.
Open the ViewHolder class and paste the code below.
public class ExcelViewHolder extends SmartViewHolder<ExcelModel> {
private static final String TAG = ExcelViewHolder.class.getSimpleName();
@BindView(R.id.conversion_name)
AppCompatTextView conversionName;
@BindView(R.id.conversion_icon)
AppCompatImageView conversionIcon;
public ExcelViewHolder(ViewGroup parentView) {
super(LayoutInflater.from(parentView.getContext()).inflate(R.layout.convert_file_type_layout, parentView, false));
ButterKnife.bind(this, itemView);
}
@Override
public void bind(ExcelModel item) {
conversionName.setText(item.getConversionName());
conversionIcon.setImageResource(item.getConversionIcon());
}
}
You can see from the code that it reference a layout file.
R.layout.convert_file_type_layout
Create a new layout file and name it convert_file_type_layout.xml file.
Open the layout file and add the code below it.
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/card_wrapper"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:cardElevation="4dp"
app:cardCornerRadius="8dp"
app:cardUseCompatPadding="true">
<androidx.appcompat.widget.LinearLayoutCompat
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingTop="30dp"
android:paddingBottom="30dp"
android:paddingStart="20dp"
android:paddingEnd="20dp"
android:gravity="center">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/conversion_icon"
android:layout_width="64dp"
android:layout_height="64dp"
android:scaleType="centerCrop"
android:src="@drawable/excel"
android:layout_marginEnd="5dp"/>
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/conversion_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="PDF 2 Excel"
android:textStyle="bold"
android:textColor="#444444"
android:textSize="12sp"
android:layout_marginTop="18dp"/>
</androidx.appcompat.widget.LinearLayoutCompat>
</androidx.cardview.widget.CardView>
RecyclerView Item Click Event
We have just concluded the first part of this tutorial. If you compile your code and run it, you will see a UI similar to the screenshot below.
— Screen Shoot —
We have already added a click event listener when we worked on the HomeFragment class. Below is the code to refresh your mind.Â
@OnClick(R.id.contacts_to_excel)
public void readDeviceContact(View view){
Intent contactIntent = new Intent(requireActivity(), ContactToExcelActivity.class);
startActivity(contactIntent);
Bungee.slideLeft(requireActivity());
}
Clicking the Contact menu will navigate the user to a new page that lists all the contacts on the user’s device.
Create ContactToExcelActivity Page
We will create a new Activity page that will list our device contacts. Name this file ContactToExcelActivity.java
or any name of your choice.
We will add a RecyclerView in the layout file. Each item in the RecyclerView will contain a TextView, which will hold the contact information and a Checkbox. The checkbox toggles to select or unselect a list of contacts to convert to Excel.
Open the new activity page and paste the code below.
public class ContactToExcelActivity extends AppCompatActivity implements Ads.IAdCallback {
private String TAG = ContactToExcelActivity.class.getSimpleName();
@BindView(R.id.contact_list)
RecyclerView contactList;
@BindView(R.id.contact_total)
AppCompatTextView contactTotal;
private SmartRecyclerAdapter smartRecyclerAdapter;
private ContactData contactData;
private List<ContactExcelModel> allContacts;
private Spinning spanning;
private String selectedExcelExtension = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_contact_to_excel);
setTitle("Contact To Excel");
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
ButterKnife.bind(this);
spanning = new Spinning(this);
spanning.show();
contactData = new ContactData(this);
this.setupContactList();
spanning.hide();
}
private List<ContactExcelModel> fetchData(){
List<Contact> contacts = Contacts.getQuery().find();
List<ContactExcelModel> data = new ArrayList<>();
Map<String, ContactExcelModel> dataStore = new HashMap<>();
for (Contact contact : contacts) {
String firstName = contact.getGivenName();
String lastName = contact.getDisplayName();
Long id = contact.getId();
String phone = "";
for(PhoneNumber nums : contact.getPhoneNumbers()){
phone += nums.getNumber() + " ";
}
String email = "";
for(Email emailContact : contact.getEmails()){
email += emailContact + " ";
}
String birthday = "";
if(contact.getBirthday() != null){
birthday = contact.getBirthday().getStartDate();
}
if(phone != null || !phone.isEmpty()){
if(firstName == null || firstName.isEmpty()){
firstName = "No name";
}
if(!dataStore.containsKey(phone)){
dataStore.put(phone, new ContactExcelModel(id, firstName, lastName, phone, email, birthday));
}
}
}
for (Map.Entry<String, ContactExcelModel> entry : dataStore.entrySet()) {
data.add(entry.getValue());
}
return data;
}
private void setupContactList(){
allContacts = this.fetchData();
if(allContacts != null){
int total = allContacts.size();
contactTotal.setText("Total Contacts: " + String.valueOf(total));
}
smartRecyclerAdapter = SmartRecyclerAdapter
.items(allContacts)
.map(ContactExcelModel.class, ContactExcelViewHolder.class)
.setLayoutManager(new LinearLayoutManager(this))
.addViewEventListener((OnContactSelected) (view, actionId, position) -> {
ContactExcelModel objType = (ContactExcelModel) allContacts.get(position);
boolean selectBox = ((AppCompatCheckBox)view).isChecked();
if(selectBox){
contactData.addContact(objType);
}else{
contactData.removeContact(objType);
}
contactData.getContacts();
})
.into(contactList);
}
private void unSelectAll(){
contactData.clearAll();
for(ContactExcelModel ceModel : allContacts){
ceModel.setChecked(false);
contactData.addContact(ceModel);
}
smartRecyclerAdapter.smartNotifyDataSetChanged();
}
private void selectAll(){
contactData.clearAll();
for(ContactExcelModel ceModel : allContacts){
ceModel.setChecked(true);
contactData.addContact(ceModel);
}
smartRecyclerAdapter.smartNotifyDataSetChanged();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.contact_menu_option, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
int menuId = item.getItemId();
if(menuId == android.R.id.home){
onBackPressed();
}
if(menuId == R.id.nav_select){
this.selectAll();
contactData.getContacts();
}
if(menuId == R.id.nav_unselect){
this.unSelectAll();
contactData.getContacts();
}
return super.onOptionsItemSelected(item);
}
@Override
public void onBackPressed() {
super.onBackPressed();
Bungee.slideRight(this);
}
@OnClick(R.id.contacts_to_excel_btn)
public void onClickView(){
DisplayUtils.showExcelExtensionPicker(ContactToExcelActivity.this, (view, position, id, item) -> {
selectedExcelExtension = item.toString();
}, view -> {
if(selectedExcelExtension == null){
DisplayUtils.showToast(ContactToExcelActivity.this, "Please select excel extension");
}else{
convertContactToExcel();
}
});
}
private void convertContactToExcel(){
if(spanning != null){
spanning.show();
}
MapWrapper mapWrapper = new MapWrapper();
Map<Long, ContactExcelModel> selectedContact = contactData.getContacts();
Map<Integer, Object[]> excelData = mapWrapper.contactToExcel(selectedContact);
// convert data to excel
CreateExcel createExcel = new CreateExcel(ContactToExcelActivity.this, excelData);
StorageUtil store = new StorageUtil(ContactToExcelActivity.this);
String folderPath = store.createFileStorageFolder("CreateExcel");
String filePath = folderPath + File.separator + "contact_" + System.currentTimeMillis() + "."+selectedExcelExtension;
Uri uri = Uri.fromFile(new File(filePath));
createExcel.setUri(uri);
createExcel.createNewExcelFile();
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
if(spanning != null){
spanning.hide();
}
}
}, 2000);
}
private void gotoViewExcel(String excelObjString){
Intent excelIntent = new Intent(ContactToExcelActivity.this, ViewExcelActivity.class);
excelIntent.putExtra("EXCEL_OBJ", excelObjString);
excelIntent.putExtra("IS_PATH", "true");
startActivity(excelIntent);
Bungee.slideLeft(ContactToExcelActivity.this);
}
}
There is a lot to take from the code. Below is a simple explanation to help you understand it better.
- We have used a third-party Contact Picker plugin. Add the below line of code to your project build.gradle file.
implementation 'com.github.tamir7.contacts:contacts:1.1.7'
- The RecyclerView will list all the contacts on the user’s device.
- The checkbox toggles the select and unselect states of each item of the contacts.
- Other utility classes like StorageUtil, CreateExcel and more are add to clean up the code.
Create the activity_contact_to_excel.xml layout file
Open the layout file for the activity page and paste the code below.
<?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=".ui.home.contacts.ContactToExcelActivity">
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/contact_notice"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:gravity="center"
android:padding="24dp"
android:text="Select the contact(s) that will be added to excel"
android:textSize="13sp"
android:background="@color/notice" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/contact_total"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/contact_notice"
android:gravity="center"
android:padding="12dp"
android:text="Total Contacts : 220"
android:textStyle="bold"
android:textColor="@color/black"
android:textSize="13sp" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/contact_list"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/contact_total"
app:layout_constraintBottom_toTopOf="@id/card_bottom"
android:layout_margin="8dp"
android:scrollbars="none"/>
<androidx.cardview.widget.CardView
android:id="@+id/card_bottom"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:cardCornerRadius="8dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@id/contact_list"
android:layout_marginStart="18dp"
android:layout_marginBottom="18dp"
android:layout_marginEnd="18dp"
android:layout_marginTop="4dp"
android:elevation="3dp">
<androidx.appcompat.widget.AppCompatButton
android:id="@+id/contacts_to_excel_btn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/background"
android:textColor="@color/white"
android:text="convert to excel"/>
</androidx.cardview.widget.CardView>
</androidx.constraintlayout.widget.ConstraintLayout>
Create the Contact List Model Class
Create a new model class and name it ContactExcelModel
. Open the new file and add the code below.
public class ContactExcelModel {
private Long id;
private String firstName;
private String lastName;
private String phone;
private String email;
private String birthday;
private boolean isChecked = false;
public ContactExcelModel(Long id, String firstName, String lastName, String phone, String email, String birthday) {
this.id = id;
this.firstName = firstName;
this.lastName = lastName;
this.phone = phone;
this.email = email;
this.birthday = birthday;
}
public String getFullName(){
return this.firstName + " " + this.lastName;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getBirthday() {
return birthday;
}
public void setBirthday(String birthday) {
this.birthday = birthday;
}
public boolean isChecked() {
return this.isChecked;
}
public void setChecked(boolean checked) {
this.isChecked = checked;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
}
Create the Contact List ViewHolder Class
Create a new ViewHolder class and name it ContactExcelViewHolder
. Open the new file and add the code below.
public class ContactExcelViewHolder extends SmartViewHolder<ContactExcelModel> {
private String TAG = ContactExcelViewHolder.class.getSimpleName();
@BindView(R.id.contact_fullname)
AppCompatTextView fullName;
@BindView(R.id.contact_phone)
AppCompatTextView phone;
@BindView(R.id.is_selected)
AppCompatCheckBox selectContact;
public ContactExcelViewHolder(ViewGroup parentView) {
super(LayoutInflater.from(parentView.getContext()).inflate(R.layout.contact_item_view_layout, parentView, false));
ButterKnife.bind(this, itemView);
}
@Override
public void bind(ContactExcelModel item) {
fullName.setText(item.getLastName());
phone.setText(item.getPhone());
selectContact.setChecked(item.isChecked());
}
@Override
public void unbind() {
super.unbind();
}
}
Create the ViewHolder Layout File
Create a new layout file and name it contact_item_view_layout.xml
. Open the new file and paste the code below.
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:elevation="4dp"
android:layout_marginBottom="2dp"
app:cardUseCompatPadding="true">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="12dp">
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/contact_fullname"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
android:textSize="14sp"
app:layout_constraintEnd_toStartOf="@id/is_selected"
app:layout_constraintTop_toTopOf="parent"
android:text="Developer Account"
android:textStyle="bold"/>
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/contact_phone"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="13sp"
android:layout_marginTop="4dp"
app:layout_constraintTop_toBottomOf="@+id/contact_fullname"
app:layout_constraintStart_toStartOf="parent"
android:text="079393987"
android:textStyle="bold"/>
<androidx.appcompat.widget.AppCompatCheckBox
android:id="@+id/is_selected"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:checked="false"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.cardview.widget.CardView>
This marks the end of the part 2 tutorial. It is long because we have to create some rudimental page.
In the next part of the series on how to create an Android app from scratch, we will cover how to import an Excel file and convert it into a table.
If you have any questions or suggestions with this tutorial, kindly use the comment box to contact us.