Pergunta

Em vários pedaços de código do Android que eu vi:

 public class MyActivity extends Activity {
    public void method() {
       mContext = this;    // since Activity extends Context
       mContext = getApplicationContext();
       mContext = getBaseContext();
    }
 }

No entanto não consigo encontrar qualquer explicação razoável de que é preferível, e em que circunstâncias que devem ser utilizados.

Ponteiros para documentação sobre isso, e orientação sobre o que poderia quebrar se o errado é escolhido, seria muito apreciado.

Foi útil?

Solução

Eu concordo que a documentação é escassa quando se trata de contextos em Android, mas você pode juntar alguns fatos de várias fontes.

Este post no oficial do Google Android desenvolvedores blog foi escrito principalmente para vazamentos de memória de endereço ajuda, mas fornece algumas boas informações sobre contextos, bem como:

Em um aplicativo Android regular, você geralmente têm dois tipos de Contexto, Atividade e aplicação.

Lendo o artigo um pouco diz mais sobre a diferença entre os dois e quando você pode querer considerar usando o contexto de aplicação (Activity.getApplicationContext()) ao invés de usar o contexto this Atividade). Basicamente, o contexto de aplicação está associada com a aplicação e será sempre o mesmo durante todo o ciclo de vida de sua aplicação, onde, como o contexto Atividade está associada com a atividade e poderia ser destruído muitas vezes como a atividade é destruído durante as mudanças de orientação da tela e tal.

Eu não poderia encontrar realmente nada sobre quando usar getBaseContext () diferente de um post de Dianne Hackborn, um dos engenheiros do Google que trabalham no SDK Android:

Não use getBaseContext (), use apenas Contexto que você tem.

Essa foi a partir de um post sobre o android-desenvolvedores newsgroup , você pode querer considerar fazer sua pergunta lá também, porque um punhado de pessoas trabalhando no Android monitor real que newsgroups e responder a perguntas.

Portanto, em geral, parece preferível utilizar o contexto de aplicação global, quando possível.

Outras dicas

Aqui está o que eu encontrei em relação ao uso de context:

1). Dentro de uma própria Activity, uso this para inflar layouts e menus, cadastre-se menus de contexto, instanciar widgets, iniciar outras atividades, criar novos Intent dentro de uma Activity, instanciar preferências, ou outros métodos disponível em um Activity.

layout de inflar:

View mView = this.getLayoutInflater().inflate(R.layout.myLayout, myViewGroup);

menu de inflar:

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    super.onCreateOptionsMenu(menu);
    this.getMenuInflater().inflate(R.menu.mymenu, menu);
    return true;
}

menu de contexto Register:

this.registerForContextMenu(myView);

Instantiate widget:

TextView myTextView = (TextView) this.findViewById(R.id.myTextView);

Iniciar uma Activity:

Intent mIntent = new Intent(this, MyActivity.class);
this.startActivity(mIntent);

preferências instanciar:

SharedPreferences mSharedPreferences = this.getPreferenceManager().getSharedPreferences();

2). Para a classe de aplicação à escala, utilização getApplicationContext() como este existem contexto para o tempo de vida do pedido.

Recuperar o nome do pacote Android atual:

public class MyApplication extends Application {    
    public static String getPackageName() {
        String packageName = null;
        try {
            PackageInfo mPackageInfo = getApplicationContext().getPackageManager().getPackageInfo(getApplicationContext().getPackageName(), 0);
            packageName = mPackageInfo.packageName;
        } catch (NameNotFoundException e) {
            // Log error here.
        }
        return packageName;
    }
}

Bind uma classe de todo o aplicativo:

Intent mIntent = new Intent(this, MyPersistent.class);
MyServiceConnection mServiceConnection = new MyServiceConnection();
if (mServiceConnection != null) {
    getApplicationContext().bindService(mIntent, mServiceConnection, Context.BIND_AUTO_CREATE);
}

3) para os ouvintes e outro tipo de classes de Android (por exemplo ContentObserver), utilizar uma substituição Contexto como:.

mContext = this;    // Example 1
mContext = context; // Example 2

onde this ou context é o contexto de uma classe (Actividade, etc).

contexto Activity substituição:

public class MyActivity extends Activity {
    private Context mContext;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);        
        mContext = this;
    }
}

Listener contexto substituição:

public class MyLocationListener implements LocationListener {
    private Context mContext;
    public MyLocationListener(Context context) {
        mContext = context;
    }
}

contexto ContentObserver substituição:

public class MyContentObserver extends ContentObserver {
    private Context mContext;
    public MyContentObserver(Handler handler, Context context) {
        super(handler);
        mContext = context;
    }
}

