Quantas atividades vs fragmentos?

185

Introdução:

O padrão básico do "Fragments Tutorial" é mais ou menos assim:

  1. Em um tablet, tenha uma lista à esquerda e detalhes à direita.
  2. Ambos são Fragmentse ambos residem no mesmo Activity.
  3. Em um telefone, tenha uma lista Fragmentem um Activity.
  4. Lançar um novo Activitycom os detalhes Fragment.

(por exemplo, API do Android 3.0 Fragments por Dianne Hackborn e o Guia da API do Fragments )

Nos dois dispositivos, a funcionalidade está no Fragments. (simples)

No tablet , o aplicativo inteiro é 1Activity ; no telefone , existem muitosActivities .


Questões:

  • Existe um motivo para dividir o aplicativo de telefone em vários Activities?

Um problema com esse método é que você duplica muita lógica no Tablet principal Activitye no telefone separado Activities.

  • Não seria mais fácil manter o modelo 1 Activity em ambos os casos, usando a mesma lógica de ativar Fragmentse desativar (apenas usando um layout diferente)?

Dessa maneira, a maior parte da lógica reside em Fragmentssi mesma e existe apenas uma Activityduplicação de código única e menor.

Também o que li sobre ActionBarSherlockisso é que parece funcionar melhor em Fragmentsvez de Activities(mas ainda não o trabalhei).

Os tutoriais estão simplificados demais ou perdi algo importante nessa abordagem?


Tentamos as duas abordagens com sucesso no escritório - mas estou prestes a iniciar um projeto maior e quero facilitar o máximo possível as coisas para mim.

Alguns links para perguntas relacionadas:


Atualizações

Recompensa iniciada em questão - ainda não estou convencido sobre o motivo pelo qual preciso duplicar minha lógica de aplicativo na atividade do tablet e em cada atividade do telefone.

Também encontrei um artigo interessante do pessoal da Square, que vale a pena ler:

Richard Le Mesurier
fonte
38
+1 para uma pergunta incrível e bem escrita.
Siddharth Lele
isso é algo que me incomoda muito hoje em dia. Atualmente, estou trabalhando em um aplicativo cujo design inclui muitos fragmentos e estará disponível no telefone e no tablet. Estou procurando um caminho intermediário, mas ainda não consegui encontrar nenhum. ...
Nixit Patel
1
Sinceramente, não quero ofender, mas acho que você acabou de aceitar o que queria ouvir, em vez da resposta real. A resposta do Scuba não é recomendada pelo Google e a postagem de blog que eu gostei explica o porquê.
Pjco 26/09/12
1
@pjco Discordo especificamente de ter o onItemSelected()método na Atividade. No meu aplicativo "real", tenho muitas listas e sublistas. Esse padrão sugere que minha Atividade da guia deve ter um onItemSelected()método para lidar com cada uma das listas. Além disso, as atividades telefônicas devem ter a mesma lógica duplicada em cada uma delas. IMHO é muito melhor colocar a lógica Item Selecionado em cada Fragmento - não há duplicação e eu prefiro essa maneira de estruturar o código. Espero que ajude #
Richard Le Mesurier
2
Atualmente, estou pendurado nesse dilema no trabalho. Os fragmentos carregam muito mais rápido do que o lançamento de novas atividades, então comecei a implementar uma única arquitetura de atividade. No entanto, encontrei um problema, que parece que não consigo encontrar uma boa maneira de oferecer suporte a configurações de múltiplos fragmentos sem fazer algo hacky. Veja esta pergunta .
theblang

Respostas:

41

Concordo que os tutoriais são muito simplificados. Eles apenas apresentam, Fragmentsmas eu não concordo com o padrão sugerido.

Concordo também que não é uma boa ideia duplicar a lógica do seu aplicativo em várias atividades (consulte o princípio DRY na wikipedia ).


Prefiro o padrão usado pelo ActionBarSherlockaplicativo Fragments Demo (faça o download aqui e o código-fonte aqui ). A demonstração que mais se aproxima do tutorial mencionado na pergunta é a chamada "Layout" no aplicativo; ou FragmentLayoutSupportno código fonte.

Nesta demonstração, a lógica foi movida para fora do Activitye para o Fragment. Na TitlesFragmentverdade, contém a lógica para alterar fragmentos. Dessa forma, cada atividade é muito simples. Duplicar muitas Atividades muito simples, onde nenhuma lógica está dentro das Atividades, torna muito simples.

