How to Build a Barcode Scanner Invoice Generator App in Android Java

Introduction

In this tutorial, we will explore how to develop a Barcode Scanner Invoice Generator App in Android Java that allows users to scan barcodes, add products to a list, and generate a PDF invoice. This app is ideal for small businesses or retail stores that need a quick and efficient way to manage transactions. By the end of this guide, you’ll be able to build a fully functional barcode scanner invoice generator app using modern Android development tools.


Prerequisites

Before getting started, ensure you have the following:

  • Android Studio installed
  • Basic knowledge of Java/Kotlin
  • Dependencies for barcode scanning and PDF generation

Step 1: Adding Dependencies

To enable barcode scanning and PDF generation, add the following dependencies to your build.gradle file:

implementation 'com.google.mlkit:barcode-scanning:17.2.0'
implementation 'com.itextpdf:itext7-core:7.1.15'

Step 2: Implement Barcode Scanner

To scan barcodes, use the Google ML Kit. Integrate the camera preview and process the scanned barcode:

BarcodeScannerOptions options =
    new BarcodeScannerOptions.Builder()
        .setBarcodeFormats(Barcode.FORMAT_ALL_FORMATS)
        .build();

BarcodeScanner scanner = BarcodeScanning.getClient(options);

Once a barcode is scanned, retrieve the product details and add them to a list.


Step 3: Displaying Items in RecyclerView

Create a RecyclerView adapter to show scanned products dynamically:

public class ProductAdapter extends RecyclerView.Adapter<ProductAdapter.ViewHolder> {
    private List<Product> productList;
    
    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
        Product product = productList.get(position);
        holder.name.setText(product.getName());
        holder.price.setText(String.valueOf(product.getPrice()));
    }
}

Step 4: Generating a PDF Invoice

Use iText7 to create a PDF file containing the product details and save it to device storage:

PdfWriter writer = new PdfWriter(filePath);
PdfDocument pdfDoc = new PdfDocument(writer);
Document document = new Document(pdfDoc);
document.add(new Paragraph("Invoice"));

for (Product product : productList) {
    document.add(new Paragraph(product.getName() + " - " + product.getPrice()));
}
document.close();

Complete Code Here


1. MainActivity.java


public class MainActivity extends AppCompatActivity {

    Button btnCreatePDf;
    Bitmap bitmap, scaledBitmap;
    EditText etCustomerName;
    private final String[] informationArray = new String[]{"Name", "Company Name", "Address", "Phone", "Email"};

    private int srNumber;
    String ItemName, price, Quantity, priceTotal;


    private RecyclerView recyclerView;

    private MyAdapter adapter;
    private final List listItem = new ArrayList<>();
    private final List fullCodeList = new ArrayList<>();


    private static final int CAMERA_PERMISSION_REQUEST_CODE = 200;


    private DecoratedBarcodeView barcodeView;

    private final Map<String, String> map = new HashMap<>();

    int startingIndex = 5;
    String copyDecodeText;
    int yAxisForValue = 280;
    private List totalPricePerItemList = new ArrayList<>();
    private String customerName;