4). Para BroadcastReceiver (incluindo embutido receptor / embedded), use próprio contexto do receptor.

BroadcastReceiver externa:

public class MyBroadcastReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        final String action = intent.getAction();
        if (action.equals(Intent.ACTION_SCREEN_OFF)) {
            sendReceiverAction(context, true);
        }
        private static void sendReceiverAction(Context context, boolean state) {
            Intent mIntent = new Intent(context.getClass().getName() + "." + context.getString(R.string.receiver_action));
            mIntent.putExtra("extra", state);
            context.sendBroadcast(mIntent, null);
        }
    }
}

Sequenciais / BroadcastReceiver incorporado:

public class MyActivity extends Activity {
    private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            final boolean connected = intent.getBooleanExtra(context.getString(R.string.connected), false);
            if (connected) {
                // Do something.
            }
        }
    };
}

5). Para Serviços, use próprio contexto do serviço.

public class MyService extends Service {
    private BroadcastReceiver mBroadcastReceiver;
    @Override
    public void onCreate() {
        super.onCreate();
        registerReceiver();
    }
    private void registerReceiver() {
        IntentFilter mIntentFilter = new IntentFilter();
        mIntentFilter.addAction(Intent.ACTION_SCREEN_OFF);
        this.mBroadcastReceiver = new MyBroadcastReceiver();
        this.registerReceiver(this.mBroadcastReceiver, mIntentFilter);
    } 
}

6). Para brindes, geralmente usam getApplicationContext(), mas, quando possível, utilizar o contexto transmitido de uma Actividade de serviço, etc.

Use contexto da aplicação:

Toast mToast = Toast.makeText(getApplicationContext(), message, Toast.LENGTH_LONG);
mToast.show();

Use contexto passou de uma fonte:

public static void showLongToast(Context context, String message) {
    if (context != null && message != null) {
        Toast mToast = Toast.makeText(context, message, Toast.LENGTH_LONG);
        mToast.show();
    }
}

E por último, não use getBaseContext() como aconselhado pelos desenvolvedores quadro do Android.

UPDATE:. Adicionar exemplos de uso Context

Eu li esta discussão há alguns dias, me perguntando a mesma pergunta. A minha decisão depois de ler este era simples:. Utilize sempre applicationContext

No entanto, I encontrou um problema com isso, eu passei algumas horas para encontrá-lo, e alguns segundos para resolvê-lo ... (mudando uma palavra ...)

Eu estou usando um LayoutInflater para inflar uma exibição que contém uma Spinner.

Então, aqui estão duas possibilidades:

1)

    LayoutInflater layoutInflater = LayoutInflater.from(this.getApplicationContext());

2)

    LayoutInflater layoutInflater = LayoutInflater.from(this.getBaseContext());

Então, eu estou fazendo algo parecido com isto:

    // managing views part
    View view = ContactViewer.mLayoutInflater.inflate(R.layout.aViewContainingASpinner, theParentView, false);
    Spinner spinner = (Spinner) view.findViewById(R.id.theSpinnerId);
    String[] myStringArray = new String[] {"sweet","love"};

    // managing adapter part
    // The context used here don't have any importance -- both work.
    ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(this.getApplicationContext(), myStringArray, android.R.layout.simple_spinner_item);
    adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
    spinner.setAdapter(adapter);

    theParentView.addView(view);

O que eu notei: Se você instanciado seu LinearLayout com o applicationContext, então, quando você clicar no botão rotativo na sua atividade, você terá uma exceção não pega, proveniente da máquina virtual Dalvik (não do seu código, é por isso que eu tenho passei muito tempo para descobrir onde foi o meu erro ...).

Se você usar o baseContext, então tudo bem, o menu de contexto será aberto e você será capaz de escolher entre suas escolhas.

Então, aqui é a minha conclusão: Suponho que (eu não testei ainda) do que o baseContext é necessária quando se lida com contextMenu em sua atividade ...

O teste foi feito codificação com API 8, e testado em um HTC Desire, o Android 2.3.3.

Espero que meu comentário não ter aborrecido você até agora, e desejo-lhe tudo de melhor. Feliz codificação; -)

Em primeiro lugar, concordo que devemos usar appcontext sempre que possível. em seguida, "este" em atividade. Eu nunca tive a necessidade de basecontext.

Em meus testes, na maioria dos casos eles podem ser trocados. Na maioria dos casos, a razão que você deseja obter um porão de um contexto é o de acessar arquivos, preferências, banco de dados etc. Estes dados são, eventualmente, refletidos como arquivos na pasta de dados privada do seu aplicativo (/ dados / dados /). Não importa qual o contexto que você usa, eles vão ser mapeados para a mesma pasta / arquivos para que você está OK.

