Como passar um objeto de uma atividade para outra no Android

779

Estou tentando trabalhar no envio de um objeto do meu cliente classe de de um Activitye exibi-lo em outro Activity.

O código para a classe do cliente:

public class Customer {

    private String firstName, lastName, Address;
    int Age;

    public Customer(String fname, String lname, int age, String address) {

        firstName = fname;
        lastName = lname;
        Age = age;
        Address = address;
    }

    public String printValues() {

        String data = null;

        data = "First Name :" + firstName + " Last Name :" + lastName
        + " Age : " + Age + " Address : " + Address;

        return data;
    }
}

Eu quero enviar seu objeto de um Activity para outro e, em seguida, exibir os dados no outro Activity.

Como posso conseguir isso?

Kaibuki
fonte
1
provavelmente você deve alterar a resposta aceita em vista da opinião de massa.
Rohit Vipin Mathews
Eu costumava definir o objeto como Pacelable ou Serializable, mas sempre que adiciono outras variáveis, tenho que adicionar tudo às funções para obter e definir Pacelable ou Serializable. então fiz o DataCache para transferir entre atividades e fragmentos. github.com/kimkevin/AndroidDataCache É super fácil de transferir objetos.
kimkevin

Respostas:

886

Uma opção pode ser permitir que sua classe personalizada implemente a Serializableinterface e, em seguida, você pode transmitir instâncias de objeto com a intenção extra usando a putExtra(Serializable..)variante doIntent#putExtra() método.

Pseudocódigo :

//To pass:
intent.putExtra("MyClass", obj);

// To retrieve object in second Activity
getIntent().getSerializableExtra("MyClass");

Nota: Verifique se cada classe aninhada da sua classe personalizada principal implementou a interface Serializable para evitar exceções de serialização. Por exemplo:

class MainClass implements Serializable {

    public MainClass() {}

    public static class ChildClass implements Serializable {

        public ChildClass() {}
    }
}
Samuh
fonte
126
@OD: Em minha defesa, nunca disse que essa era a melhor opção; O OP apenas pediu alternativas e eu sugeri uma. Obrigado de qualquer forma.
Samuh 9/05/11
83
Por que Serializable não é uma boa opção? É uma interface bem conhecida, há uma boa chance de que as classes das pessoas já possam implementá-la (ArrayList, por exemplo, já é serializável). Por que você deveria alterar seus objetos de dados para adicionar código extra simplesmente para passá-los de uma classe para outra? Isso parece um projeto ruim. Eu posso imaginar que pode haver algum impacto no desempenho em algum nível, mas acho que em 99% dos casos, as pessoas estão passando pequenas quantidades de dados e elas não se importam. Às vezes, mais simples e portátil também são melhores.
Nate
16
@Ander: Esta resposta ( stackoverflow.com/questions/2139134/… ) está errada então? Ele diz que Parcelable é projetado especificamente para esse fim (e muito mais rápido que Serializable). Eu estou confuso.
Slauma
41
Parcelablepode ser bom para velocidade, mas é complicado de implementar. E se você tiver 8 objetos para passar entre as atividades, você fará cada um Parcelable? Em vez disso, faria mais sentido usar Serializable. Ao implementar, Parcelablevocê precisa adicionar muito código à classe e ordenar os campos de uma maneira muito específica; Serializablevocê não Por fim, acho que tudo se resume a quantos objetos você está passando e o que está tentando fazer.
precisa saber é o seguinte
15
Serializableé uma interface Java padrão. Você simplesmente marca uma classe como serializável ao implantar a interface, e o Java a serializa automaticamente em determinadas situações. Parcelableé uma interface específica do Android em que você mesmo implementa a serialização. Ele foi criado para ser muito mais eficiente que Serializable, e para contornar alguns problemas com o esquema de serialização Java padrão
Gaurav Arora
311

Implemente sua classe com Serializable. Vamos supor que esta seja sua classe de entidade:

import java.io.Serializable;

@SuppressWarnings("serial") //With this annotation we are going to hide compiler warnings
public class Deneme implements Serializable {

    public Deneme(double id, String name) {
        this.id = id;
        this.name = name;
    }

    public double getId() {
        return id;
    }

    public void setId(double id) {
        this.id = id;
    }

    public String getName() {
        return this.name;
    }

    public void setName(String name) {
        this.name = name;
    }

    private double id;
    private String name;
}

Estamos enviando o objeto chamado deneda atividade X para a atividade Y. Em algum lugar da atividade X;

Deneme dene = new Deneme(4,"Mustafa");
Intent i = new Intent(this, Y.class);
i.putExtra("sampleObject", dene);
startActivity(i);

Na atividade Y, estamos obtendo o objeto.

Intent i = getIntent();
Deneme dene = (Deneme)i.getSerializableExtra("sampleObject");

É isso aí.

Mustafa Güven
fonte
1
Foi realmente útil para mim. Obrigado ... Mas ao receber o objeto transmitido, a sintaxe deve ser [Deneme dene = (Deneme) i.getSerializableExtra ("sampleObject"); ] ... É isso ???
JibW
1
@ MustafaGüven Mas estou conseguindo classCastException: java.lang.Longfazer isso. Você pode, por favor, explicar o porquê?
Shajeel Afzal
Não há nenhuma relação com a minha resposta. É uma coisa muito diferente que você está recebendo. Você poderia compartilhar seus códigos?
Mustafa Güven
1
A serialização é muito lenta para POJOs grandes. Usar um ônibus é um padrão muito melhor.
Steven Mark Ford
1
Por que eu deveria ter que prefixar (Serializable)o objeto?
Alston
123
  • Usar variáveis ​​estáticas globais não é uma boa prática de engenharia de software .
  • Converter os campos de um objeto em tipos de dados primitivos pode ser um trabalho agitado .
  • Usar serializável é bom, mas não é eficiente em termos de desempenho em na plataforma Android.
  • Parcelable foi projetado especificamente para Android e você deve usá-lo. Aqui está um exemplo simples: Passando objetos personalizados entre atividades do Android

Você pode gerar código Parcelable para sua classe usando este site .

