Por que eu quero evitar construtores não padrão em fragmentos?

173

Estou criando um aplicativo com Fragmentse em um deles, criei um construtor não padrão e recebi este aviso:

Avoid non-default constructors in fragments: use a default constructor plus Fragment#setArguments(Bundle) instead

Alguém pode me dizer por que isso não é uma boa ideia?

Você também pode sugerir como eu faria isso:

public static class MenuFragment extends ListFragment {
    public ListView listView1;
    Categories category;

    //this is my "non-default" constructor
    public MenuFragment(Categories category){
        this.category = category;
    }....

Sem usar o construtor não padrão?

BlackHatSamurai
fonte
3
Não, aqueles não ajudam. Eles não responderam à minha pergunta. Mas obrigada, no entanto :)
BlackHatSamurai
31
@BlaineOmega Na verdade, este em particular: stackoverflow.com/a/11602478/321697 definitivamente responde sua pergunta. Em uma mudança de orientação ou outro evento que faz com que o fragmento seja recriado, o Android usa o construtor padrão e o pacote passado como argumento. Se você estiver usando um construtor personalizado, assim que o fragmento for recriado devido a um desses eventos, o que você fez no construtor personalizado será perdido.
precisa saber é o seguinte
1
Obrigado, mas isso responde ao porquê, mas não ao como.
BlackHatSamurai
Isso é coberto pelos primeiro e segundo links no meu comentário original.
CommonsWare

Respostas:

110

Crie um objeto de pacote configurável e insira seus dados (neste exemplo, seu Categoryobjeto). Cuidado, você não pode passar esse objeto diretamente no pacote, a menos que seja serializável. Eu acho que é melhor criar seu objeto no fragmento e colocar apenas um ID ou outra coisa no pacote. Este é o código para criar e anexar um pacote configurável:

Bundle args = new Bundle();
args.putLong("key", value);
yourFragment.setArguments(args);

Depois disso, no seu fragmento, acesse os dados:

Type value = getArguments().getType("key");

Isso é tudo.

nistv4n
fonte
3
como passar um objeto? Eu quero passar um objeto de contexto ou qualquer outro objeto.
Adil Malik
12
Os pacotes configuráveis ​​podem transportar objetos Java serializados, bem como Parcelableobjetos. Além disso, você não deve passar a Context, porque essas informações podem ser acessadas através do getActivity()método do fragmento .
krakatoa
No fragmento onde fazer isso Type value = getArguments().getType("key");?
Muhammad Babar
4
@ Muhammad Babar: Se eu fosse você, acrescentaria ao newInstance()método. Por exemplo: public static FragmentName newInstance(your variables){}. Como a documentação do Android recomenda, não faça um construtor com parâmetros, porque o padrão (sem parâmetros) será chamado automaticamente após o reinício do seu fragmento.
Nistv4n
@MuhammadBabar onCreateView is OK
chanjianyi
272

Parece que nenhuma das respostas realmente responde "por que usar bundle para passar parâmetros em vez de construtores não padrão"

A razão pela qual você deve passar os parâmetros através do pacote é que, quando o sistema restaura um fragment(por exemplo, na alteração da configuração), ele restaura automaticamente o seu bundle.

Os retornos de chamada gostam onCreateou onCreateViewdevem ler os parâmetros do bundle- desta forma, você garante que restaura o estado do fragmentcorretamente para o mesmo estado em que fragmentfoi inicializado (observe que esse estado pode ser diferente do onSaveInstanceState bundleque é passado para o onCreate/onCreateView)

A recomendação de usar o newInstance()método estático é apenas uma recomendação. Você pode usar um construtor não padrão, mas certifique-se de preencher os parâmetros de inicialização no bundleinterior do corpo desse construtor. E leia esses parâmetros nos métodos onCreate()ou onCreateView().

numan salati
fonte
2
Bem explicado. Obrigado. Se eu fosse o único a pergunta, eu teria que dar-lhe um carrapato
Karue Benson Karue
5
Você não pode mais usar o construtor não padrão (por qualquer motivo) .... isso gera um erro do compilador (costumava ser um aviso).
precisa saber é o seguinte
51

Você Fragmentnão deve ter construtores por causa de como a FragmentManagerinstancia. Você deve ter um newInstance()método estático definido com os parâmetros necessários, agrupe-os e defina-os como os argumentos do fragmento, que você poderá acessar posteriormente com o Bundleparâmetro

Por exemplo:

public static MyFragment newInstance(int title, String message) {
    MyFragment fragment = new MyFragment();
    Bundle bundle = new Bundle(2);
    bundle.putInt(EXTRA_TITLE, title);
    bundle.putString(EXTRA_MESSAGE, message);
    fragment.setArguments(bundle);
    return fragment ;
}

E leia estes argumentos em onCreate:

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    title = getArguments().getInt(EXTRA_TITLE);
    message = getArguments().getString(EXTRA_MESSAGE);

    //...
}

Dessa forma, se desanexado e reconectado, o estado do objeto pode ser armazenado através dos argumentos, assim como bundlesanexado a Intents.

Asaf Pinhassi
fonte
9

Se você usar o parâmetro para alguma classe. tente isso

SomeClass mSomeInstance;
public static final MyFragment newInstance(SomeClass someInstance){
    MyFragment f = new MyFragment();
    f.mSomeInstance = someInstance;
    return f;
}
김동기
fonte
5
Esta é realmente uma má sugestão. Depois que o Fragment for recriado por a FragmentManager, você perderá mSomeInstance.
Yaroslav Mytkalyk
Acordado, SomeClass deve ser parcelable e armazenados em um pacote usando setArguments ()
Jake_
1

Eu acho que não há diferença entre construtor estático e dois construtores (um vazio e parametrizado que armazena argumentos no pacote de argumentos de um fragmento); provavelmente, essa regra é criada para reduzir a probabilidade de esquecer de implementar o construtor não-arg em Java , que não é gerado implicitamente quando a sobrecarga está presente.

Nos meus projetos, uso o Kotlin e implemento fragmentos com um construtor primário no-arg e um construtor secundário para argumentos que apenas os armazenam em um pacote configurável e os definem como argumentos de Fragmento, tudo funciona bem.

Pavlus
fonte
0

Se o fragmento usar construtores não padrão após a alteração da configuração, o fragmento perderá todos os dados.

Akop Vardanian
fonte