Colocando a lógica nos fragmentos, não há necessidade de escrever o código mais de uma vez ; está disponível independentemente da atividade em que o fragmento for inserido. Isso o torna um padrão mais poderoso do que o sugerido pelo tutorial básico.

    /**
    * Helper function to show the details of a selected item, either by
    * displaying a fragment in-place in the current UI, or starting a
    * whole new activity in which it is displayed.
    */
    void showDetails(int index)
    {
        mCurCheckPosition = index;

        if (mDualPane)
        {
            // We can display everything in-place with fragments, so update
            // the list to highlight the selected item and show the data.
            getListView().setItemChecked(index, true);

            // Check what fragment is currently shown, replace if needed.
            DetailsFragment details = (DetailsFragment) getFragmentManager()
                .findFragmentById(R.id.details);
            if (details == null || details.getShownIndex() != index)
            {
                // Make new fragment to show this selection.
                details = DetailsFragment.newInstance(index);

                // Execute a transaction, replacing any existing fragment
                // with this one inside the frame.
                FragmentTransaction ft = getFragmentManager()
                    .beginTransaction();
                ft.replace(R.id.details, details);
                ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
                ft.commit();
            }

        }
        else
        {
            // Otherwise we need to launch a new activity to display
            // the dialog fragment with selected text.
            Intent intent = new Intent();
            intent.setClass(getActivity(), DetailsActivity.class);
            intent.putExtra("index", index);
            startActivity(intent);
        }
    }

Outra vantagem do padrão ABS é que você não termina com uma Atividade do Tablet que contém muita lógica e isso significa que você economiza memória. O padrão do tutorial pode levar a uma atividade principal muito grande em um aplicativo mais complexo; pois ele precisa lidar com a lógica de todos os fragmentos que são colocados nele a qualquer momento.

No geral, não pense nisso como sendo forçado a usar muitas atividades. Pense nisso como tendo a oportunidade de dividir seu código em muitos fragmentos e economizando memória ao usá-los.

Stephen Asherson
fonte
thx para uma resposta abrangente - observei as demos do ABS e acho que há muito código bom lá. Vou tentar mover muito da minha lógica nos fragmentos vez
Richard Le Mesurier
O aplicativo de demonstração foi movido para aqui: play.google.com/store/apps/…
Philipp E.
Acho que o padrão que você está descrevendo é do código de exemplo original do Google: android-developers.blogspot.com/2011/02/… Acho que o ActionBarSherlock acabou de portar o código de demonstração do Google para usar as classes ABS.
Dan J
17

Eu acho que você está no caminho certo. (E sim, os tutoriais são simplificados demais).

Em um layout de tablet, você pode usar uma única atividade e trocar e remover fragmentos (em vários 'painéis'). Enquanto estiver no layout do telefone, você pode usar uma nova atividade para cada fragmento.

Igual a:

insira a descrição da imagem aqui

Pode parecer muito trabalho extra, mas, ao usar várias atividades para telefones, você ativa o ciclo de vida básico da atividade e a transferência de intenção. Isso também permite que a estrutura lide com todas as animações e a pilha traseira.

Para ajudar a reduzir o código, você pode usar BaseActivityae estender a partir disso.

Portanto, se o usuário tiver um tablet, você usaria MyMultiPaneFragActivityou algo semelhante. Essa atividade é responsável pelo gerenciamento de retornos de chamada dos fragmentos e das intenções de roteamento para o fragmento correto (como uma intenção de pesquisa)

Se o usuário tiver um telefone, você poderá usar uma Atividade regular com muito pouco código e estendê-lo MyBaseSingleFragActivityou algo semelhante. Essas atividades podem ser muito simples, de 5 a 10 linhas de código (talvez até menos).

A parte complicada é rotear as intenções e outros enfeites. * (Editar: veja mais abaixo).

Eu acho que a razão pela qual essa é a maneira recomendada é economizar memória e reduzir a complexidade e o acoplamento. Se você estiver trocando Fragmentos, ele FragmentManagermantém uma referência a esse Fragmento para a pilha traseira. Ele também simplifica o que deve estar "em execução" para o usuário. Essa configuração também dissocia as visualizações, o layout e a lógica no fragmento do ciclo de vida da atividade. Dessa maneira, um Fragmento pode existir em uma única atividade, ao lado de outro fragmento (painel duplo) ou em Atividade de três painéis, etc.

* Um dos benefícios de ter um roteamento de intenção regular é que você pode iniciar uma Atividade explicitamente de qualquer lugar da pilha inversa. Um exemplo pode ser o caso dos resultados da pesquisa. (MySearchResults.class).

Leia aqui para mais informações:

http://android-developers.blogspot.com/2011/09/preparing-for-handsets.html

Pode ser um trabalho um pouco mais inicial, porque cada fragmento deve funcionar bem em atividades separadas, mas geralmente compensa. Isso significa que você pode usar arquivos de layout alternativos que definem diferentes combinações de fragmentos, mantêm o código de fragmento modular, simplificam o gerenciamento da barra de ação e permitem que o sistema lide com todo o trabalho da pilha traseira.