SohailAziz
fonte
4
E se meu objeto contiver Arraylist aninhada?
Dr. Andro
10
Bem, talvez, mas deve-se realmente levar o `` desempenho '' com um grão de sal. Se isso custar a implementação Parcelable, prefiro manter minhas classes POJO independentes do Android e usá-las Serializable.
VH-NZZ
Não concordo que você deva usar o Parcelable. Um padrão simples de barramento é muito mais eficiente no tempo de execução e economiza muito tempo de desenvolvimento.
Steven Mark Ford
15
De acordo com este benchmark, bitbucket.org/afrishman/androidserializationtest Serializable é muito mais rápido que Parcelable. Pare de compartilhar esse absurdo de 5 anos sobre o Parcelable.
afrish
7
Como as variáveis ​​estáticas globais "não são boas práticas de engenharia de software"? Você pode criar algo como um cache singleton e / ou grade de dados e passar IDs ou similares. Quando você repassa referências em Java, você está usando variáveis ​​estáticas globais em certo sentido, pois elas apontam para o mesmo objeto.
ranhura
112

Use gson para converter seu objeto em JSON e transmiti-lo através da intenção. Na nova atividade, converta o JSON em um objeto.

No seu build.gradle, adicione isso às suas dependências

implementation 'com.google.code.gson:gson:2.8.4'

Na sua atividade, converta o objeto em json-string:

Gson gson = new Gson();
String myJson = gson.toJson(vp);
intent.putExtra("myjson", myjson);

Na sua atividade de recebimento, converta a string json novamente no objeto original:

Gson gson = new Gson();
YourObject ob = gson.fromJson(getIntent().getStringExtra("myjson"), YourObject.class);

Para Kotlin é exatamente o mesmo

Passe os dados

val gson = Gson()
val intent = Intent(this, YourActivity::class.java)
intent.putExtra("identifier", gson.toJson(your_object))
startActivity(intent)

Receba os dados

val gson = Gson()
val yourObject = gson.fromJson<YourObject>(intent.getStringExtra("identifier"), YourObject::class.java)
khalid
fonte
3
É um exagero, o gson é apenas um tipo de serialização de string para o json, é melhor implementar Serializable ou Paracable.
James Roeiter
14
Não há necessidade de implementar serializável em cada objeto e em todo projeto (perda de tempo) se você puder usar uma biblioteca (gson) que lida com isso. E sobre o exagero, existem telefones dual e quadcore por aí, eles podem lidar com até uma lista seguindo essa ideia de resposta.
sagits
4
Eu também recomendaria o uso do gson, porque o gson também pode serializar listas de matrizes além das acima.
Nurgasemetey
4
Isso é ótimo! No meu caso, estou usando uma biblioteca que os objetos não implementam serializável ou parcelável. Portanto, esta é a minha única opção afaik
Chad Bingham
2
Essa é a melhor opção. Algumas classes são tão simples, você não precisa complicar mais a sua implementação através da implementação de serializado
Ojonugwa Jude Ochalifu
98

Ao chamar uma atividade

Intent intent = new Intent(fromClass.this,toClass.class).putExtra("myCustomerObj",customerObj);

No toClass.java, receba a atividade por

Customer customerObjInToClass = getIntent().getExtras().getParcelable("myCustomerObj");

Certifique-se de que a classe do cliente implemente pacotes

public class Customer implements Parcelable {

    private String firstName, lastName, address;
    int age;

    /* all your getter and setter methods */

    public Customer(Parcel in ) {
        readFromParcel( in );
    }

    public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
        public LeadData createFromParcel(Parcel in ) {
            return new Customer( in );
        }

        public Customer[] newArray(int size) {
            return new Customer[size];
        }
    };


    @Override
    public void writeToParcel(Parcel dest, int flags) {

        dest.writeString(firstName);
        dest.writeString(lastName);
        dest.writeString(address);
        dest.writeInt(age);
    }

    private void readFromParcel(Parcel in ) {

        firstName = in .readString();
        lastName  = in .readString();
        address   = in .readString();
        age       = in .readInt();
    }
Publicidades
fonte
Adhavan, eu tenho uma pergunta. Quando você cria a primeira classe Intent, transmite fromClass.this como o primeiro argumento. Existe uma maneira de recuperar esse objeto na classe de atividade de recebimento?
newman
1
Miliu, deClass fr = (deClass) getParent (); é isso que você precisava?
Anúncios
Adhava, eu realmente fiz isso, mas fr é nulo. Alguma idéia do porquê?
newman
miliu, compartilhe seu rastreamento de exceção, para que possamos analisá-lo.
Anúncios
O Parcelable possui muitos códigos de placas de caldeira desnecessários e é francamente uma perda de tempo. Em vez disso, use um ônibus. Veja meu post abaixo.
Steven Mark Ford
89

Na minha experiência, existem três soluções principais, cada uma com suas desvantagens e vantagens:

  1. Implementando Parcelable

  2. Implementando Serializable

  3. Usando algum tipo de biblioteca de barramento de eventos leve (por exemplo, EventBus da Greenrobot ou Otto da Square)

Parcelável - padrão rápido e Android, mas possui muitos códigos padrão e requer seqüências codificadas para referência ao extrair valores da intenção (não fortemente tipada).

Serializável - clichê próximo a zero, mas é a abordagem mais lenta e também requer seqüências codificadas durante a extração de valores da intenção (não fortemente tipada).

Barramento de Eventos - clichê zero, abordagem mais rápida e não requer sequências codificadas, mas requer uma dependência adicional (embora geralmente leve, ~ 40 KB)

Publiquei uma comparação muito detalhada dessas três abordagens, incluindo benchmarks de eficiência.

