Intent: passando objetos com campos não serializáveis
Suponha a seguinte classe Aluno
:
public class Aluno { private String nome; private String telefone;
public Aluno(String nome, String telefone) { this.nome = nome; this.telefone = telefone; } }
Como faríamos para passar uma instância dessa classe para uma Activity?
Como visto nos cursos de Android da Caelum, poderiamos usar o método putExtra()
da Intent
para isso:
Aluno aluno = new Aluno("Felipe", "555-1234");
Intent intent = new Intent(this, OutraActivity.class); intent.putExtra("aluno", aluno); startActivity(intent);
Porém, o putExtra()
não é capaz de receber um Aluno
! Então, temos que implementar a interface Serializable
:
public class Aluno implements Serializable { //... }
Agora a classe Aluno
é capaz de serializar todos os seus atributos que podem ser serializáveis. Porém, o que acontece se a classe Aluno
possuir algum atributo que não é serializável?
Um exemplo disso seria colocar um atributo Context
na nossa classe para exibir um Toast:
public class Aluno { private String nome; private String telefone; private Context context = CaixaPreta.getContext();
public Aluno(String nome, String telefone) { this.nome = nome; this.telefone = telefone; }
public void mostraNome() { Toast.makeText(context, this.nome, Toast.LENGTH\_LONG).show(); } }
Como Context
não é serializável, teremos uma java.io.NotSerializableException
ao chamar o putExtra()
!
Para resolver esse problema, podemos simplesmente ignorar o campo Context
na serialização por meio do modifier transient
:
public class Aluno { private String nome; private String telefone; private transient Context context = CaixaPreta.getContext();
public Aluno(String nome, String telefone) { this.nome = nome; this.telefone = telefone; }
public void mostraNome() { Toast.makeText(context, this.nome, Toast.LENGTH\_LONG).show(); } }
Como poderemos chamar o método mostraNome()
após recuperar o aluno na OutraActivity
?
Intent intent = getIntent(); Aluno recuperado = (Aluno) intent.getSerializableExtra("aluno");
recuperado.mostraNome();
Como ignoramos o campo Context, ao recuperar o aluno o conteúdo de context
será null.
À primeira vista, poderíamos popular o context
no construtor do Aluno
:
public Aluno(String nome, String telefone) { this.nome = nome; this.telefone = telefone; this.context = CaixaPreta.getContext(); }
Porém, o processo de desserialização não chama o construtor da classe. Então ainda teremos um null no context
.
Ao fazer a desserialização do nosso aluno podemos implementar um método chamado readObject
, responsável por popular os campos do objeto desseralizado.
public class Aluno { private String nome; private String telefone; private transient Context context = CaixaPreta.getContext();
public Aluno(String nome, String telefone) { this.nome = nome; this.telefone = telefone; }
public void mostraNome() { Toast.makeText(context, this.nome, Toast.LENGTH\_LONG).show(); }
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); this.context = CaixaPreta.getContext(); } }
Com isso, podemos passar o Aluno
para uma outra Activity e repopular o campo que não é serializável!