    String pattern = "^[-+]?[\\d&]*\\.?\\d+$";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        EdgeToEdge.enable(this);
        setContentView(R.layout.activity_main);
        ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {
            Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
            v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
            return insets;
        });
        etCustomerName = findViewById(R.id.etCustomerName);
        btnCreatePDf = findViewById(R.id.btnNext);
        bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.logo_2);

        recyclerView = findViewById(R.id.myRecyclerView);
        barcodeView = findViewById(R.id.zxingBarcodeScanner);
        barcodeView.setStatusText("");

        recyclerView.setLayoutManager(new LinearLayoutManager(this));
        adapter = new MyAdapter(this, listItem, (position, quantity) -> {
            listItem.get(position).setItemQuantity(quantity);
        });
        recyclerView.setAdapter(adapter);

        map.put("1244", "Cold Drink");
        map.put("0054", "Burger");
        map.put("0187", "Sandwich");
        map.put("7176", "Pizza");

        startScanning();
        //scaledBitmap = Bitmap.createScaledBitmap(bitmap,100,100,false);
        ActivityCompat.requestPermissions(this, new String[]{
                Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.CAMERA}, PackageManager.PERMISSION_GRANTED);
        {

            //  createPdf();
            startScanning();
            createPdf();
        }

    }


    private void startScanning() {
        barcodeView.decodeContinuous(new BarcodeCallback() {
            @Override
            public void barcodeResult(BarcodeResult result) {
                // Handle the decoded result
                String decodedText = result.getText();
                // addItemToRecyclerView(decodedText);

                if (decodedText.length() == 14) {
                    // Check if barcode has been scanned before
                    if (!fullCodeList.contains(decodedText)) {

                        fullCodeList.add(decodedText);

                        copyDecodeText = decodedText;

                        // Extract the last 4 digits using substring
                        double lastDigitPrice = Double.parseDouble(decodedText.substring(decodedText.length() - 4));

                        String productId = copyDecodeText.substring(startingIndex, startingIndex + 4);

                        if (String.valueOf(lastDigitPrice).matches(pattern) && productId.matches(pattern)) {
                            ItemModel itemModel = new ItemModel(lastDigitPrice, map.get(productId), 1);
                            addItemToRecyclerView(itemModel);
                        }
                    }
                }

            }


            @Override
            public void possibleResultPoints(List resultPoints) {
                // You can use this callback method to show visual cues on the viewfinder.
            }


        });
    }


    private void addItemToRecyclerView(ItemModel item) {
        //  listItem.add(item);
        //   adapter.addItem(item);
        listItem.add(item);
        adapter.notifyItemInserted(listItem.size() - 1);
    }


    private void createPdf() {
        btnCreatePDf.setOnClickListener(v -> {

            if(etCustomerName.getText().length() != 0 && adapter.getItemCount() != 0){

                customerName = etCustomerName.getText().toString();

                PdfDocument pdfDocument = new PdfDocument();
                Paint paint = new Paint();
                //    paint.setLetterSpacing(0.01f);

                PdfDocument.PageInfo pageInfo1 = new PdfDocument.PageInfo.Builder(595, 842, 1).create();
                PdfDocument.Page myPage1 = pdfDocument.startPage(pageInfo1);
                Canvas canvas = myPage1.getCanvas();


                // insert the picture
                int endPosition = pageInfo1.getPageWidth() - 100;
                scaledBitmap = Bitmap.createScaledBitmap(bitmap, 100, 100, false);

                canvas.drawBitmap(scaledBitmap, endPosition, 0, paint);

                // draw a text as like invoice
                paint.setTextAlign(Paint.Align.CENTER);
                paint.setTextSize(32.0f);
                paint.setColor(ContextCompat.getColor(this, R.color.green));
                paint.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
                canvas.drawText("Invoice", (float) pageInfo1.getPageWidth() / 2, 100, paint);


                // customer name headiing
                paint.setTextAlign(Paint.Align.LEFT);
                paint.setTextSize(10.0f);
                paint.setColor(Color.BLACK);
                paint.setTypeface(Typeface.defaultFromStyle(Typeface.ITALIC));
                canvas.drawText("Customer Name: "+customerName, 80, 170, paint);


          /*  int endX = pageInfo1.getPageWidth() - 5;

            float textWidth = paint.measureText(getCurrentDate());
            float x = pageInfo1.getPageWidth() - textWidth;*/

                // date and time heading
                paint.setTextAlign(Paint.Align.RIGHT);
                canvas.drawText("Date: " + getCurrentDate(), 590, 170, paint);
                canvas.drawText("Time: " + getCurrentTime(), 590, 180, paint);

                //draw rectangle stroke etc
                paint.setTextAlign(Paint.Align.RIGHT);
                paint.setStyle(Paint.Style.STROKE);
                paint.setStrokeWidth(1);
                //draw rectangle
                canvas.drawRect(10, 220, pageInfo1.getPageWidth() - 10, 250, paint);
                // draw four line vertical, to make portions in rectangle
                canvas.drawLine(100, 220, 100, 250, paint);
                canvas.drawLine(300, 220, 300, 250, paint);
                canvas.drawLine(430, 220, 430, 250, paint);
                canvas.drawLine(500, 220, 500, 250, paint);


                paint.setStrokeWidth(0);
                paint.setStyle(Paint.Style.FILL);
                paint.setTextSize(12.0f);
                paint.setTextAlign(Paint.Align.LEFT);
                paint.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));

                // draw texts invoice data headings
                canvas.drawText("Sr No.", 15, 240, paint);
                canvas.drawText("Item Name", 105, 240, paint);
                canvas.drawText("Price", 305, 240, paint);
                canvas.drawText("Qty", 435, 240, paint);
                canvas.drawText("Total", 505, 240, paint);

                srNumber = 0;
                for (int sNo = 0; sNo < listItem.size(); sNo++) { srNumber++; // draw values as like qty price item name etc canvas.drawText(srNumber + "", 17, yAxisForValue, paint); canvas.drawText(listItem.get(sNo).getItemName(), 106, yAxisForValue, paint); canvas.drawText(String.valueOf(listItem.get(sNo).getItemPrice()), 306, yAxisForValue, paint); canvas.drawText(String.valueOf(listItem.get(sNo).getItemQuantity()), 435, yAxisForValue, paint); canvas.drawText(calculateTotalPerItem(listItem.get(sNo).getItemPrice(), listItem.get(sNo).getItemQuantity()), 508, yAxisForValue, paint); yAxisForValue += 20; } yAxisForValue += 20; // draw line below of value and above of total canvas.drawLine(300, yAxisForValue, pageInfo1.getPageWidth() - 10, yAxisForValue, paint); yAxisForValue += 20; // draw texts as like total canvas.drawText("Sub Total", 306, yAxisForValue, paint); canvas.drawText(String.valueOf(calculateSubTotal()), 508, yAxisForValue, paint); canvas.drawText(":", 435, yAxisForValue, paint); yAxisForValue += 20; canvas.drawText("Tax (5%)", 306, yAxisForValue, paint); canvas.drawText(String.valueOf(calculateTax()), 508, yAxisForValue, paint); canvas.drawText(":", 435, yAxisForValue, paint); Paint paint2 = new Paint(); paint2.setStrokeWidth(1); // Set the stroke width to 5 (adjust as needed) paint2.setColor(ContextCompat.getColor(this, R.color.black)); // Set the stroke color to black paint2.setStyle(Paint.Style.STROKE); // Set the style to fill and stroke yAxisForValue += 35; // this value uses for top int bottom = yAxisForValue + 45; paint.setColor(ContextCompat.getColor(this, R.color.green)); canvas.drawRect(300, yAxisForValue, pageInfo1.getPageWidth() - 10, bottom, paint); canvas.drawRect(300, yAxisForValue, pageInfo1.getPageWidth() - 10, bottom, paint2); int yValueForGrandTotal = bottom - yAxisForValue; int calc = yValueForGrandTotal / 3; int finalCalc = calc * 2; yAxisForValue += finalCalc; paint.setColor(Color.WHITE); paint.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD)); paint.setTextSize(16.0f); canvas.drawText("Total", 320, yAxisForValue, paint); canvas.drawText(String.valueOf(calculateSubTotal() + calculateTax()), 515, yAxisForValue, paint); paint.setColor(ContextCompat.getColor(this, R.color.black)); paint.setTextAlign(Paint.Align.LEFT); paint.setTextSize(8.0f); canvas.drawText("Invoice Number: " + System.currentTimeMillis(), 17, pageInfo1.getPageHeight() - 20, paint); paint.setTextAlign(Paint.Align.RIGHT); canvas.drawText("Generate by Al Saeed", pageInfo1.getPageWidth() - 17, pageInfo1.getPageHeight() - 20, paint); pdfDocument.finishPage(myPage1); String folderName = "AlsaeedFolder"; // Define your custom folder name File customFolder = new File(Environment.getExternalStorageDirectory(), folderName); if (!customFolder.exists()) { customFolder.mkdirs(); // Create the folder if it doesn't exist } File file = new File(customFolder, "myPDF.pdf"); try { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                        pdfDocument.writeTo(Files.newOutputStream(file.toPath()));
                    } else {
                        pdfDocument.writeTo(new FileOutputStream(file));
                    }
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }

                Toast.makeText(this, "File save in " + file.getAbsolutePath(), Toast.LENGTH_SHORT).show();
                // pdfDocument.close();


                // Open the PDF file using a PDF viewer app
                Intent intent = new Intent(Intent.ACTION_VIEW);
                Uri pdfUri = FileProvider.getUriForFile(this, "alsaeeddev.com.fileProvider", file);
                intent.setDataAndType(pdfUri, "application/pdf");
                intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); // Grant read permissions

                try {
                    startActivity(intent); // Launch the PDF viewer activity
                } catch (ActivityNotFoundException e) {
                    // Handle the case where no PDF viewer app is available
                    Toast.makeText(getApplicationContext(), "No PDF viewer app found", Toast.LENGTH_SHORT).show();
                }

                Toast.makeText(this, "File saved in " + file.getAbsolutePath(), Toast.LENGTH_SHORT).show();
                pdfDocument.close();

            }else {
                etCustomerName.setError("Enter Name");
            }




        });
    }


    private String getCurrentDate() {
        // Get the current date
        Calendar calendar = Calendar.getInstance();
        int year = calendar.get(Calendar.YEAR);
        int month = calendar.get(Calendar.MONTH) + 1; // Month is zero-based, so add 1
        int day = calendar.get(Calendar.DAY_OF_MONTH);

// Construct the date string
        return year + "-" + month + "-" + day;

    }


    private String getCurrentTime() {
        // Get the current time
        Calendar calendar = Calendar.getInstance();
        int hour = calendar.get(Calendar.HOUR_OF_DAY); // 24-hour format
        int minute = calendar.get(Calendar.MINUTE);
        int second = calendar.get(Calendar.SECOND);

// Construct the time string
        return hour + ":" + minute + ":" + second;
    }


    private String calculateTotalPerItem(double price, int quantity) {
        double total = price * quantity;
        totalPricePerItemList.add(total);
        return String.valueOf(total);
    }


    private double calculateSubTotal() {
        double subTotal = 0;
        for (int i = 0; i < totalPricePerItemList.size(); i++) {
            subTotal += totalPricePerItemList.get(i);
        }
        return subTotal;
    }


    private double calculateTax() {

        return calculateSubTotal() * 0.5;
    }

    @Override
    protected void onResume() {
        super.onResume();
        barcodeView.resume();
    }

    @Override
    protected void onPause() {
        super.onPause();
        yAxisForValue = 280;
        totalPricePerItemList.clear();
        barcodeView.pause();

    }

    @Override
    protected void onStop() {
        yAxisForValue = 280;
        totalPricePerItemList.clear();
        super.onStop();
    }

    @Override
    protected void onDestroy() {
        listItem.clear();
        fullCodeList.clear();
        super.onDestroy();
    }
}
</pre