Steven Mark Ford
fonte
4
O link para o artigo está morto. Ainda disponível no webarchive: web.archive.org/web/20160917213123/http://…
OlivierH
É uma pena que o link está abaixo :(
Mauker
O problema do uso do Barramento de Eventos é quando a Atividade de destino é recriada devido à rotação, por exemplo. Nesse caso, a atividade de destino não tem acesso ao objeto passado porque esse objeto foi consumido do barramento por chamada anterior.
JuliuszJ
1
O Parcelable é o mais rápido e, com esse gerador ( parcelabler.com ), você pode colar sua classe e gerar o código para você. Simples.
precisa
1
@ ByyWaleed ... Eu concordo absolutamente, eu sempre uso este site, cria coisas sem problemas. No entanto, tive muitas tentativas malsucedidas, quando tento usar um POJO que é composto por outro Objeto. Por alguma razão, sua colocação não funciona realmente.
Yo Apps
42

Encontrei um método simples e elegante:

  • SEM Parcelável
  • NÃO serializável
  • SEM campo estático
  • No Event Bus

Método 1

Código para a primeira atividade:

    final Object objSent = new Object();
    final Bundle bundle = new Bundle();
    bundle.putBinder("object_value", new ObjectWrapperForBinder(objSent));
    startActivity(new Intent(this, SecondActivity.class).putExtras(bundle));        
    Log.d(TAG, "original object=" + objSent);

Código para a segunda atividade:

    final Object objReceived = ((ObjectWrapperForBinder)getIntent().getExtras().getBinder("object_value")).getData();
    Log.d(TAG, "received object=" + objReceived);

você encontrará objSente objReceivedterá o mesmohashCode , então eles são idênticos.

Mas por que podemos passar um objeto java dessa maneira?

Na verdade, o fichário do Android criará uma referência JNI global para o objeto java e liberará essa referência JNI global quando não houver uma referência para esse objeto java. O fichário salvará essa referência JNI global no objeto Binder.

* CUIDADO: esse método funciona apenas a menos que as duas atividades sejam executadas no mesmo processo; caso contrário, jogue ClassCastException em (ObjectWrapperForBinder) getIntent (). GetExtras (). GetBinder ("object_value") *

classe definição de ObjectWrapperForBinder

public class ObjectWrapperForBinder extends Binder {

    private final Object mData;

    public ObjectWrapperForBinder(Object data) {
        mData = data;
    }

    public Object getData() {
        return mData;
    }
}

Método 2

  • para o remetente,
    1. use o método nativo personalizado para adicionar seu objeto java à tabela de referência global da JNI (via JNIEnv :: NewGlobalRef)
    2. coloque o número inteiro de retorno (na verdade, JNIEnv :: NewGlobalRef return jobject, que é um ponteiro, podemos convertê-lo para int com segurança) no Intent (via Intent :: putExtra)
  • para o receptor
    1. obter número inteiro de Intent (via Intent :: getInt)
    2. use o método nativo customizado para restaurar seu objeto java da tabela de referência global JNI (via JNIEnv :: NewLocalRef)
    3. remova o item da tabela de referência global JNI (via JNIEnv :: DeleteGlobalRef),

Mas o Método 2 tem um problema pequeno, mas sério, se o receptor falhar ao restaurar o objeto java (por exemplo, alguma exceção ocorre antes de restaurar o objeto java ou a Atividade do receptor não existir), o objeto java se tornará um órfão ou vazamento de memória, o método 1 não tem esse problema, porque o fichário do Android lidará com essa exceção

Método 3

Para chamar o objeto java remotamente, criaremos um contrato / interface de dados para descrever o objeto java, usaremos o arquivo aidl

IDataContract.aidl

package com.example.objectwrapper;
interface IDataContract {
    int func1(String arg1);
    int func2(String arg1);
}

Código para a primeira atividade

    final IDataContract objSent = new IDataContract.Stub() {

        @Override
        public int func2(String arg1) throws RemoteException {
            // TODO Auto-generated method stub
            Log.d(TAG, "func2:: arg1=" + arg1);
            return 102;
        }

        @Override
        public int func1(String arg1) throws RemoteException {
            // TODO Auto-generated method stub
            Log.d(TAG, "func1:: arg1=" + arg1);
            return 101;
        }
    };
    final Bundle bundle = new Bundle();
    bundle.putBinder("object_value", objSent.asBinder());
    startActivity(new Intent(this, SecondActivity.class).putExtras(bundle));
    Log.d(TAG, "original object=" + objSent);

Código para a segunda atividade:

altere o atributo android: process no AndroidManifest.xml para um nome de processo não vazio para garantir que a segunda atividade seja executada em outro processo

    final IDataContract objReceived = IDataContract.Stub.asInterface(getIntent().getExtras().getBinder("object_value"));
    try {
        Log.d(TAG, "received object=" + objReceived + ", func1()=" + objReceived.func1("test1") + ", func2()=" + objReceived.func2("test2"));
    } catch (RemoteException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

Dessa maneira, podemos transmitir uma interface entre duas atividades, mesmo que elas sejam executadas em processos diferentes, e chamar o método da interface remotamente

Método 4

O método 3 parece não ser simples o suficiente, porque precisamos implementar uma interface de auxílio. Se você quiser apenas uma tarefa simples e o valor de retorno do método for desnecessário, podemos usar android.os.Messenger

Código da primeira atividade (remetente):

public class MainActivity extends Activity {
    private static final String TAG = "MainActivity";

    public static final int MSG_OP1 = 1;
    public static final int MSG_OP2 = 2;

    public static final String EXTRA_MESSENGER = "messenger";

    private final Handler mHandler = new Handler() {

        @Override
        public void handleMessage(Message msg) {
            // TODO Auto-generated method stub
            Log.e(TAG, "handleMessage:: msg=" + msg);
            switch (msg.what) {
            case MSG_OP1:

                break;
            case MSG_OP2:
                break;

            default:

                break;
            }
            super.handleMessage(msg);
        }

    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        startActivity(new Intent(this, SecondActivity.class).putExtra(EXTRA_MESSENGER, new Messenger(mHandler)));
    }
}

Código para a segunda atividade (destinatário):

public class SecondActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);

        final Messenger messenger = getIntent().getParcelableExtra(MainActivity.EXTRA_MESSENGER);
        try {
            messenger.send(Message.obtain(null, MainActivity.MSG_OP1, 101, 1001, "10001"));
            messenger.send(Message.obtain(null, MainActivity.MSG_OP2, 102, 1002, "10002"));
        } catch (RemoteException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }
}

Todo o Messenger.send será executado em um manipulador de forma assíncrona e seqüencial.

Na verdade, android.os.Messenger também é uma interface de auxílio, se você tiver o código-fonte do Android, poderá encontrar um arquivo chamado IMessenger.aidl

package android.os;

import android.os.Message;

