In Android Studio choose New Project → Empty Views Activity, with Language Java and Minimum SDK API 24.
2. No library needed
Android can write and read PDFs by itself: PdfDocument creates them and PdfRenderer displays them. There's nothing to add to Gradle, and no storage permission is needed.
3. Build the form
In activity_main.xml, add a title box and a large text box that fills the screen, then a Create PDF button.
4. Lay out the text
A PDF page is a canvas measured in points; A4 is 595 × 842. StaticLayout wraps your text into lines that fit between the margins, just like a TextView does.
5. Draw the pages
In PdfMaker, startPage gives you a Canvas. The first page gets the title, the date and a thin line. Then draw as many whole lines of text as fit, add the page number, and finishPage. Repeat until every line is drawn, so long text flows onto page 2, 3 and so on.
6. Save it
writeTo saves the PDF into the app's own files/pdfs folder, then close() frees the memory. The title becomes the file name, keeping only letters, digits and dashes.
7. Work in the background
Writing a long PDF takes a moment, so MainActivity does it on a background thread and comes back to the main thread to open the viewer.
8. Show the PDF
PdfViewerActivity opens the file with PdfRenderer. For each page, it draws the page into a Bitmap as wide as the screen and shows it in an ImageView. Fill the bitmap with white first: PDF pages are transparent.
9. Share it
App files are private, so another app can't open them directly. Register a FileProvider in the manifest (Required setup) and res/xml/file_paths.xml. FileProvider.getUriForFile then gives a temporary content:// link to send with ACTION_SEND.
10. Save a copy
ActivityResultContracts.CreateDocument("application/pdf") opens the system Save to screen. The user picks a place, such as Downloads, and you copy the file there.
11. Run it
Paste in a long piece of text to see it flow across pages, then try Share and Save.
What's improved over the video
No third-party PDF library, text wraps and flows onto new pages, writing happens in the background, a built-in viewer shows every page, and you can share or save a copy without any storage permission.
Files affected
Check what to add and what to replace before copying code.
Checks the title and text, writes the PDF in the background, then opens the viewer.
MainActivity.java
packagecom.example.texttopdf;importandroid.content.Intent;importandroid.os.Bundle;importandroid.os.Handler;importandroid.os.Looper;importandroid.text.format.DateFormat;importandroid.widget.Button;importandroid.widget.Toast;importandroidx.appcompat.app.AppCompatActivity;importcom.google.android.material.textfield.TextInputLayout;importjava.io.File;importjava.io.IOException;importjava.util.Date;importjava.util.concurrent.ExecutorService;importjava.util.concurrent.Executors;/** Type a title and some text, then turn them into a PDF and open it in the viewer. */publicclassMainActivityextendsAppCompatActivity{/** Writing a long PDF can take a moment, so it happens off the main thread. */privatefinalExecutorService background =Executors.newSingleThreadExecutor();privatefinalHandler mainThread =newHandler(Looper.getMainLooper());privateTextInputLayout titleLayout, bodyLayout;privateButton create;@OverrideprotectedvoidonCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState);Screens.setUp(this,R.layout.activity_main);
titleLayout =findViewById(R.id.layoutTitle);
bodyLayout =findViewById(R.id.layoutBody);
create =findViewById(R.id.btnCreate);
create.setOnClickListener(v ->create());}@OverrideprotectedvoidonDestroy(){super.onDestroy();
background.shutdown();}privatevoidcreate(){String title =text(titleLayout);String body =text(bodyLayout);
titleLayout.setError(title.isEmpty()?getString(R.string.error_title):null);
bodyLayout.setError(body.isEmpty()?getString(R.string.error_body):null);if(title.isEmpty()|| body.isEmpty())return;// Files in getFilesDir() belong to the app: no storage permission is needed.File file =newFile(newFile(getFilesDir(),"pdfs"),fileName(title));String date =DateFormat.getLongDateFormat(this).format(newDate());
create.setEnabled(false);
background.execute(()->{boolean ok =writePdf(title, date, body, file);
mainThread.post(()->{
create.setEnabled(true);if(ok){startActivity(newIntent(this,PdfViewerActivity.class).putExtra("path", file.getAbsolutePath()));}else{Toast.makeText(this,R.string.error_create,Toast.LENGTH_LONG).show();}});});}privatestaticbooleanwritePdf(String title,String date,String body,File file){File folder = file.getParentFile();if(folder ==null||!(folder.isDirectory()|| folder.mkdirs()))returnfalse;try{PdfMaker.write(title, date, body, file);returntrue;}catch(IOException e){returnfalse;}}/** "My notes: day 1" becomes "My-notes-day-1.pdf". Only letters, digits and dashes are safe in every file system. */staticStringfileName(String title){String safe = title.replaceAll("[^A-Za-z0-9]+","-").replaceAll("^-|-$","");return(safe.isEmpty()?"document": safe)+".pdf";}privatestaticStringtext(TextInputLayout layout){return layout.getEditText()==null?"": layout.getEditText().getText().toString().trim();}}