Isso é o que eu observei. Talvez existam casos você deve distingui-los.

Em alguns casos, você pode usar o contexto da actividade durante contexto de aplicação ao executar algo em um fio. Quando segmento concluir a execução e você precisa voltar as costas resultado para a atividade de chamadas, você precisa que o contexto com um manipulador.

((YourActivity) context).yourCallbackMethod(yourResultFromThread, ...);

Em palavras simples

getApplicationContext() como o nome do método sugerem fará seu aplicativo ciente de largura detalhes do aplicativo que você pode acessar de qualquer lugar do aplicativo. Assim, você pode fazer uso deste em serviço obrigatório, o registo de transmissão etc. Application context vai estar vivo até as saídas de aplicativos.

getActivity() ou this fará seu aplicativo ciente da tela atual que é visível também os detalhes de nível de aplicativo fornecidos pelo application context. Então o que você quer saber sobre a tela atual como Window ActionBar Fragementmanger e assim estão disponíveis com este contexto. Basicamente e Activity estender Context. Neste contexto será viva até o componente atual (atividade) está vivo

Eu só usei isso e getBaseContext quando brindar a partir de um onClick (de noob muito verde para ambos Java e Android). Eu uso isso quando meu clicker é diretamente na atividade e tem que usar getBaseContext em um clicker interna anônima. Eu estou supondo que é praticamente o truque com getBaseContext, é talvez retornando o contexto da atividade em que a classe interna é esconderijo.

A confusão decorre do fato de que existem inúmeras maneiras de Contexto acesso, com (na superfície) não há diferenças discerníveis. Abaixo estão quatro das maneiras mais comuns que você pode ser capaz de acesso Contexto em uma atividade.

getContext()
getBaseContext()
getApplicationContext()
getActionBar().getThemedContext() //new

O que é um contexto? Eu, pessoalmente, gosto de pensar em Contexto como o estado do seu pedido a qualquer momento. O contexto de aplicação representa uma configuração global ou a base de sua aplicação e uma actividade ou serviço pode construir sobre ele e representa um exemplo de configuração do seu aplicativo ou um estado transitivo para ele.

Se você olhar para a fonte para android.content.Context, você vê que o contexto é uma classe abstrata e os comentários sobre a classe são as seguintes:

Interface de informações globais sobre um ambiente de aplicação. Esta é uma classe abstrata, cuja implementação é fornecido pelo sistema Android. isto permite o acesso a recursos application-specific e classes, bem como up-chamadas para operações application-level como o lançamento de atividades, transmitindo e recebendo intenções, etc. O que eu tirar isso é que Context fornece uma implementação comum a nível da aplicação de acesso, bem como recursos de nível de sistema. recursos nível de aplicativo pode estar acessando coisas como cordas [getResources()] ou ativos recursos [getAssets()] e recursos em nível de sistema é qualquer coisa que você acessa com Context.getSystemService().

Por uma questão de fato, dê uma olhada nas observações sobre os métodos e eles parecem reforçar essa noção:

getSystemService(): retorne a alavanca para um serviço system-level pelo nome. A classe do objeto retornado varia de acordo com o nome solicitado. getResources(): Regresso uma instância de recursos para o pacote do aplicativo. getAssets(): Regresso uma instância de recursos para o pacote do aplicativo. Pode valer a pena destacar que na classe abstrata Contexto, todos os métodos acima são abstratos! Apenas um exemplo de getSystemService (Classe) tem um resumo de um método de implementação e que chama. Isso significa que a implementação para estes devem ser fornecidos principalmente pelas classes de aplicação, que incluem:

ContextWrapper
Application
Activity
Service
IntentService

Olhando para a documentação da API, a hierarquia das classes parece com isso:

Contexto

| - ContextWrapper

| - - Aplicação

| - - ContextThemeWrapper

| - - - - Atividade

| - - Serviço

| - - - IntentService

Uma vez que sabemos que Context si não está fornecendo qualquer insight, nos movemos para baixo da árvore e dar uma olhada no ContextWrapper e perceber que não há muito lá. Desde Aplicação estende ContextWrapper, não há muito a olhar para lá, quer uma vez que não substituir a implementação fornecida pelo ContextWrapper. Isto significa que a implementação para o contexto é fornecido pelo sistema operacional e está escondido do API. Você pode dar uma olhada na implementação concreta de Contexto por olhar para a fonte para a classe ContextImpl.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top