/** @hide */
oneway interface IMessenger {
    void send(in Message msg);
}
Yessy
fonte
Desculpe, eu não vi que você tivesse uma resposta vinculativa, bem como, sinto que sua resposta também é muito elegante.
SkidRunner 13/07/2016
Uau .... método 1º deste homem é enorme ..... Quando você tem muito grandes objetos de tamanho / maiores que funciona bem
karan
Eu uso o método one.So, você economiza meu tempo. obrigado;
ShweLiam 16/11/19
Muito obrigado pelo método ObjectWrapperForBinder, realmente ajuda!
Vladimir Tolstikov
40

Você também pode gravar os dados do objeto em Strings e ints temporários e passá-los para a atividade. É claro que dessa forma, você obtém os dados transportados, mas não o próprio objeto.

Mas se você apenas deseja exibi-los, e não usar o objeto em outro método ou algo parecido, isso deve ser suficiente. Fiz da mesma maneira apenas para exibir dados de um objeto em outra atividade.

String fName_temp   = yourObject.getFname();
String lName_temp   = yourObject.getLname();
String age_temp     = yourObject.getAge();
String address_temp = yourObject.getAddress();

Intent i = new Intent(this, ToClass.class);
i.putExtra("fname", fName_temp);
i.putExtra("lname", lName_temp);
i.putExtra("age", age_temp);
i.putExtra("address", address_temp);

startActivity(i);

Você também pode passá-los diretamente ao invés dos temporários, mas dessa forma fica mais claro, na minha opinião. Além disso, você pode definir os valores temporários para nulos, para que sejam limpos pelo GarbageCollector mais cedo.

Boa sorte!

Em uma nota lateral: substitua toString () em vez de escrever seu próprio método de impressão.

Conforme mencionado nos comentários abaixo, é assim que você recupera seus dados em outra atividade:

String fName = getIntent().getExtras().getInt("fname");
MJB
fonte
9
recupere seus dados novamente com: String fName = getIntent (). getExtras (). getInt ("fname");
Alister
2
Para recuperar os dados: Bundle extras = getIntent().getExtras(); String val = extras.getString("fname");
Eric Leschinski
1
Isso pode rapidamente se tornar inviável para grandes POJOs. Em vez disso, use um ônibus. Veja meu post abaixo.
Steven Mark Ford
como mencionei na minha resposta, isso é para casos simples de uso em que você não precisa do objeto em si, mas apenas alguns valores dele. Não é mentira ser uma solução para casos complexos.
MJB 31/07
1
Boa idéia para passar um único objeto, mas estou tentando passar uma matriz de tamanho desconhecido do meu objeto. Talvez sua solução não seja para passar matrizes de objetos.
Muhammad Saqib
25

Eu fiz uma classe auxiliar única que contém objetos temporários.

public class IntentHelper {

    private static IntentHelper _instance;
    private Hashtable<String, Object> _hash;

    private IntentHelper() {
        _hash = new Hashtable<String, Object>();
    }

    private static IntentHelper getInstance() {
        if(_instance==null) {
            _instance = new IntentHelper();
        }
        return _instance;
    }

    public static void addObjectForKey(Object object, String key) {
        getInstance()._hash.put(key, object);
    }

    public static Object getObjectForKey(String key) {
        IntentHelper helper = getInstance();
        Object data = helper._hash.get(key);
        helper._hash.remove(key);
        helper = null;
        return data;
    }
}

Em vez de colocar seus objetos no Intent, use IntentHelper:

IntentHelper.addObjectForKey(obj, "key");

Dentro da sua nova atividade, você pode obter o objeto:

Object obj = (Object) IntentHelper.getObjectForKey("key");

Lembre-se de que, uma vez carregado, o objeto é removido para evitar referências desnecessárias.

Roger Sanoli
fonte
1
Boa ideia! Além disso, você pode criar uma classe adicional ObjectContainer {Object, obj; permanente booleano; ....} A idéia é que você pode passar um booleano no método add se precisar manter o objeto persistente e não remover quando chamarmos get. Isso ajudará a manter alguns objetos globais. Como pode ser uma conexão bluetooth aberta etc.
Umair
1
Bonito, mas não reinvente a roda. O padrão de barramento é elegante e mais poderoso. Veja meu post abaixo.
Steven Mark Ford
@StevenMarkFord O padrão de barramento ainda é válido até hoje? Eu estou tentando melhorar uma base de código com um código como este acessando dados entre atividades: BookActivity.getInstance().recommendationResponseinRoomsActivity
Woppi
Quando a Atividade receptora é recriada (por exemplo, na rotação da tela) objse torna null. Para evitar isso, objdeve ser armazenado em algum lugar para obtê-lo novamente. De fato, a solução Json armazena dados de objetos no Intent.
Salvador
25

Existem algumas maneiras pelas quais você pode acessar variáveis ​​ou objetos em outras classes ou atividades.

A. Banco de Dados

B. Preferências compartilhadas.

C. Serialização de objetos.

D. Uma classe que pode conter dados comuns pode ser nomeada como Utilitários Comuns. Depende de você.

E. Passagem de dados através de Intents e Parcelable Interface.

Depende das necessidades do seu projeto.

A. Banco de Dados

SQLite é um banco de dados de código aberto incorporado ao Android. O SQLite suporta recursos padrão de banco de dados relacional, como sintaxe SQL, transações e instruções preparadas.

Tutoriais

B. Preferências compartilhadas

Suponha que você queira armazenar o nome de usuário. Portanto, agora haverá duas coisas, um nome de usuário chave , valor valor.

Como guardar

 // Create object of SharedPreferences.
 SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this);

 //Now get Editor
 SharedPreferences.Editor editor = sharedPref.edit();

 //Put your value
 editor.putString("userName", "stackoverlow");

 //Commits your edits
 editor.commit();

Usando putString (), putBoolean (), putInt (), putFloat () e putLong (), você pode salvar o tipo de dt desejado.

Como buscar

SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this);
String userName = sharedPref.getString("userName", "Not Available");

http://developer.android.com/reference/android/content/SharedPreferences.html

C. Serialização de objetos

A serlização de objetos é usada se queremos salvar um estado de objeto para enviá-lo por uma rede ou se você pode usá-lo também para sua finalidade.

Use Java beans e armazene-o como um de seus campos e use getters e setter para isso.

JavaBeans são classes Java que possuem propriedades. Pense nas propriedades como variáveis ​​de instância privada. Como eles são particulares, a única maneira de acessá-los de fora da classe é através dos métodos da classe. Os métodos que alteram o valor de uma propriedade são chamados métodos setter, e os métodos que recuperam o valor de uma propriedade são chamados métodos getter.

