Qual é a diferença entre os vários métodos para obter um contexto?
-
06-07-2019 - |
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.
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();
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);
}
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);
}
}
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.