Melhores bibliotecas de PDF para Android
As melhores bibliotecas de PDF para Android deste ano.
PDF significa Portable Document Format. É um formato de arquivo desenvolvido na década de 1990 para apresentar documentos, incluindo formatação de texto e imagens, de maneira independente de software aplicativo, hardware e sistemas operacionais.
O PDF foi lançado pela primeira vez há 24 anos no ano 15 de junho de 1993 pela Adobe, no entanto, agora é um padrão aberto mantido pela Organização Internacional de Padronização (ISO).
Existem muitos aplicativos de leitura de PDF gratuitos e comerciais para dispositivos Android. No entanto, nós, como desenvolvedores, devemos construir nossos próprios pequenos leitores de PDF que talvez nós e nossos amigos possamos usar.
Não é tão difícil quanto você pensa e existem várias bibliotecas de código aberto para ajudar nisso.
Nesta parte, veremos algumas dessas bibliotecas e provavelmente trechos de como usá-las.
Vamos começar.
1. AndroidPdfViewer
Esta é uma biblioteca de código aberto para exibição de documentos PDF. Esses PDFs são renderizados com PdfiumAndroid.
AndroidPdfViewer é atualmente a biblioteca Android PDF View mais popular. É mantido por bartesk e ele lançou várias versões da biblioteca de forma independente.
Por exemplo, muitas pessoas ainda estão usando AndroidPdfView, mas há um AndroidPdfViewV1 e [AndroidPdfViewV2] (https://github.com/barteksc/AndroidPdfViewerV2).
Esta biblioteca tem suporte para animações, gestos, zoom e toque duplo.
Usar esta biblioteca é fácil, muito fácil.
Primeiro, basta incluí-lo no nível do aplicativo build.gradle:
implementation 'com.github.barteksc:android-pdf-viewer:2.8.2'
Então no seu layout:
<com.github.barteksc.pdfviewer.PDFView
android_id="@+id/pdfView"
android_layout_width="match_parent"
android_layout_height="match_parent"/>
Então você pode carregar o pdf de várias fontes:
pdfView.fromUri(Uri)
or
pdfView.fromFile(File)
or
pdfView.fromBytes(byte[])
or
pdfView.fromStream(InputStream) // stream is written to bytearray - native code cannot use Java Streams
or
pdfView.fromSource(DocumentSource)
or
pdfView.fromAsset(String)
.pages(0, 2, 1, 3, 3, 3) // all pages are displayed by default
.enableSwipe(true) // allows to block changing pages using swipe
.swipeHorizontal(false)
.enableDoubletap(true)
.defaultPage(0)
// allows to draw something on the current page, usually visible in the middle of the screen
.onDraw(onDrawListener)
// allows to draw something on all pages, separately for every page. Called only for visible pages
.onDrawAll(onDrawListener)
.onLoad(onLoadCompleteListener) // called after document is loaded and starts to be rendered
.onPageChange(onPageChangeListener)
.onPageScroll(onPageScrollListener)
.onError(onErrorListener)
.onPageError(onPageErrorListener)
.onRender(onRenderListener) // called after document is rendered for the first time
// called on single tap, return true if handled, false to toggle scroll handle visibility
.onTap(onTapListener)
.enableAnnotationRendering(false) // render annotations (such as comments, colors or forms)
.password(null)
.scrollHandle(null)
.enableAntialiasing(true) // improve rendering a little bit on low-res screens
// spacing between pages in dp. To define spacing color, set view background
.spacing(0)
.invalidPageColor(Color.WHITE) // color of page that is invalid and cannot be loaded
.load();
Exemplo
Aqui está um exemplo
@EActivity(R.layout.activity_main)
@OptionsMenu(R.menu.options)
public class PDFViewActivity extends AppCompatActivity implements OnPageChangeListener, OnLoadCompleteListener,
OnPageErrorListener {
private static final String TAG = PDFViewActivity.class.getSimpleName();
private final static int REQUEST_CODE = 42;
public static final int PERMISSION_CODE = 42042;
public static final String SAMPLE_FILE = "sample.pdf";
public static final String READ_EXTERNAL_STORAGE = "android.permission.READ_EXTERNAL_STORAGE";
@ViewById
PDFView pdfView;
@NonConfigurationInstance
Uri uri;
@NonConfigurationInstance
Integer pageNumber = 0;
String pdfFileName;
@OptionsItem(R.id.pickFile)
void pickFile() {
int permissionCheck = ContextCompat.checkSelfPermission(this,
READ_EXTERNAL_STORAGE);
if (permissionCheck != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(
this,
new String[]{READ_EXTERNAL_STORAGE},
PERMISSION_CODE
);
return;
}
launchPicker();
}
void launchPicker() {
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("application/pdf");
try {
startActivityForResult(intent, REQUEST_CODE);
} catch (ActivityNotFoundException e) {
//alert user that file manager not working
Toast.makeText(this, R.string.toast_pick_file_error, Toast.LENGTH_SHORT).show();
}
}
@AfterViews
void afterViews() {
pdfView.setBackgroundColor(Color.LTGRAY);
if (uri != null) {
displayFromUri(uri);
} else {
displayFromAsset(SAMPLE_FILE);
}
setTitle(pdfFileName);
}
private void displayFromAsset(String assetFileName) {
pdfFileName = assetFileName;
pdfView.fromAsset(SAMPLE_FILE)
.defaultPage(pageNumber)
.onPageChange(this)
.enableAnnotationRendering(true)
.onLoad(this)
.scrollHandle(new DefaultScrollHandle(this))
.spacing(10) // in dp
.onPageError(this)
.pageFitPolicy(FitPolicy.BOTH)
.load();
}
private void displayFromUri(Uri uri) {
pdfFileName = getFileName(uri);
pdfView.fromUri(uri)
.defaultPage(pageNumber)
.onPageChange(this)
.enableAnnotationRendering(true)
.onLoad(this)
.scrollHandle(new DefaultScrollHandle(this))
.spacing(10) // in dp
.onPageError(this)
.load();
}
@OnActivityResult(REQUEST_CODE)
public void onResult(int resultCode, Intent intent) {
if (resultCode == RESULT_OK) {
uri = intent.getData();
displayFromUri(uri);
}
}
@Override
public void onPageChanged(int page, int pageCount) {
pageNumber = page;
setTitle(String.format("%s %s / %s", pdfFileName, page + 1, pageCount));
}
public String getFileName(Uri uri) {
String result = null;
if (uri.getScheme().equals("content")) {
Cursor cursor = getContentResolver().query(uri, null, null, null, null);
try {
if (cursor != null && cursor.moveToFirst()) {
result = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME));
}
} finally {
if (cursor != null) {
cursor.close();
}
}
}
if (result == null) {
result = uri.getLastPathSegment();
}
return result;
}
@Override
public void loadComplete(int nbPages) {
PdfDocument.Meta meta = pdfView.getDocumentMeta();
Log.e(TAG, "title = " + meta.getTitle());
Log.e(TAG, "author = " + meta.getAuthor());
Log.e(TAG, "subject = " + meta.getSubject());
Log.e(TAG, "keywords = " + meta.getKeywords());
Log.e(TAG, "creator = " + meta.getCreator());
Log.e(TAG, "producer = " + meta.getProducer());
Log.e(TAG, "creationDate = " + meta.getCreationDate());
Log.e(TAG, "modDate = " + meta.getModDate());
printBookmarksTree(pdfView.getTableOfContents(), "-");
}
public void printBookmarksTree(List<PdfDocument.Bookmark> tree, String sep) {
for (PdfDocument.Bookmark b : tree) {
Log.e(TAG, String.format("%s %s, p %d", sep, b.getTitle(), b.getPageIdx()));
if (b.hasChildren()) {
printBookmarksTree(b.getChildren(), sep + "-");
}
}
}
/**
* Listener for response to user permission request
*
* @param requestCode Check that permission request code matches
* @param permissions Permissions that requested
* @param grantResults Whether permissions granted
*/
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[],
@NonNull int[] grantResults) {
if (requestCode == PERMISSION_CODE) {
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
launchPicker();
}
}
}
@Override
public void onPageError(int page, Throwable t) {
Log.e(TAG, "Cannot load page " + page);
}
}
Referência
| Não | Lin |
|---|---|
| 1. | Navegar Exemplo |
| 2. | Leia mais |
| 3. | Download direto |
2. PDFiumAndroid
O mesmo autor do AndroidPdfViewer, bartesk bifurcou o PdfiumAndroid de seu repositório original e tem mantido e adicionado alguns documentação também.
O PdfiumAndroid original não foi mantido.
Portanto, a versão bifurcada tem alguma documentação e está sendo mantida ativamente.
Ele o bifurcou para usá-lo com o popular AndroidPdfViewer.
No entanto, você também pode usá-lo de forma independente.
Primeiro você precisa adicioná-lo como uma dependência:
implementation 'com.github.barteksc:pdfium-android:1.8.2'
Então aqui está um exemplo simples:
void openPdf() {
ImageView iv = (ImageView) findViewById(R.id.imageView);
ParcelFileDescriptor fd = ...;
int pageNum = 0;
PdfiumCore pdfiumCore = new PdfiumCore(context);
try {
PdfDocument pdfDocument = pdfiumCore.newDocument(fd);
pdfiumCore.openPage(pdfDocument, pageNum);
int width = pdfiumCore.getPageWidthPoint(pdfDocument, pageNum);
int height = pdfiumCore.getPageHeightPoint(pdfDocument, pageNum);
// ARGB_8888 - best quality, high memory usage, higher possibility of OutOfMemoryError
// RGB_565 - little worse quality, twice less memory usage
Bitmap bitmap = Bitmap.createBitmap(width, height,
Bitmap.Config.RGB_565);
pdfiumCore.renderPageBitmap(pdfDocument, bitmap, pageNum, 0, 0,
width, height);
//if you need to render annotations and form fields, you can use
//the same method above adding 'true' as last param
iv.setImageBitmap(bitmap);
printInfo(pdfiumCore, pdfDocument);
pdfiumCore.closeDocument(pdfDocument); // important!
} catch(IOException ex) {
ex.printStackTrace();
}
}
public void printInfo(PdfiumCore core, PdfDocument doc) {
PdfDocument.Meta meta = core.getDocumentMeta(doc);
Log.e(TAG, "title = " + meta.getTitle());
Log.e(TAG, "author = " + meta.getAuthor());
Log.e(TAG, "subject = " + meta.getSubject());
Log.e(TAG, "keywords = " + meta.getKeywords());
Log.e(TAG, "creator = " + meta.getCreator());
Log.e(TAG, "producer = " + meta.getProducer());
Log.e(TAG, "creationDate = " + meta.getCreationDate());
Log.e(TAG, "modDate = " + meta.getModDate());
printBookmarksTree(core.getTableOfContents(doc), "-");
}
public void printBookmarksTree(List<PdfDocument.Bookmark> tree, String sep) {
for (PdfDocument.Bookmark b : tree) {
Log.e(TAG, String.format("%s %s, p %d", sep, b.getTitle(), b.getPageIdx()));
if (b.hasChildren()) {
printBookmarksTree(b.getChildren(), sep + "-");
}
}
}
| Exibir | Baixar |
|---|---|
| Exibir | Download direto |
3. PdfBox-Android
PdfBox-Android é uma porta da biblioteca PdfBox do Apache para ser usada no Android. A maioria dos recursos que devem estar na biblioteca pai já estão implementados no PdfBox-Android.
PdfBox-Android requer Android API 19 e superior para funcionalidade completa.
PdfBox-Android é mais uma biblioteca que nos permite renderizar documentos PDF. Foi escrito por Tom Roush e tem vários colaboradores.
O código principal do projeto PdfBox-Android está licenciado sob a licença Apache 2.0, encontrada aqui.
Esta biblioteca existe há mais de 4 anos, mas ainda é atualizada regularmente.
Instalação do PDFBox-Android
Veja como instalar o PDFBox-Android.
Acesse o build.gradle do nível do aplicativo e adicione a declaração de implementação:
dependencies {
implementation 'com.tom-roush:pdfbox-android:1.8.10.3'
}
Você pode verificar a versão mais recente aqui.
Se você estiver usando o Maven, então:
<dependency>
<groupId>com.tom_roush</groupId>
<artifactId>pdfbox-android</artifactId>
<version>1.8.10.0</version>
<type>pom</type>
</dependency>
Antes de fazer chamadas para PDFBox, é altamente recomendável inicializar o carregador de recursos da biblioteca. Adicione a seguinte linha antes de chamar os métodos PDFBox:
PDFBoxResourceLoader.init(getApplicationContext());
Exemplo
Aqui está um exemplo:
MainActivity.java
public class MainActivity extends Activity {
File root;
AssetManager assetManager;
Bitmap pageImage;
TextView tv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
@Override
protected void onStart() {
super.onStart();
setup();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
/**
* Initializes variables used for convenience
*/
private void setup() {
// Enable Android asset loading
PDFBoxResourceLoader.init(getApplicationContext());
// Find the root of the external storage.
root = getApplicationContext().getCacheDir();
assetManager = getAssets();
tv = (TextView) findViewById(R.id.statusTextView);
}
/**
* Creates a new PDF from scratch and saves it to a file
*/
public void createPdf(View v) {
PDDocument document = new PDDocument();
PDPage page = new PDPage();
document.addPage(page);
// Create a new font object selecting one of the PDF base fonts
PDFont font = PDType1Font.HELVETICA;
// Or a custom font
// try
// {
// // Replace MyFontFile with the path to the asset font you'd like to use.
// // Or use LiberationSans "com/tom_roush/pdfbox/resources/ttf/LiberationSans-Regular.ttf"
// font = PDType0Font.load(document, assetManager.open("MyFontFile.TTF"));
// }
// catch (IOException e)
// {
// Log.e("PdfBox-Android-Sample", "Could not load font", e);
// }
PDPageContentStream contentStream;
try {
// Define a content stream for adding to the PDF
contentStream = new PDPageContentStream(document, page);
// Write Hello World in blue text
contentStream.beginText();
contentStream.setNonStrokingColor(15, 38, 192);
contentStream.setFont(font, 12);
contentStream.newLineAtOffset(100, 700);
contentStream.showText("Hello World");
contentStream.endText();
// Load in the images
InputStream in = assetManager.open("falcon.jpg");
InputStream alpha = assetManager.open("trans.png");
// Draw a green rectangle
contentStream.addRect(5, 500, 100, 100);
contentStream.setNonStrokingColor(0, 255, 125);
contentStream.fill();
// Draw the falcon base image
PDImageXObject ximage = JPEGFactory.createFromStream(document, in);
contentStream.drawImage(ximage, 20, 20);
// Draw the red overlay image
Bitmap alphaImage = BitmapFactory.decodeStream(alpha);
PDImageXObject alphaXimage = LosslessFactory.createFromImage(document, alphaImage);
contentStream.drawImage(alphaXimage, 20, 20 );
// Make sure that the content stream is closed:
contentStream.close();
// Save the final pdf document to a file
String path = root.getAbsolutePath() + "/Created.pdf";
document.save(path);
document.close();
tv.setText("Successfully wrote PDF to " + path);
} catch (IOException e) {
Log.e("PdfBox-Android-Sample", "Exception thrown while creating PDF", e);
}
}
/**
* Loads an existing PDF and renders it to a Bitmap
*/
public void renderFile(View v) {
// Render the page and save it to an image file
try {
// Load in an already created PDF
PDDocument document = PDDocument.load(assetManager.open("Created.pdf"));
// Create a renderer for the document
PDFRenderer renderer = new PDFRenderer(document);
// Render the image to an RGB Bitmap
pageImage = renderer.renderImage(0, 1, ImageType.RGB);
// Save the render result to an image
String path = root.getAbsolutePath() + "/render.jpg";
File renderFile = new File(path);
FileOutputStream fileOut = new FileOutputStream(renderFile);
pageImage.compress(Bitmap.CompressFormat.JPEG, 100, fileOut);
fileOut.close();
tv.setText("Successfully rendered image to " + path);
// Optional: display the render result on screen
displayRenderedImage();
}
catch (IOException e)
{
Log.e("PdfBox-Android-Sample", "Exception thrown while rendering file", e);
}
}
/**
* Fills in a PDF form and saves the result
*/
public void fillForm(View v) {
try {
// Load the document and get the AcroForm
PDDocument document = PDDocument.load(assetManager.open("FormTest.pdf"));
PDDocumentCatalog docCatalog = document.getDocumentCatalog();
PDAcroForm acroForm = docCatalog.getAcroForm();
// Fill the text field
PDTextField field = (PDTextField) acroForm.getField("TextField");
field.setValue("Filled Text Field");
// Optional: don't allow this field to be edited
field.setReadOnly(true);
PDField checkbox = acroForm.getField("Checkbox");
((PDCheckBox) checkbox).check();
PDField radio = acroForm.getField("Radio");
((PDRadioButton)radio).setValue("Second");
PDField listbox = acroForm.getField("ListBox");
List<Integer> listValues = new ArrayList<>();
listValues.add(1);
listValues.add(2);
((PDListBox) listbox).setSelectedOptionsIndex(listValues);
PDField dropdown = acroForm.getField("Dropdown");
((PDComboBox) dropdown).setValue("Hello");
String path = root.getAbsolutePath() + "/FilledForm.pdf";
tv.setText("Saved filled form to " + path);
document.save(path);
document.close();
} catch (IOException e) {
Log.e("PdfBox-Android-Sample", "Exception thrown while filling form fields", e);
}
}
/**
* Strips the text from a PDF and displays the text on screen
*/
public void stripText(View v) {
String parsedText = null;
PDDocument document = null;
try {
document = PDDocument.load(assetManager.open("Hello.pdf"));
} catch(IOException e) {
Log.e("PdfBox-Android-Sample", "Exception thrown while loading document to strip", e);
}
try {
PDFTextStripper pdfStripper = new PDFTextStripper();
pdfStripper.setStartPage(0);
pdfStripper.setEndPage(1);
parsedText = "Parsed text: " + pdfStripper.getText(document);
}
catch (IOException e)
{
Log.e("PdfBox-Android-Sample", "Exception thrown while stripping text", e);
} finally {
try {
if (document != null) document.close();
}
catch (IOException e)
{
Log.e("PdfBox-Android-Sample", "Exception thrown while closing document", e);
}
}
tv.setText(parsedText);
}
/**
* Creates a simple pdf and encrypts it
*/
public void createEncryptedPdf(View v)
{
String path = root.getAbsolutePath() + "/crypt.pdf";
int keyLength = 128; // 128 bit is the highest currently supported
// Limit permissions of those without the password
AccessPermission ap = new AccessPermission();
ap.setCanPrint(false);
// Sets the owner password and user password
StandardProtectionPolicy spp = new StandardProtectionPolicy("12345", "hi", ap);
// Setups up the encryption parameters
spp.setEncryptionKeyLength(keyLength);
spp.setPermissions(ap);
BouncyCastleProvider provider = new BouncyCastleProvider();
Security.addProvider(provider);
PDFont font = PDType1Font.HELVETICA;
PDDocument document = new PDDocument();
PDPage page = new PDPage();
document.addPage(page);
try
{
PDPageContentStream contentStream = new PDPageContentStream(document, page);
// Write Hello World in blue text
contentStream.beginText();
contentStream.setNonStrokingColor(15, 38, 192);
contentStream.setFont(font, 12);
contentStream.newLineAtOffset(100, 700);
contentStream.showText("Hello World");
contentStream.endText();
contentStream.close();
// Save the final pdf document to a file
document.protect(spp); // Apply the protections to the PDF
document.save(path);
document.close();
tv.setText("Successfully wrote PDF to " + path);
}
catch (IOException e)
{
Log.e("PdfBox-Android-Sample", "Exception thrown while creating PDF for encryption", e);
}
}
/**
* Helper method for drawing the result of renderFile() on screen
*/
private void displayRenderedImage() {
new Thread() {
public void run() {
runOnUiThread(new Runnable() {
@Override
public void run() {
ImageView imageView = (ImageView) findViewById(R.id.renderedImageView);
imageView.setImageBitmap(pageImage);
}
});
}
}.start();
}
}
Referência
Obtenha o PDFBox-Android abaixo:
| Não. | Localização | Link |
|---|---|---|
| 1. | GitHub | Exemplo |
| 2. | GitHub | Download direto |
| 3. | GitHub | Navegar |
4. PdfViewPager
Widget Android que pode renderizar documentos PDF armazenados no cartão SD, vinculados como ativos ou baixados de um URL remoto.
Este widget pode exibir documentos PDF em suas atividades ou fragmentos.
Observação importante: PDFViewPager usa a classe PdfRenderer, quefunciona somente na API 21 ou superior. Consulte documento oficial para obter detalhes.
Aqui está a demonstração:

Etapa 1: instale-o
Instale-o adicionando a seguinte instrução de implementação ao arquivo build.gradle no nível do aplicativo:
implementation 'es.voghdev.pdfviewpager:library:1.1.2'
Etapa 2: etapa Adicionar ao layout
PDFViewPager pode ser adicionado a uma página de forma declarativa ou imperativa. Para adicioná-lo declarativamente, adicione o seguinte ao seu layout:
<es.voghdev.pdfviewpager.library.PDFViewPager
android:id="@+id/pdfViewPager"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
Etapa 3: Escreva o código
Carregue PDFs da Pasta de Ativos
Se o seu arquivo PDF estiver localizado na pasta de recursos, copie-o para o diretório de cache.
CopyAsset copyAsset = new CopyAssetThreadImpl(context, new Handler());
copyAsset.copy(asset, new File(getCacheDir(), "sample.pdf").getAbsolutePath(
Você pode carregá-lo da seguinte maneira:
<es.voghdev.pdfviewpager.library.PDFViewPager
android:id="@+id/pdfViewPager"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:assetFileName="sample.pdf"/>
ou assim:
pdfViewPager = new PDFViewPager(this, "sample.pdf");
Em seguida, libere os recursos fechando o close () assim:
@Override
protected void onDestroy() {
super.onDestroy();
((PDFPagerAdapter) pdfViewPager.getAdapter()).close();
}
Carregue PDFs do cartão SD
Se seus PDFs estiverem localizados no cartão SD, crie um objeto PDFViewPager, passando a localização do arquivo em seu cartão SD
PDFViewPager pdfViewPager = new PDFViewPager(context, getPdfPathOnSDCard());
protected String getPdfPathOnSDCard() {
File f = new File(getExternalFilesDir("pdf"), "adobe.pdf");
return f.getAbsolutePath();
}
Em seguida, libere os recursos ocupados:
@Override
protected void onDestroy() {
super.onDestroy();
((PDFPagerAdapter) pdfViewPager.getAdapter()).close();
}
Como carregar PDFs de fontes remotas
Comece adicionando as seguintes permissões em seu manifesto do Android:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
Em seguida, faça sua atividade ou fragmento implementar DownloadFile.Listener:
public class RemotePDFActivity extends AppCompatActivity implements DownloadFile.Listener {
Em seguida, crie um objeto RemotePDFViewPager:
String url = "http://www.cals.uidaho.edu/edComm/curricula/CustRel_curriculum/content/sample.pdf";
RemotePDFViewPager remotePDFViewPager =
new RemotePDFViewPager(context, url, this);
Em seguida, manipule os eventos:
@Override
public void onSuccess(String url, String destinationPath) {
// That's the positive case. PDF Download went fine
adapter = new PDFPagerAdapter(this, "AdobeXMLFormsSamples.pdf");
remotePDFViewPager.setAdapter(adapter);
setContentView(remotePDFViewPager);
}
@Override
public void onFailure(Exception e) {
// This will be called if download fails
}
@Override
public void onProgressUpdate(int progress, int total) {
// You will get download progress here
// Always on UI Thread so feel free to update your views here
}
E, claro, feche o adaptador:
@Override
protected void onDestroy() {
super.onDestroy();
adapter.close();
}
Encontre exemplos completos abaixo.
Referência
| Não. | Link |
|---|---|
| 1. | Browse Exemplos |
| 2. | Leia mais |
| 3. | Siga autor da biblioteca |