public class VariableStorage implements Serializable  {

    private String inString;

    public String getInString() {
        return inString;
    }

    public void setInString(String inString) {
        this.inString = inString;
    }
}

Defina a variável no seu método de email usando

VariableStorage variableStorage = new VariableStorage();
variableStorage.setInString(inString);

Em seguida, use a serialização de objetos para serializar esse objeto e em sua outra classe desserializar esse objeto.

Na serialização, um objeto pode ser representado como uma sequência de bytes que inclui os dados do objeto, além de informações sobre o tipo do objeto e os tipos de dados armazenados no objeto.

Depois que um objeto serializado é gravado em um arquivo, ele pode ser lido e desserializado. Ou seja, as informações de tipo e bytes que representam o objeto e seus dados podem ser usados ​​para recriar o objeto na memória.

Se você deseja um tutorial para isso, consulte:

D. Utilidades comuns

Você pode fazer uma aula sozinho, que pode conter dados comuns que você precisa com freqüência em seu projeto.

Amostra

public class CommonUtilities {

    public static String className = "CommonUtilities";

}

E. Passando dados pelas intenções

Consulte o tutorial Android - Dados do pacote para passar entre Atividades usando classes Parcelable para esta opção de passagem de dados.

Nikhil Agrawal
fonte
22

Crie sua própria classe da Customerseguinte maneira:

import import java.io.Serializable;
public class Customer implements Serializable
{
    private String name;
    private String city;

    public Customer()
    {

    }
    public Customer(String name, String city)
    {
        this.name= name;
        this.city=city;
    }
    public String getName() 
    {
        return name;
    }
    public void setName(String name) 
    {
        this.name = name;
    }
    public String getCity() 
    {
        return city;
    }
    public void setCity(String city) 
    {
        this.city= city;
    }

}

No seu onCreate()método

@Override
protected void onCreate(Bundle savedInstanceState) 
{
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.activity_top);

    Customer cust=new Customer();
    cust.setName("abc");
    cust.setCity("xyz");

    Intent intent=new Intent(abc.this,xyz.class);
    intent.putExtra("bundle",cust);
    startActivity(intent); 
}

Na xyz activityaula, você precisa usar o seguinte código:

Intent intent=getIntent();
Customer cust=(Customer)intent.getSerializableExtra("bundle");
textViewName.setText(cust.getName());
textViewCity.setText(cust.getCity());
Mayur Chudasama
fonte
..Check seu código que você está passando "pacote" como chave para colocar cust obj & recebendo a partir de "classe" ..pls usar uma chave quer "classe" ou "pacote" ..
AK Joshi
I rosto Erro: Parcelable encontrou IOException escrever objeto serializado
Arul Mani
15

A melhor maneira é ter uma classe (chamada Control) em seu aplicativo que conterá uma variável estática do tipo 'Customer' (no seu caso). Inicialize a variável em sua Atividade A.

Por exemplo:

Control.Customer = CustomerClass;

Em seguida, vá para a Atividade B e busque-a na classe Control. Não se esqueça de atribuir um nulo depois de usar a variável, caso contrário, a memória será desperdiçada.

Umesh
fonte
4
@ aez Porque é desleixado do ponto de vista do design e quebrará terrivelmente se o Intent estiver em outro processo.
7
Você terá problemas ao retomar seu aplicativo para a Atividade B. Como a Atividade pode ser eliminada pelo Android e o objeto não será salvo.
Ryan R
15
public class MyClass implements Serializable{
    Here is your instance variable
}

Agora você deseja passar o objeto desta classe em startActivity. Simplesmente use isto:

Bundle b = new Bundle();
b.putSerializable("name", myClassObject);
intent.putExtras(b);

Isso funciona aqui porque o MyClass é implementado Serializable.

Dhiral Pandya
fonte
você pode explicar ou elaborar mais
Amitsharma
HomeworkData homeworkData = homeWorksList.get (position); Intenção intenção = nova Intenção (c, HomeWorkActivitydetail.class); Pacote b = novo pacote (); b.putSerializable ("CompleteData", homeworkData); intent.putExtras (b); c.startActivity (intenção); em um momento de objeto add me dá algum erro para adicionar elementos do objeto que não pode passar objeto completo com este
Amitsharma
Eu estou tendo alguns valores, estes são adicionados
Amitsharma #
12

Se você optar por usar da maneira que o Samuh descreve, lembre-se de que apenas valores primitivos podem ser enviados. Ou seja, valores que são parceláveis. Portanto, se seu objeto contiver objetos complexos, eles não serão seguidos. Por exemplo, variáveis ​​como Bitmap, HashMap etc ... Elas são difíceis de passar pela intenção.

Em geral, eu conselho você daria para enviar tipos de dados única primitivos como extras, como String, int, boolean etc. No seu caso seria: String fname, String lname, int age, eString address .

Minha opinião: Objetos mais complexos são melhor compartilhados com a implementação de um ContentProvider , SDCard , etc. Também é possível usar uma variável estática , mas isso pode levar rapidamente a códigos propensos a erros ...

Mas, novamente, é apenas a minha opinião subjetiva.

Vidar Vestnes
fonte
8

Estou usando o parcelable para enviar dados de uma atividade para outra atividade. Aqui está o meu código que funciona bem no meu projeto.

public class Channel implements Serializable, Parcelable {

    /**  */
    private static final long serialVersionUID = 4861597073026532544L;

    private String cid;
    private String uniqueID;
    private String name;
    private String logo;
    private String thumb;


    /**
     * @return The cid
     */
    public String getCid() {
        return cid;
    }

    /**
     * @param cid
     *     The cid to set
     */
    public void setCid(String cid) {
        this.cid = cid;
    }

    /**
     * @return The uniqueID
     */
    public String getUniqueID() {
        return uniqueID;
    }

    /**
     * @param uniqueID
     *     The uniqueID to set
     */
    public void setUniqueID(String uniqueID) {
        this.uniqueID = uniqueID;
    }

    /**
     * @return The name
     */
    public String getName() {
        return name;
    }

    /**
     * @param name
     *            The name to set
     */
    public void setName(String name) {
        this.name = name;
    }