2. MyAdapter.java

 


public class MyAdapter extends RecyclerView.Adapter {
    private final List itemList;

   private final Context context;
  private final QuantityChangeListener listener;

    public MyAdapter(Context context, List data, QuantityChangeListener listener) {
        this.itemList = data;
       this.listener = listener;
       this.context = context;
    }

    @NonNull
    @Override
    public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.rv_item, parent, false);
        return new MyViewHolder(view);
    }

    @Override
    public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
        holder.bindData(position);

      //  holder.itemView.setOnClickListener(v -> Toast.makeText(context, itemList.get(position).getItemQuantity(), Toast.LENGTH_SHORT).show());
    }

    @Override
    public int getItemCount() {
        return itemList.size();
    }

    public void addItem(String item) {
      /*  mData.add(item);
        notifyItemInserted(mData.size() - 1);*/

     /*   mData.add(0, item); // Insert item at index 0
        notifyItemInserted(0);*/
    }

    public  class MyViewHolder extends RecyclerView.ViewHolder {
        TextView itemName, itemPrice;
        EditText editText;


        public MyViewHolder(@NonNull View itemView) {
            super(itemView);
            itemName = itemView.findViewById(R.id.tvItemName);
            itemPrice = itemView.findViewById(R.id.tvItemPrice);
            editText = itemView.findViewById(R.id.etQuantity);


        }

        public void bindData(int position) {
            ItemModel item = itemList.get(position);
            itemName.setText(item.getItemName());
           itemPrice.setText(String.valueOf(item.getItemPrice()));
           editText.setText(String.valueOf(item.getItemQuantity()));

           editText.addTextChangedListener(new TextWatcher() {
               @Override
               public void beforeTextChanged(CharSequence s, int start, int count, int after) {

               }

               @Override
               public void onTextChanged(CharSequence s, int start, int before, int count) {
                   if(!TextUtils.isEmpty(s.toString())){
                       int quantity = Integer.parseInt(s.toString());
                       if(quantity != 0) {
                           item.setItemQuantity(quantity);
                           //   if(listener != null && position != RecyclerView.NO_POSITION) {
                           listener.onQuantityChanged(position, quantity);
                       }
                     //  }
                   }
               }

               @Override
               public void afterTextChanged(Editable s) {

               }
           });





        }

   /*     public interface QuantityChangeListener {
            void onQuantityChanged(int position, int quantity);
        }

        public void setListener(QuantityChangeListener listener){
            listener = listener;
        }*/


    }

}
</pre

