Ola, eu tava usando minha aplicaçao no android quando me deparei com um problema grave: o App deu crash pq ficou sem memoria. No android studio eu fiz alguns testes e recrie a cena do erro o problema é que conforme eu mudo a orientaçao do aparelho o OS carrega os novos layouts em landscape ou portrait e isso consome 10MB por vez de acordo com o monitor da IDE, quando o app chega a 200MB de memoria ele para. Eu n sei oque fazer pra evitar isso, porque afinal se o android carrega os novos layouts pq n dispensa os velhos sao apenas duas orientaçoes ele devia carregar apenas duas vezes. Chega um ponto que quando o usuario estiver usando minha aplicaçao por muito tempo ela vai parar por falta de memoria. Alguem sabe oque fazer? obg.
Gilian,
Existem duas formas de resolver seu problema.
-
A primeira e mais recomendada é salvar os dados após trocar a orientação da tela (de portrait para landscape e vice-versa), daí quando o usuário gira a tela vc simplesmente recarrega a tela com os dados que já foram salvos.
-
A segunda opção seria limpar todos os dados após a troca de orientação, dessa forma vc evitaria o sebrecarregamento de memória.
Mas em todo caso posta o código da sua Activity pra gente analisar.
ola, o app carrega poucos dados do db entao n teria problema em carrega-los nova,ente ao mudar a orientaçao.
A questao é: Como eu faço pra limpar os dados ao mudar a orientaçao?
MAINACTIVITY (telaPrincipal) é aqui que ocorre o erro:
package main;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.os.Vibrator;
import android.support.design.widget.TabLayout;
import android.support.v4.content.ContextCompat;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;
import com.daimajia.androidanimations.library.Techniques;
import com.daimajia.androidanimations.library.YoYo;
import com.gilianmarques.dev.main.R;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Locale;
import debitosFixosManager.DebitoFixo;
import debitosManager.fragDebitos;
import fragmentos.fragChart;
import objetos.Strings;
import objetos.checkChanges;
import objetos.debito;
import objetos.folha;
import objetos.gConf;
import objetos.gFolhas;
import services.AutoStartUp;
import slidingview.ViewPagerAdapter;
public class telaPrincipal extends AppCompatActivity {
gConf gdc = gConf.getInstancia();
gFolhas gf = gFolhas.getInstancia();
checkChanges chkChanges = checkChanges.getInstancia();
Strings String = Strings.getInstancia();
boolean onWindowFocusChanged = false;
LinearLayout Tpllmain;
ImageView imgMenu;
Toolbar toolbar;
TabLayout tabLayout;
ViewPager viewpager;
ViewPagerAdapter viewPagerAdapter;
EditText edtNome, edtRenda;
Spinner spinner;
TextView txtNome, txtRenda;
ImageView imgok;
AlertDialog editBuilder;
public static Context context;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
context = getApplicationContext();
setContentView(R.layout.tela_principal);
toolbar = (Toolbar) findViewById(R.id.toolbar2);
toolbar.setTitle("DebitReminder");
setSupportActionBar(toolbar);
tabLayout = (TabLayout) findViewById(R.id.tabLayout);
viewpager = (ViewPager) findViewById(R.id.viewPager);
Tpllmain = (LinearLayout) findViewById(R.id.Tpllmain);
toolbar.setLogo(R.mipmap.ic_launcher);
imgMenu = (ImageView) findViewById(R.id.imgMenu);
imgMenu.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (gdc.getConfAtual().getQualFragTaNaTela() == 1) {
showMenu();
} else if (gdc.getConfAtual().getQualFragTaNaTela() == 0) {
showChartMenu();
} else if (gdc.getConfAtual().getQualFragTaNaTela() == 2) {
showStatMenu();
}
}
});
carregarFolha();
onWindowFocusChanged = true;
}
@Override
protected void onDestroy() {
Toast.makeText(getApplicationContext(), "Salvando dados", Toast.LENGTH_SHORT).show();
//salva as configuraçoes ao sair
gdc.saveConf(false);
super.onDestroy();
}
@Override
public void onBackPressed() {
gdc.saveConf(false);
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_HOME);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent); // super.onBackPressed();
}
@Override
public boolean onKeyDown(int keycode, KeyEvent e) {
switch (keycode) {
case KeyEvent.KEYCODE_MENU:
showMenu();
return true;
}
return super.onKeyDown(keycode, e);
}
/**
* @param hasFocus caso a janela estaja na tela esse metodo checa se ja tem uma folha e se nao
* leva o usuario para uma activity para a criaçao de uma.
*/
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if (onWindowFocusChanged) {
//parece que as vezes esse metodo é chamado antes do Oncreate e da um nullPointer por isso o if
if (hasFocus) {
//atualizo os debitos se necessario
if (chkChanges.isAtualizarDebitos()) {
carregarFolha();
chkChanges.setAtualizarDebitos(false);
} else if (gf.getFolhaAtual().getDebitos().size() <= 0) {
carregarFolha();
}
} else {
}
}
}
private void carregarFolha() {
folha f = gFolhas.getInstancia().getFolhaAtual();
if (f != null) {
toolbar.setTitle(" " + gf.getFolhaAtual().getNome());
toolbar.setSubtitle(" " + gf.getFolhaAtual().getMes());
carregarDebitos(f);
} else {
DialogInterface.OnClickListener dialogClickListener = new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
switch (which) {
case DialogInterface.BUTTON_NEUTRAL:
//Ação quando o usuário clicar no botão ok
startActivity(new Intent(telaPrincipal.this, addFolha.class));
break;
}
}
};
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage(String.s01).setTitle("Bem-vindo ao DebitReminder").setNeutralButton("OK", dialogClickListener)
.show();
}
}
private void carregarDebitos(folha folha) {
ArrayList<debito> array = folha.getDebitos();
if (array == null) {
// se nao tiver debitos levo o usuario para uma activity para criar o primeiro
//limpo a tela, util pra quando o usuario apaga o ultimo debito
if (viewpager != null) {
viewpager.removeAllViews();
}
DialogInterface.OnClickListener dialogClickListener = new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
switch (which) {
case DialogInterface.BUTTON_NEUTRAL:
//Ação quando o usuário clicar no botão ok
startActivity(new Intent(telaPrincipal.this, addDebito.class));
break;
}
}
};
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage(String.s04).setTitle("DebitReminder").setNeutralButton("OK", dialogClickListener)
.show();
chkChanges.setAtualizarDebitos(true);
} else if (array.size() <= 0) {
// se nao houver debitos na folha
//limpo a tela, util pra quando o usuario apaga o ultimo debito
if (viewpager != null) {
viewpager.removeAllViews();
}
DialogInterface.OnClickListener dialogClickListener = new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
switch (which) {
case DialogInterface.BUTTON_NEUTRAL:
//Ação quando o usuário clicar no botão ok
startActivity(new Intent(telaPrincipal.this, addDebito.class));
break;
}
}
};
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage(String.s04).setTitle("DebitReminder").setNeutralButton("OK", dialogClickListener)
.show();
chkChanges.setAtualizarDebitos(true);
} else {
if (viewpager != null) {
viewpager.removeAllViews();
}
//caso ja tenha debitos chamo os fragmentos
int salvaçao = gdc.getConfAtual().getQualFragTaNaTela();
viewPagerAdapter = new ViewPagerAdapter(getSupportFragmentManager());
viewPagerAdapter.addFragments(new fragChart(), "Gráfico");
viewPagerAdapter.addFragments(new fragDebitos(), "Débitos");
/// viewPagerAdapter.addFragments(new frag_StatMain(), "Estatísticas");
viewpager.setAdapter(viewPagerAdapter);
tabLayout.setupWithViewPager(viewpager);
if (gdc.getConfAtual().isNotificationClick()) {
// seta o fragmento de estatisticas na tela se o usuario chegou aqui clicando em uma notificaçao
viewpager.setCurrentItem(2);
gdc.getConfAtual().setNotificationClick(false);
} else {
// senao seta ao ultimo fragmento na tela
viewpager.setCurrentItem(salvaçao);
}
// iniciando serviço
Intent serviceIntent = new Intent(this.getApplicationContext(), AutoStartUp.class);
this.getApplicationContext().startService(serviceIntent);
}
}
private void showEditFolhaDialogo() {
LayoutInflater inflater = this.getLayoutInflater();
View v = inflater.inflate(R.layout.dialogo_edit_folha, null);
editBuilder = new AlertDialog.Builder(this).create();
txtNome = (TextView) v.findViewById(R.id.txtnome);
txtRenda = (TextView) v.findViewById(R.id.txtRenda);
edtNome = (EditText) v.findViewById(R.id.edtNome);
edtRenda = (EditText) v.findViewById(R.id.edtRenda);
spinner = (Spinner) v.findViewById(R.id.spinner);
imgok = (ImageView) v.findViewById(R.id.imgok);
TextView txttop = (TextView) v.findViewById(R.id.txttop);
txttop.setText(gf.getFolhaAtual().getNome());
ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(this, R.array.meses, android.R.layout.simple_spinner_item);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner.setAdapter(adapter);
String mes = gf.getFolhaAtual().getMes();
int n = 0;
String[] m = {"janeiro1", "fevereiro2", "março3", "abril4", "maio5", "junho6", "julho7", "agosto8", "setembro9", "outubro10", "novembro11", "dezembro12"};
for (int i = 0; i < m.length; i++) {
if (m[i].contains(mes.toLowerCase())) {
n = Integer.parseInt(m[i].replaceAll("[^0123456789]", ""));
break;
}
}
imgok.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if (chkvalores()) {
if (chkIdRepetida()) {
Vibrar();
Toast.makeText(getApplicationContext(), "Já existe uma folha com esse nome.", Toast.LENGTH_LONG).show();
}
if (!chkRendaFolha()) {
Vibrar();
Toast.makeText(getApplicationContext(), "O valor inserído no campo renda é inválido.", Toast.LENGTH_LONG).show();
}
if (chkRendaFolha() && !chkIdRepetida()) {
folha f = gf.getFolhaAtual();
//mantenho as caracteristicas da folha ante dela ser editada
folha oldFolha = new folha();
oldFolha.setNome(f.getNome());
oldFolha.setMes(f.getMes());
oldFolha.setRenda(f.getRenda());
//edito a folha
f.setNome(edtNome.getText().toString() + " ");
f.setMes(spinner.getSelectedItem().toString());
f.setRenda(edtRenda.getText().toString());
boolean ok = gf.escreverFolha(gf.getFolhaAtual(), oldFolha);
if (ok) {
DialogInterface.OnClickListener dialogClickListener = new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
switch (which) {
case DialogInterface.BUTTON_POSITIVE:
}
}
};
AlertDialog.Builder builder = new AlertDialog.Builder(telaPrincipal.this).setPositiveButton("ok", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
}
});
builder.setMessage("Dados da folha foram alterados com sucesso.").setTitle("DebitReminder")
.setPositiveButton("OK", dialogClickListener)
.show();
chkChanges.setAtualizarDebitos(true);
}
editBuilder.dismiss();
} else {
showEditFolhaDialogo();
}
}
return false;
}
});
spinner.setSelection((n - 1), true);
edtNome.setText(gf.getFolhaAtual().getNome());
edtRenda.setText(gf.getFolhaAtual().getRenda());
spinner.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
chkvalores();
return false;
}
});
edtNome.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if (edtNome.getHint().equals("")) {
} else {
txtNome.setText(edtNome.getHint());
YoYo.with(Techniques.FadeInUp).duration(200).playOn(txtNome);
edtNome.setHint("");
}
return false;
}
});
edtNome.setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
if (hasFocus) {
} else {
chkvalores();
}
}
});
edtRenda.setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
if (hasFocus && !edtRenda.getHint().equals("")) {
txtRenda.setText(edtRenda.getHint());
YoYo.with(Techniques.FadeInUp).duration(200).playOn(txtRenda);
edtRenda.setHint("");
} else {
chkvalores();
}
}
});
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
System.out.println(spinner.getItemAtPosition(position));
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
editBuilder.setView(v);
editBuilder.getWindow().getAttributes().windowAnimations = R.style.DialogAnimation;
editBuilder.show();
}
private void showremoveFolhaDialogo() {
gFolhas gf = gFolhas.getInstancia();
final String[] arrayResultados = new String[gf.getTodasAsFolhas().size()];
final ArrayList<folha> arrayFolhas = gf.getTodasAsFolhas();
for (int i = arrayFolhas.size() - 1; i >= 0; i--) {
arrayResultados[i] = (arrayFolhas.get(i).getNome() + "/" + arrayFolhas.get(i).getMes());
}
final android.app.AlertDialog.Builder builder2 = new android.app.AlertDialog.Builder(telaPrincipal.this);
builder2.setTitle(" Qual folha deseja remover? ")
.setItems(arrayResultados, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
gFolhas gf = gFolhas.getInstancia();
if (arrayFolhas.get(which).getNome().equals(gf.getFolhaAtual().getNome())) {
Toast.makeText(getApplicationContext(), "Nâo é possível remover a folha atual.", Toast.LENGTH_LONG).show();
showremoveFolhaDialogo();
} else {
String id = arrayFolhas.get(which).getNome();
showConfirmRemoveDialog(id);
}
}
});
builder2.show();
}
private void showMenu() {
TextView txteditarFolha, txtConfiguraçoes, txtalternarfolhas, txtRemoverFolha, txtGerDebFixos;
LayoutInflater inflater = this.getLayoutInflater();
View v = inflater.inflate(R.layout.dialogo_menu, null);
final AlertDialog builder = new AlertDialog.Builder(telaPrincipal.this).create();
builder.setView(v);
builder.getWindow().getAttributes().windowAnimations = R.style.DialogAnimation;
txtRemoverFolha = (TextView) v.findViewById(R.id.txtremoverFolha);
txtRemoverFolha.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
builder.dismiss();
showremoveFolhaDialogo();
}
});
txteditarFolha = (TextView) v.findViewById(R.id.txteditarFolha);
txteditarFolha.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
builder.dismiss();
showEditFolhaDialogo();
}
});
txtGerDebFixos = (TextView) v.findViewById(R.id.txtgerDebFixos);
txtGerDebFixos.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
builder.dismiss();
startActivity(new Intent(telaPrincipal.this, DebitoFixo.class));
}
});
txtConfiguraçoes = (TextView) v.findViewById(R.id.txtConfiguraçoes);
txtConfiguraçoes.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
}
});
txtalternarfolhas = (TextView) v.findViewById(R.id.txtAlternarfolhas);
txtalternarfolhas.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
gFolhas gf = gFolhas.getInstancia();
final String[] arrayResultados = new String[gf.getTodasAsFolhas().size()];
final ArrayList<folha> arrayFolhas = gf.getTodasAsFolhas();
for (int i = arrayFolhas.size() - 1; i >= 0; i--) {
arrayResultados[i] = (arrayFolhas.get(i).getNome() + "/" + arrayFolhas.get(i).getMes());
}
final android.app.AlertDialog.Builder builder2 = new android.app.AlertDialog.Builder(telaPrincipal.this);
builder2.setTitle(" Qual folha deseja abrir? ")
.setItems(arrayResultados, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
gFolhas gf = gFolhas.getInstancia();
folha f = gf.getFolhaById(arrayFolhas.get(which).getNome());
gf.setFolhaAtual(f);
chkChanges.setAtualizarDebitos(true);
builder.dismiss();
}
});
builder2.show();
}
});
builder.show();
}
private void showChartMenu() {
String[] opçoes = {"Todos os débitos", "Apenas os débitos pagos", "Apenas os débitos em aberto"};
final AlertDialog.Builder builder2 = new AlertDialog.Builder(telaPrincipal.this);
builder2.setTitle(" Quais débitos deseja ver no gráfico? ")
.setItems(opçoes, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
if (which == 0) {
gdc.getConfAtual().setChart(1);
} else if (which == 1) {
gdc.getConfAtual().setChart(2);
} else if (which == 2) {
gdc.getConfAtual().setChart(3);
}
gdc.saveConf(false);
chkChanges.setAtualizarDebitos(true);
}
});
builder2.show();
}
private void showStatMenu() {
String[] opçoes = {"Estatísticas de cada débito"};
final android.app.AlertDialog.Builder builder2 = new android.app.AlertDialog.Builder(telaPrincipal.this);
builder2
.setItems(opçoes, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
if (which == 0) {
startActivity(new Intent(getApplicationContext(), main.todosDebitosestatisticas.class));
}
}
});
builder2.show();
}
private boolean showConfirmRemoveDialog(final String id) {
AlertDialog.Builder builder2 = new AlertDialog.Builder(telaPrincipal.this);
builder2.setTitle(" Tem certeza que deseja remover " + id + "?").setPositiveButton("Sim", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
if (gf.removeById(id)) {
Toast.makeText(getApplicationContext(), "Folha " + id + " foi removida.", Toast.LENGTH_LONG).show();
}
}
}).setNegativeButton("cancelar", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
}
});
builder2.show();
return true;
}
/**
* @return retorna falso se a ID NAO FOR REPETIDA
*/
private boolean chkIdRepetida() {
ArrayList<folha> array = gf.getTodasAsFolhas();
if (!edtNome.getText().toString().equals(gf.getFolhaAtual().getNome())) {
for (int i = 0; i < array.size(); i++) {
if (array.get(i).getNome().equals(edtNome.getText().toString())) {
return true;
}
}
}
return false;
}
private boolean chkvalores() {
boolean v1 = chkIdFolha();
boolean v2 = chkRendaFolha();
if (!chkIdRepetida() && !edtNome.getText().toString().equals("") && !edtRenda.getText().toString().equals("") && v1 && v2) {
imgok.setEnabled(true);
YoYo.with(Techniques.FadeInRight).duration(350).playOn(imgok);
} else {
imgok.setEnabled(false);
YoYo.with(Techniques.FadeOutLeft).duration(350).playOn(imgok);
return false;
}
return true;
}
/**
* obtem do banco a folhas e compara os nomes pra checar se a id ja existe
*
* @return true se estiver tudo Ok com o nome da folha, FALSE se for repetida
*/
private boolean chkIdFolha() {
boolean ok = true;
ArrayList<folha> array = gf.getTodasAsFolhas();
if (array == null) {
return true;
}
//removo todos os . e , pq n pode criar tabelas com esses acentos no DB
edtNome.setText(edtNome.getText().toString().replaceAll("[^abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 ]", ""));
//tabelas tambem n podem conter apenas numeros
if (!ehInteiro(edtNome.getText().toString())) {
ok = false;
} else {
char[] cArray = edtNome.getText().toString().toCharArray();
if (Character.isDigit(cArray[0])) {
ok = false;
}
}
for (int i = array.size() - 1; i >= 0; i--) {
System.out.println("chkId (addFolha)DevInfo folhas : " + array.get(i).getNome());
if (array.get(i).getNome().toLowerCase(Locale.US).equals(edtNome.getText().toString().toLowerCase(Locale.US))) {
if (!edtNome.getText().toString().equals(gf.getFolhaAtual().getNome())) {
ok = false;
break;
}
}
}
// TODO: 30/10/2016 o nome da folha n pode conter . , ou numeros mais os debitos tao podendo
if (ok) {
edtNome.setTextColor(ContextCompat.getColor(telaPrincipal.this, R.color.preto));
} else {
Vibrar();
edtNome.setTextColor(ContextCompat.getColor(telaPrincipal.this, R.color.colorPrimaryDark));
YoYo.with(Techniques.Shake).duration(800).playOn(edtNome);
}
return ok;
}
/**
* checa se tem digitos
*
* @param s variavel que sera checada
* @return TRUE se tiver uma letra senao, FALSE
*/
public boolean ehInteiro(String s) {
// cria um array de char
char[] c = s.toCharArray();
for (int i = 0; i < c.length; i++)
// verifica se o char não é um dígito
if (!Character.isDigit(c[i])) {
return true;
}
return false;
}
String valorFormatado = "";
private boolean chkRendaFolha() {
try {
if (!valorFormatado.equals(edtRenda.getText().toString())) {
BigDecimal v1 = new BigDecimal(edtRenda.getText().toString().replaceAll("\\.", "").replace(",", "."));
BigDecimal v2 = new BigDecimal("0");
v1 = v2.add(v1);
DecimalFormat df = new DecimalFormat("###,##0.00");
valorFormatado = df.format(v1);
edtRenda.setText(valorFormatado);
return true;
}
} catch (Exception e) {
if (!edtRenda.getText().toString().equals("")) {
Vibrar();
edtRenda.setTextColor(ContextCompat.getColor(telaPrincipal.this, R.color.colorPrimaryDark));
YoYo.with(Techniques.Shake).duration(800).playOn(edtRenda);
return false;
}
}
edtRenda.setTextColor(ContextCompat.getColor(telaPrincipal.this, R.color.preto));
return true;
}
private void Vibrar() {
Vibrator rr = (Vibrator) this.getSystemService(Context.VIBRATOR_SERVICE);
long milliseconds = 30;//'30' é o tempo em milissegundos, é basicamente o tempo de duração da vibração. portanto, quanto maior este numero, mais tempo de vibração você irá ter
rr.vibrate(milliseconds);
try {
Thread.sleep(30);
} catch (InterruptedException e) {
e.printStackTrace();
}
rr.vibrate(milliseconds);
}
}
`