    /**
     * @return the logo
     */
    public String getLogo() {
        return logo;
    }

    /**
     * @param logo
     *     The logo to set
     */
    public void setLogo(String logo) {
        this.logo = logo;
    }

    /**
     * @return the thumb
     */
    public String getThumb() {
        return thumb;
    }

    /**
     * @param thumb
     *     The thumb to set
     */
    public void setThumb(String thumb) {
        this.thumb = thumb;
    }


    public Channel(Parcel in) {
        super();
        readFromParcel(in);
    }

    public static final Parcelable.Creator<Channel> CREATOR = new Parcelable.Creator<Channel>() {
        public Channel createFromParcel(Parcel in) {
            return new Channel(in);
        }

        public Channel[] newArray(int size) {

            return new Channel[size];
        }
    };

    public void readFromParcel(Parcel in) {
        String[] result = new String[5];
        in.readStringArray(result);

        this.cid = result[0];
        this.uniqueID = result[1];
        this.name = result[2];
        this.logo = result[3];
        this.thumb = result[4];
    }

    public int describeContents() {
        return 0;
    }

    public void writeToParcel(Parcel dest, int flags) {

        dest.writeStringArray(new String[] { this.cid, this.uniqueID,
                this.name, this.logo, this.thumb});
    }
}

Em activityA, use-o assim:

Bundle bundle = new Bundle();
bundle.putParcelableArrayList("channel",(ArrayList<Channel>) channels);
Intent intent = new Intent(ActivityA.this,ActivityB.class);
intent.putExtras(bundle);
startActivity(intent);

No ActivityB, use-o assim para obter dados:

Bundle getBundle = this.getIntent().getExtras();
List<Channel> channelsList = getBundle.getParcelableArrayList("channel");
Bebin TN
fonte
7

Você pode tentar usar essa classe. A limitação é que ele não pode ser usado fora de um processo.

Uma atividade:

 final Object obj1 = new Object();
 final Intent in = new Intent();
 in.putExtra(EXTRA_TEST, new Sharable(obj1));

Outra atividade:

final Sharable s = in.getExtras().getParcelable(EXTRA_TEST);
final Object obj2 = s.obj();

public final class Sharable implements Parcelable {

    private Object mObject;

    public static final Parcelable.Creator < Sharable > CREATOR = new Parcelable.Creator < Sharable > () {
        public Sharable createFromParcel(Parcel in ) {
            return new Sharable( in );
        }


        @Override
        public Sharable[] newArray(int size) {
            return new Sharable[size];
        }
    };

    public Sharable(final Object obj) {
        mObject = obj;
    }

    public Sharable(Parcel in ) {
        readFromParcel( in );
    }

    Object obj() {
        return mObject;
    }


    @Override
    public int describeContents() {
        return 0;
    }


    @Override
    public void writeToParcel(final Parcel out, int flags) {
        final long val = SystemClock.elapsedRealtime();
        out.writeLong(val);
        put(val, mObject);
    }

    private void readFromParcel(final Parcel in ) {
        final long val = in .readLong();
        mObject = get(val);
    }

    /////

    private static final HashMap < Long, Object > sSharableMap = new HashMap < Long, Object > (3);

    synchronized private static void put(long key, final Object obj) {
        sSharableMap.put(key, obj);
    }

    synchronized private static Object get(long key) {
        return sSharableMap.remove(key);
    }
}
Barbariska
fonte
6

Inicie outra atividade a partir dessa atividade e transmita parâmetros via Bundle Object

Intent intent = new Intent(getBaseContext(), YourActivity.class);
intent.putExtra("USER_NAME", "[email protected]");
startActivity(intent);

Recuperar dados em outra atividade (YourActivity)

String s = getIntent().getStringExtra("USER_NAME");

Isso é bom para tipos simples de dados. Mas se você deseja passar dados complexos entre as atividades. Você precisa serializar primeiro.

Aqui temos o modelo de funcionário

class Employee{
    private String empId;
    private int age;
    print Double salary;

    getters...
    setters...
}

Você pode usar o Gson lib fornecido pelo google para serializar dados complexos como este

String strEmp = new Gson().toJson(emp);
Intent intent = new Intent(getBaseContext(), YourActivity.class);
intent.putExtra("EMP", strEmp);
startActivity(intent);

Bundle bundle = getIntent().getExtras();
String empStr = bundle.getString("EMP");
            Gson gson = new Gson();
            Type type = new TypeToken<Employee>() {
            }.getType();
            Employee selectedEmp = gson.fromJson(empStr, type);
DroidNinja
fonte
TypeToken <> está obsoleto. Qual é a alternativa?
Ragavendra M
6

Esta questão também é discutida em outra questão do Stack Overflow. Veja uma solução para a transmissão de dados através da intenção usando Serializable . O ponto principal é sobre o uso de Bundleobjetos que armazenam os dados necessários dentro Intent.

 Bundle bundle = new Bundle();

 bundle.putSerializable(key1, value1);
 bundle.putSerializable(key2, value2);
 bundle.putSerializable(key3, value3);

 intent.putExtras(bundle);

Para extrair valores:

 Bundle bundle = new Bundle();

 for (String key : bundle.keySet()) {
 value = bundle.getSerializable(key));
 }

A vantagem Serializableé a sua simplicidade. No entanto, considere usar o Parcelablemétodo se precisar de muitos dados para serem transferidos, porque Parcelablefoi projetado especificamente para Android e é mais eficiente que Serializable. Você pode criar uma Parcelableclasse usando:

  1. uma ferramenta online - parcelabler
  2. um plugin para o Android Studio - Android Parcelable code generator
Ayaz Alifov
fonte
5

Crie uma classe como a classe bean e implemente a Serializableinterface. Então, podemos passar pelo intentmétodo, por exemplo:

intent.putExtra("class", BeanClass);

Em seguida, obtenha-o da outra atividade, por exemplo:

BeanClass cb = intent.getSerializableExtra("class");
Peter Mortensen
fonte
5

Crie dois métodos em sua classe personalizada como esta

public class Qabir {

    private int age;
    private String name;

    Qabir(){
    }

    Qabir(int age,String name){
        this.age=age; this.name=name;
    }   

    // method for sending object
    public String toJSON(){
        return "{age:" + age + ",name:\"" +name +"\"}";
    }