3. QuantityChangeListener.java

 


public interface QuantityChangeListener {
    void onQuantityChanged(int position, int quantity);
}
</pre

4. ItemModel.java

 


public class ItemModel {
    private final double itemPrice;
    private final String itemName;
    private int itemQuantity;

    public int getItemQuantity() {
        return itemQuantity;
    }

    public void setItemQuantity(int quantity){
        this.itemQuantity = quantity;
    }



    public double getItemPrice() {
        return itemPrice;
    }

    public String getItemName() {
        return itemName;
    }


    public ItemModel(double itemPrice, String itemName, int itemQuantity) {
        this.itemPrice = itemPrice;
        this.itemName = itemName;
        this.itemQuantity = itemQuantity;
    }




}
</pre

5. 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"
    android:elevation="10dp"
    android:id="@+id/main"
    tools:context=".MainActivity">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/myRecyclerView"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_marginStart="1dp"
        android:layout_marginTop="8dp"
        android:layout_marginEnd="1dp"
        app:layout_constraintBottom_toTopOf="@id/btnNext"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        android:layout_marginBottom="8dp"
        app:layout_constraintTop_toBottomOf="@+id/zxingBarcodeScanner" />

    <com.journeyapps.barcodescanner.DecoratedBarcodeView
        android:id="@+id/zxingBarcodeScanner"
        android:layout_width="0dp"
        android:layout_height="150dp"
        android:layout_marginStart="8dp"
        android:layout_marginTop="8dp"
        android:layout_marginEnd="8dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/etCustomerName" />

 

    <androidx.appcompat.widget.AppCompatButton
        android:id="@+id/btnNext"
        android:layout_width="200dp"
        android:layout_height="wrap_content"
        android:text="Generate Invoice"
        android:textAllCaps="false"
        android:background="@drawable/btn_bg"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        android:layout_marginBottom="8dp"
        app:layout_constraintStart_toStartOf="parent" />

    <EditText
        android:id="@+id/etCustomerName"
        android:layout_width="0dp"
        android:layout_height="48dp"
        android:layout_marginStart="8dp"
        android:layout_marginTop="8dp"
        android:layout_marginEnd="8dp"
        android:background="@drawable/btn_bg"
        android:ems="10"
        android:textSize="14sp"
        android:paddingStart="8dp"
        android:paddingEnd="8dp"
        android:inputType="text"
        android:hint="Customer name"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