pjco
fonte
Quanto à vantagem do MySearchResults - você sugere uma maneira diferente de responder a essa intenção, dependendo do telefone ou tablet - por que isso é melhor do que ter uma única atividade que responda nos dois casos? Você sugere que, no Tablet, não há roteamento de intenção regular - portanto, você precisa resolver o problema do tablet de qualquer maneira. Por que não usar essa solução no aparelho também?
Richard Le Mesurier
A vantagem aqui é que o código do seu tablet pode ser roteado para vários painéis. Às vezes, você desejará alterar vários painéis em uma única intenção. Como uma pesquisa resulta à esquerda com as detials do primeiro item no painel maior à direita. Esse código não seria portátil para um único layout.
pjco 11/09/12
Por que não há problema em trocar fragmentos quando existem muitos, mas se apenas um fragmento está visível, não devo mudar para outro fragmento?
Richard Le Mesurier
Não sei se entendi o que você quer dizer, mas para esclarecer meu comentário acima: Às vezes, você pode alterar mais de 1 fragmento ao mesmo tempo em um layout com vários fragmentos. Isso requer código para alterar 2 fragmentos, que você não iria reutilização em um único layout de fragmento
pjco
Você é bem-vindo :) por favor upvote ou aceitar que se sinta a resposta é útil
pjco
6

Aqui está a resposta de Reto Meier sobre o mesmo, tirada deste vídeo do curso Android Fundamentals da Udacity .

Há vários motivos pelos quais seria melhor dividir seu aplicativo em atividades diferentes.

  • Ter uma única atividade monolítica aumenta a complexidade do seu código, dificultando a leitura, o teste e a manutenção.
  • Torna a criação e o gerenciamento de filtros de intenção muito mais difíceis.
  • Aumenta o risco de acoplar firmemente componentes independentes.
  • Torna muito mais provável a introdução de riscos à segurança se a atividade única incluir informações confidenciais e informações seguras para compartilhar.

Uma boa regra geral é criar uma nova atividade sempre que o contexto mudar. Por exemplo, exibindo um tipo diferente de dados e alternando da exibição para a entrada de dados.

Aditya Naique
fonte
Curiosamente o título do vídeo é "por isso que não Apenas Use Fragments"
Richard Le Mesurier
é uma abordagem bem, estou enfrentando toneladas de problemas com múltiplos fragmentos de atividade único ... exp verdadeira provavelmente
GvSharma
4

Um problema com esse método é que você duplica muita lógica na Atividade principal do Tablet e nas Atividades telefônicas separadas.

No padrão de detalhes mestre, há duas atividades. Um mostra os dois fragmentos em telas maiores e apenas o fragmento "principal" em telas menores. O outro mostra o fragmento "detalhe" em telas menores.

Sua lógica de detalhes deve estar vinculada ao fragmento de detalhes. Portanto, não há duplicação de código relacionada à lógica de detalhes entre as atividades - a atividade de detalhes apenas exibe o fragmento de detalhes, talvez passando dados de um Intentextra.

Também o que li sobre o ActionBarSherlock é que ele parece funcionar melhor com Fragmentos, em vez de Atividades (mas ainda não o trabalhei).

O ActionBarSherlock não tem mais nada a ver com fragmentos do que a barra de ação nativa, pois o ActionBarSherlock é puramente um backport da barra de ação nativa.

CommonsWare
fonte
O que você pensa da idéia de uma única atividade?
theblang
@mattblang: Desde que você obtenha a navegação correta, não há problema nisso.
CommonsWare
1
Tentei refatorar para uma única arquitetura de atividade porque a substituição de um fragmento é muito mais rápida do que o lançamento de uma nova atividade com o mesmo fragmento. Eu sinto que eu estou correndo em muitas dificuldades, porém, como este . A maioria dos exemplos que encontro on-line, especialmente para configurações de múltiplos fragmentos, como detalhes mestre, não usa uma única atividade. Então, estou com um dilema.
theblang
0

Referindo-se à 1ª pergunta de "Existe um motivo para dividir o aplicativo de telefone em muitas atividades?" - Sim. simplesmente se resume ao espaço disponível, um Tablet dá mais espaço aos desenvolvedores, permitindo que os desenvolvedores coloquem mais em uma tela. O Android nos diz que o Activities pode fornecer uma tela . Então, o que você pode fazer com uma tela grande em um tablet é algo que pode estar espalhado por várias telas em um telefone, porque não há espaço suficiente para todos os fragmentos.

EFlisio
fonte
1ª frase - "Uma Atividade é um componente de aplicativo que fornece uma tela com a qual os usuários podem interagir para fazer algo". Eu vejo um erro na minha declaração original, eu não tive a intenção de colocar "são outra tela",
EFlisio