    // method for get back original object
    public void initilizeWithJSONString(String jsonString){

        JSONObject json;        
        try {
            json =new JSONObject(jsonString );
            age=json.getInt("age");
            name=json.getString("name");
        } catch (JSONException e) {
            e.printStackTrace();
        } 
    }
}

Agora, no seu remetente Activity, faça o seguinte

Qabir q= new Qabir(22,"KQ");    
Intent in=new Intent(this,SubActivity.class);
in.putExtra("obj", q.toJSON());
startActivity( in);

E no seu receptor Atividade

Qabir q =new Qabir();
q.initilizeWithJSONString(getIntent().getStringExtra("obj"));
Q07
fonte
3

Sim, o uso de um objeto estático é de longe a maneira mais fácil de fazer isso com objetos personalizados não serializáveis.

alistair
fonte
Sim, acho que concordo com você. Criar esses objetos staticé a melhor solução alternativa, se for simplesmente impraticável continuar invocando putExtra()todas as propriedades que você deseja transmitir. Por exemplo, agora, quero passar um ArrayListque contenha objetos. Eu também poderia criar meu ArrayList static.
Matthew Quiros
3

Os objetos da atividade do Android podem ser destruídos e reconstituídos. Portanto, você precisará usar outra abordagem para procurá- los - ou qualquer objeto que eles criarem !!! - acima. Ou seja, você pode passar como referência de classe estática, mas o identificador de objeto (Java chama essas "referências", como o SmallTalk; mas elas não são referências no sentido de C ou montagem) possivelmente será inválido posteriormente porque um "recurso" do Android OE é qualquer atividade que pode ser aniquilada e reconstituída posteriormente.

A pergunta original perguntou "Como passar um objeto de uma atividade para outra no Android" e ninguém respondeu a isso. Com certeza, você pode serializar (Serializable, Parcelable, de / para JSON) e passar uma cópia dos dados do objeto e um novo objeto com os mesmos dados pode ser criado; mas NÃO terá as mesmas referências / identificadores. Além disso, muitos outros mencionaram que você pode armazenar a referência em um armazenamento estático. E isso funcionará a menos que o Android decida destruir sua atividade.

Portanto, para realmente resolver a questão original, você precisaria de uma pesquisa estática e cada objeto atualizará sua referência quando / se for recriado. Por exemplo, cada atividade do Android se revistaria se seu onCreate for chamado. Você também pode ver como algumas pessoas usam a lista de tarefas para pesquisar uma Atividade pelo nome. (o sistema está destruindo temporariamente esta instância da atividade para economizar espaço .. getRunningTasks, a lista de tarefas é efetivamente uma lista especializada da instância de objeto mais recente de cada atividade).

Para referência:

Parado: "A atividade está completamente obscurecida por outra atividade (a atividade agora está em" plano de fundo "). Uma atividade parada também ainda está ativa (o objeto Activity é retido na memória , mantém todas as informações de estado e membro, mas não é conectado ao gerenciador de janelas). No entanto, não é mais visível ao usuário e pode ser eliminado pelo sistema quando a memória é necessária em outro local. "

onDestroy "o sistema está destruindo temporariamente esta instância da atividade para economizar espaço."

Portanto, o barramento de mensagens é uma solução viável. Basicamente, "pontapés". Em vez de tentar ter referências a objetos; então você re-arquiteta seu design para usar MessagePassing em vez de SequentialCode. Exponencialmente mais difícil de depurar; mas permite que você ignore esse tipo de entendimento do OperatingEnvironment. Efetivamente, cada acesso ao método de objeto é invertido para que o chamador publique uma mensagem e o próprio objeto defina um manipulador para essa mensagem. Muito mais código, mas pode torná-lo robusto com as restrições do Android OE.

Se tudo o que você deseja é a Atividade principal (coisa típica nos aplicativos Android devido à necessidade de "Contexto" em qualquer lugar)), basta que cada Atividade seja listada como "superior" no espaço estático global sempre que seu onResume for chamado. Em seguida, seu AlertDialog ou qualquer outro que precise de um contexto pode capturá-lo a partir daí. Além disso, é um pouco estranho usar um global, mas pode simplificar a passagem de um Contexto para cima e para baixo em todos os lugares e, com certeza, quando você usa um MessageBus, o TI é global de qualquer maneira.

TimJowers2
fonte
Otto tem a capacidade de executá-lo externamente em um aplicativo Java simples e antigo. Então, bom para desenvolvedores e testes sem ter que mexer com o Android. O Otto possui uma grande curva de aprendizado e a maior parte do que ele resolve já está resolvida de maneiras Android (transmissão local etc.) ou em abordagens normais de desenvolvedores de aplicativos (você pode escrever uma pesquisa global muito mais simples do que a pesquisa global da Otto, as abordagens normais são muito mais acessível para a vetorização / F3 através do código e para a depuração).
precisa saber é o seguinte
2
  1. Eu sei que a estática é ruim, mas parece que somos forçados a usá-la aqui. O problema com parceables / seriazables é que as duas atividades têm instâncias duplicadas do mesmo objeto = desperdício de memória e CPU.

    public class IntentMailBox {
        static Queue<Object> content = new LinkedList<Object>();
    }

Atividade de chamada

IntentMailBox.content.add(level);
Intent intent = new Intent(LevelsActivity.this, LevelActivity.class);
startActivity(intent);

Atividade chamada (observe que onCreate () e onResume () podem ser chamados várias vezes quando o sistema destrói e recria atividades)

if (IntentMailBox.content.size()>0)
    level = (Level) IntentMailBox.content.poll();
else
    // Here you reload what you have saved in onPause()
  1. Outra maneira é declarar um campo estático da classe que você deseja passar nessa mesma classe. Servirá apenas para esse fim. Não esqueça que ele pode ser nulo no onCreate, porque seu pacote de aplicativos foi descarregado da memória pelo sistema e recarregado posteriormente.

  2. Tendo em mente que você ainda precisa lidar com o ciclo de vida da atividade, convém gravar todos os dados diretamente nas preferências compartilhadas, exigindo estruturas de dados complexas.

Anton Duzenko
fonte
1

As respostas acima quase todas corretas, mas para quem não entende essas respostas, o Android possui a poderosa classe Intent. Com a ajuda, você compartilha dados entre não apenas a atividade, mas também outros componentes do Android (receptor de radiodifusão, servis para conteúdo, desde que utilizemos a classe ContetnResolver no Intent ) Em sua atividade, você cria intenção