6. rv_item.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="wrap_content">

    <androidx.cardview.widget.CardView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        android:layout_marginEnd="8dp"
        android:layout_marginStart="8dp"
        android:layout_marginTop="5dp"
        android:elevation="8dp"
        android:backgroundTint="#E7EFE6"
        app:cardCornerRadius="8dp"
        app:layout_constraintTop_toTopOf="parent">

        <androidx.constraintlayout.widget.ConstraintLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent">

            <TextView
                android:id="@+id/tvItemName"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_marginStart="8dp"
                android:layout_marginTop="8dp"
                android:padding="3dp"
                android:text="Pepsi"
                android:textColor="@color/black"
                android:textStyle="bold"
                app:layout_constraintEnd_toStartOf="@+id/etQuantity"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toTopOf="parent" />

            <TextView
                android:id="@+id/tvItemPrice"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_marginEnd="8dp"
                android:layout_marginBottom="8dp"
                android:padding="3dp"
                android:text="$8"
                android:layout_marginTop="3dp"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintTop_toBottomOf="@+id/tvItemName" />

            <TextView
                android:id="@+id/textView"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_marginEnd="5dp"
                android:layout_marginBottom="8dp"
                android:padding="3dp"
                android:text="Price"
                android:layout_marginTop="3dp"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintEnd_toStartOf="@+id/tvItemPrice"
                app:layout_constraintTop_toBottomOf="@+id/tvItemName" />

            <EditText
                android:id="@+id/etQuantity"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:background="@android:color/transparent"
                android:text="1"
                android:layout_marginEnd="8dp"
                android:paddingStart="8dp"
                android:paddingEnd="8dp"
                android:ems="4"
                android:gravity="center"
                app:layout_constraintBottom_toBottomOf="@+id/tvItemName"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintTop_toTopOf="@+id/tvItemName" />

        </androidx.constraintlayout.widget.ConstraintLayout>

    </androidx.cardview.widget.CardView>

</androidx.constraintlayout.widget.ConstraintLayout>

Output


Conclusion

By following these steps, you can build a functional Android application that scans barcodes, lists products in a RecyclerView, and generates a PDF invoice. This project is highly useful for businesses looking for an easy invoicing system within their Android app.

📥
Click here to Download
the source code or ask questions in the comments below!

Leave a Comment

Your email address will not be published. Required fields are marked *