Intent intent = new Intent(context,SomeActivity.class);
intent.putExtra("key",value);
startActivity(intent);

Em sua atividade recorrente, você tem

public class SomeActivity extends AppCompactActivity {

    public void onCreate(...){
    ...
          SomeObject someObject = getIntent().getExtras().getParceable("key");
    }

}

Você precisa implementar a interface Parceable ou Serializable no seu objeto para compartilhar entre as atividades. É difícil implementar o Parcealbe em vez da interface serializável no objeto, por isso o android possui um plugin especialmente para isso.

dara
fonte
0

Eu sempre me perguntei por que isso não pode ser tão simples quanto chamar um método da outra atividade. Recentemente, escrevi uma biblioteca de utilidades que a torna quase tão simples quanto isso. Você pode conferir aqui ( https://github.com/noxiouswinter/gnlib_android/wiki/gnlauncher ).

O GNLauncher torna o envio de objetos / dados para uma atividade de outra atividade etc tão fácil quanto chamar uma função nessa atividade com os dados necessários como parâmetros. Ele introduz a segurança de tipo e remove todas as dificuldades de ter que serializar, anexando à intenção usando chaves de string e desfazendo a mesma na outra extremidade.

Uso

Defina uma interface com os métodos que você deseja chamar na Atividade para iniciar.

public interface IPayload {
    public void sayHello(String name, int age);
}

Implemente a interface acima na Atividade para iniciar. Notifique também o GNLauncher quando a atividade estiver pronta.

public class Activity_1 extends Activity implements IPayload {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //Notify GNLauncher when the Activity is ready. 
        GNLauncher.get().ping(this);
    }

    @Override
    public void sayHello(String name, int age) {
        Log.d("gnlib_test", "Hello " + name + "! \nYour age is: " + age);
    }
}

Na outra atividade, obtenha um proxy para a atividade acima e chame qualquer método com os parâmetros desejados.

public class Activity_2 extends Activity {
    public void onClick(View v) {
        ((IPayload)GNLauncher.get().getProxy(this, IPayload.class, Activity_1.class)).sayHello(name, age);
    }
}

A primeira atividade será iniciada e o método chamado com os parâmetros necessários.

Pré-requisitos

Consulte https://github.com/noxiouswinter/gnlib_android/wiki#prerequisites para obter informações sobre como adicionar as dependências.

jinais
fonte
0

Passe o objeto de uma atividade para outra.

(1) atividade de origem

Intent ii = new Intent(examreport_select.this,
                    BarChartActivity.class);

            ii.putExtra("IntentExamResultDetail",
                    (Serializable) your List<ArraList<String>> object here);
            startActivity(ii);

(2) atividade de destino

List<ArrayList<String>> aa = (List<ArrayList<String>>) getIntent()
            .getSerializableExtra("IntentExamResultDetail");
Jayesh Kalkani
fonte
0

Eu costumava definir objetos com Pacelable ou Serializable para transferir, mas sempre que adiciono outras variáveis ​​ao objeto (modelo), tenho que registrar tudo. É tão inconveniente.

É super fácil transferir objetos entre atividades ou fragmentos.

Android DataCache

kimkevin
fonte
0

Podemos passar o objeto de uma atividade para outra:

SupplierDetails poSuppliersDetails = new SupplierDetails();

Dentro poSuppliersDetailstemos alguns valores. Agora estou enviando este objeto para a atividade de destino:

Intent iPODetails = new Intent(ActivityOne.this, ActivityTwo.class);
iPODetails.putExtra("poSuppliersDetails", poSuppliersDetails);

Como obter isso no ACtivityTwo:

private SupplierDetails supplierDetails;
    supplierDetails =(SupplierDetails) getIntent().getSerializableExtra("poSuppliersDetails");
Peter Mortensen
fonte
0

Passe uma atividade para outra:

startActivity(new Intent(getBaseContext(),GetActivity.class).putExtra("passingkey","passingvalue"));

Obter valores:

String myvalue= getIntent().getExtras("passingkey");
Bhuvaneshwaran Vellingiri
fonte
-1

Olá a todos, vejo muitas boas opções, mas eu queria saber por que o Binding não foi usado?

Passar uma referência a um objeto apenas me parece mais eficiente do que serializar e deserilizar objetos, mas não mergulhei profundamente para ver se é isso que está acontecendo nos bastidores.

Criar um fichário é bastante simples ...

public class MyBinder extends Binder {

    private Object myObject;

    public MyBinder(Object object) {
        myObject = object;
    }

    public Object getObject() {
        return myObject;
    }

}

E criar o pacote para usá-lo não é tão ruim assim.

public class MyParcelable implements Parcelable {

    private Object myObject;

    public MyParcelable() {
    }

    public MyParcelable(Parcel parcel) {
        myObject = ((MyBinder)parcel.readStrongBinder()).getObject();
    }

    public void setObject(Object object) {
        myObject = object;
    }

    public Object getObject() {
        return myObject;
    }

    public void writeToParcel(Parcel parcel, int flags) {
        parcel.writeStrongBinder(new MyBinder(myObject));
    }

    public int describeContents() {
        return myObject == null ? 0 : 1;
    }

    public static final Parcelable.Creator<MyParcelable> CREATOR = new Parcelable.Creator<MyParcelable>() {

        public MyParcelable createFromParcel(Parcel parcel) {
            return new MyParcelable(parcel);
        }

        public MyParcelable[] newArray(int length) {
            return new MyParcelable[length];
        }

    };
}

Essa lógica é muito legal porque você está realmente passando uma referência de atividade para atividade.

Eu aconselharia a verificação de nulos e se a instância do Binder for MyBinder!

e para implementar isso, você apenas ...

Enviá-lo

Object myObject = "some object";
MyParcelable myParcelable = new MyParcelable();
myParcelable.setObject(myObject);

intent.putExtra("MyParcelable", myParcelable);

Pegue de volta

myParcelable = (MyParcelable) getIntent().getExtras().getParcelable("MyParcelable");
myObject = myParcelable.getObject();

Caramba, alguém poderia ficar louco e fazer deste otário um verdadeiro genérico.

SkidRunner
fonte