Llamar a startActivity () desde fuera de un contexto de actividad


368

He implementado un ListViewen mi aplicación de Android. Me ato a esto ListViewusando una subclase personalizada de la ArrayAdapterclase. Dentro del ArrayAdapter.getView(...)método anulado , asigno un OnClickListener. En el onClickmétodo de la OnClickListener, quiero lanzar una nueva actividad. Me sale la excepción:

Calling startActivity() from outside of an Activity  context requires the  
FLAG_ACTIVITY_NEW_TASK flag. Is this really what you want?

¿Cómo puedo obtener el Contextque el ListView(el actual Activity) está trabajando?


1
Creo que la respuesta de Alex debería ser la solución 'aceptada' a su problema, ya que rectifica el error que mencionó de una manera más genérica
devanshu_kaushik

10
Me encanta que "¿Es esto realmente lo que quieres?" ... He recibido un mensaje antes que decía "¿Está seguro de que no olvidó anular el registro de un receptor de transmisión en alguna parte?" ¡INCREÍBLE! Felicitaciones a quien puso todos estos pequeños mensajes para ayudarnos a discutir.
Nerdy Bunz

1
Me encontré con este problema. cuando actualicé targetSdkVersion a 28.
illusionJJ

Respuestas:


575

Ya sea

  • almacenar en caché el objeto Context a través del constructor en su adaptador, o
  • obténgalo de su vista.

O como último recurso,

  • agregue el indicador FLAG_ACTIVITY_NEW_TASK a su intención:

_ _

myIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

Editar: evitaría establecer marcas, ya que interferirá con el flujo normal de eventos y la pila de historial.


66
¿Qué pasa con la función de enlace automático de TextView donde no puedo controlar la intención (y, por lo tanto, las marcas) creadas por el sistema?
Alex Semeniuk

75
Que estaba recibiendo esta excepción cuando estaba haciendo algo como esto context.startActivity(intent);acabo de cambiar contexta partir ApplicationContextde ActivityTipo. Esto solucionó el problema.
Sufian

@AlexSemeniuk ¿alguna vez encontraste una solución?

@AlexSemeniuk - AutoLink funcionará siempre que pase la actividad como contexto al adaptador
Georges

Pasé el objeto Context a través del constructor pero no funciona. pero FLAG_ACTIVITY_NEW_TASK funciona muy bien para mí, gracias.
Hiren

100

Puede lograrlo con addFlags en lugar desetFlags

myIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

De acuerdo con la documentación que hace:

Agregue banderas adicionales a la intención (o con el valor de banderas existente).


EDITAR

Tenga en cuenta que si está usando indicadores, cambia la pila del historial como dice la respuesta de Alex Volovoy :

... evite establecer marcas, ya que interferirá con el flujo normal de eventos y la pila de historial.


1
Tengo un problema muy similar. ¿Ha experimentado algún problema con la pila de historial o cualquier otra cosa como sugieren las respuestas anteriores?
Einar Sundgren

1
No estoy exactamente seguro de lo que está buscando, pero puede comenzar una actividad sin un historial como ese: Intención intención = nueva intención (Intent.ACTION_VIEW, "http: \\ www.google.com")); intención. addFlags (Intent.FLAG_ACTIVITY_NO_HISTORY); startActivity (intento);
Bruno Bieri

¿Por qué no se recomienda agregar banderas aquí? ¿Qué tan crítico es interferir con el flujo normal de eventos y la pila de historial?
Jason Krs

@JasonKrs puedes usar addFlags. Solo tenga en cuenta que puede cambiar la pila del historial dependiendo de la bandera que agregue. FLAG_ACTIVITY_NEW_TASK se puede usar en esta situación. Para obtener más detalles, lea: developer.android.com/reference/android/content/…
Bruno Bieri


40

Si recibió un error debido al uso de crear selector como a continuación:

Intent sharingIntent = new Intent(Intent.ACTION_VIEW);
sharingIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
sharingIntent.setData(Uri.parse("http://google.com"));
startActivity(Intent.createChooser(sharingIntent, "Open With"));

Establezca la bandera para crear un selector como este:

Intent sharingIntent = new Intent(Intent.ACTION_VIEW);
sharingIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
sharingIntent.setData(Uri.parse("http://google.com"));

Intent chooserIntent = Intent.createChooser(sharingIntent, "Open With");
chooserIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

startActivity(chooserIntent);

44
Fue muy útil. ¡La intención exactamente de elección debería tener esta bandera!
Mahdi

2
Esta es la solución correcta, y exactamente lo que tiene que hacer, new_task in intent.chooser
Rafael Guimarães

15

Además: si muestra enlaces en la vista de lista en fragmentos , no lo cree así

adapter = new ListAdapter(getActivity().getApplicationContext(),mStrings);

en cambio llame

adapter = new ListAdapter(getActivity(),mStrings);

el adaptador funciona bien en ambos casos, pero los enlaces solo funcionan en el último.


@ user2676468: esto resolvió el problema del enlace automático para mí.
Head Geek

Esta debería ser una respuesta aceptada, ¡en lugar de usar banderas, es mejor!
Gastón Saillén

@ GastónSaillén, no uso getApplicationContext()(excepto la inicialización de la aplicación), pero capté esta excepción. Entonces, las situaciones pueden ser diferentes.
CoolMind

Este fue mi problema, usé getApplicationContext () para el contexto. Establecer thiscomo contexto funciona en relación con la actividad actual.
Brlja

14

Creo que tal vez está implementando OnClickListener en el lugar incorrecto; por lo general, definitivamente debe implementar un OnItemClickListener en su Actividad y configurarlo en ListView, o tendrá problemas con sus eventos ...


2
Me llevas a la solución. Necesitaba usar un OnItemClickListener, asignado a ListView. Aquí hay algunos enlaces para cualquier otra persona: developer.android.com/reference/android/widget/… androidpeople.com/… Gracias por la ayuda.
Sako73

Proporcione respuestas genéricas. La respuesta de Alex Volovoy a continuación resuelve el problema de manera genérica.
devanshu_kaushik

Para la posteridad: si lo define directamente como setListener (nuevo Listener) en un componente requiere un Contexto, creará una referencia implícita a toda la actividad que perderá memoria como no creería. Esto se puede eludir haciendo un oyente de clase interna estático o moviendo el oyente a una clase separada si necesita poder manejar entradas de más de un origen.
G_V

9
CustomAdapter mAdapter = new CustomAdapter( getApplicationContext(), yourlist);

o

Context mContext = getAppliactionContext();
CustomAdapter mAdapter = new CustomAdapter( mContext, yourlist);

cambiar a continuación

CustomAdapter mAdapter = new CustomAdapter( this, yourlist);

8

Al Android 28(Android P)principio Actividad

if ((intent.getFlags() & Intent.FLAG_ACTIVITY_NEW_TASK) == 0
        && (targetSdkVersion < Build.VERSION_CODES.N
                || targetSdkVersion >= Build.VERSION_CODES.P)
        && (options == null
                || ActivityOptions.fromBundle(options).getLaunchTaskId() == -1)) {
    throw new AndroidRuntimeException(
            "Calling startActivity() from outside of an Activity "
                    + " context requires the FLAG_ACTIVITY_NEW_TASK flag."
                    + " Is this really what you want?");
}

Entonces la mejor manera es agregar FLAG_ACTIVITY_NEW_TASK

Intent intent = new Intent(context, XXXActivity.class);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
}
context.startActivity(intent);

Esto es necesario para dispositivos de 28 y superiores.
Md Mohsin el

7

Mira, si estás creando una intención dentro de un listado en algún método

override onClick (View v).

luego llame al contexto a través de esta vista también:

v.getContext ()

Ni siquiera necesitará SetFlags ...


¿Y cuál era la situación incorrecta? v.getApplicationContext ()?
CoolMind

3

Para cualquiera que tenga esto en Xamarin.Android (MonoDroid) incluso cuando se llama a StartActivity desde la actividad, esto es realmente un error de Xamarin con el nuevo tiempo de ejecución ART, consulte https://bugzilla.xamarin.com/show_bug.cgi?id=17630


Sí, solo tiene que hacer lo que se describió anteriormente, pero la redacción ha cambiado ... intent.SetFlags (ActivityFlags.NewTask);
Luke Alderton el

3

Elaborando la respuesta de Alex Volovoy un poco más:

en caso de que tenga este problema con fragmentos, getActivity () funciona bien para obtener el contexto

En otros casos:

Si no quieres usar

myIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);//not recommend

luego realice una función como esta en su OutsideClass -

public void gettingContext(Context context){
    real_context = context;//where real_context is a global variable of type Context
}

Ahora, en su actividad principal, cuando realice una nueva clase OutsideClass, llame al método anterior inmediatamente después de definir la clase OutsideClass dando el contexto de la actividad como argumento. También en su actividad principal haga una función

public void startNewActivity(final String activity_to_start) {
    if(activity_to_start.equals("ACTIVITY_KEY"));
    //ACTIVITY_KEY-is a custom key,just to
    //differentiate different activities
    Intent i = new Intent(MainActivity.this, ActivityToStartName.class);
    activity_context.startActivity(i);      
}//you can make a if-else ladder or use switch-case

ahora regrese a su clase externa y, para comenzar una nueva actividad, haga algo como esto:

@Override
public void onClick(View v) {
........
case R.id.any_button:

            MainActivity mainAct = (MainActivity) real_context;             
            mainAct.startNewActivity("ACTIVITY_KEY");                   

        break;
    }
........
}

De esta manera, podrá iniciar diferentes actividades llamadas desde diferentes OutsideClass sin meterse con banderas.

Nota: intente no almacenar en caché el objeto de contexto a través del constructor para el fragmento (con adaptador, está bien). Un fragmento debe tener un constructor vacío; de lo contrario, la aplicación se bloquea en algunos escenarios.

recuerda llamar

OutsideClass.gettingContext(Context context);

en la función onResume () también.


3

Este error ocurre cuando startactivity no sabe cuál es su actividad. Por lo tanto, debe agregar actividad antes de startActivity ()

debes establecer

context.startActivity(yourIntent);

Si llama startActivitydesde Fragment, una persona que llama a menudo puede ser un fragmento, no una actividad.
CoolMind

2

En mi opinión, es mejor usar el método startActivity()solo en el código de su Activity.class. Si usa eso en la Adapteru otra clase, resultará en eso.


2

También tuve el mismo problema. Verifique todo el contexto que ha pasado. Para ' enlaces ' necesita un contexto de actividad, no un contexto de aplicación .

Este es el lugar donde debe verificar:

1.) Si utilizó LayoutInflater , compruebe qué contexto ha pasado.

2.) Si está utilizando un adaptador, verifique qué contexto ha pasado.


2

Yo tuve el mismo problema. El problema es con el contexto. Si desea abrir algún enlace (por ejemplo, compartir cualquier enlace a través del selector), pase el contexto de actividad, no el contexto de la aplicación.

No olvide agregar myIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)si no está en su actividad.


2

Use este código en su Adaptador_Actividad y use context.startActivity(intent_Object)yintent_Object.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

Me gusta esto:

Intent n_act = new Intent(context, N_Activity.class);
n_act.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(n_act);

Funciona....


1
Intent viewIntent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);    
viewIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);    
startActivity(viewIntent);   

Espero que esto funcione.


1

Enfrenté el mismo problema y luego lo implementé

intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

y se resolvió el problema.

Puede haber otra razón relacionada con el adaptador de vista de lista.
Puedes ver este blog , lo describió muy bien.


Blog útil, gracias. :)
Rucha Bhatt Joshi

1

Usa este código. Funciona bien para mi. Comparta algo desde fuera de una actividad:

Intent intent = new Intent(Intent.ACTION_SEND);
intent.setType("text/plain");

// Append Text
String Text = "Your Text Here"

intent.putExtra(Intent.EXTRA_TEXT, Text);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

Intent shareIntent = Intent.createChooser(intent,"Share . . . ");
shareIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
G.context.getApplicationContext().startActivity(shareIntent);

Configuración de banderas desordenar el historial de stacktrace
Ezio

1

Dado que agregar indicadores afecta event_flowy stack_historyes mejor pasar el 'contexto de aplicación' a la no actividad desde donde necesita llamar a una clase de actividad de la siguiente manera:

"ActivityClassName.this" (Si bien pasa el contexto de esta manera, contendrá todos los detalles e información que necesita para llamar a una Actividad desde un escenario sin actividad)

Por lo tanto, no es necesario establecer o agregar indicadores, esto funcionará bien en todos los casos.


0
Intent i= new Intent(context, NextActivity.class);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP);

0

Si está invocando Compartir Intención en el complemento Cordova, establecer la Bandera no será de ayuda. En su lugar, use esto:

cordova.getActivity().startActivity(Intent.createChooser(shareIntent, "title"));

0

Mi situación era un poco diferente, estoy probando mi aplicación usando Espressoy tuve que iniciar mi Actividad con ActivityTestRulela instrumentación Context(que no es la que viene de un Activity).

fun intent(context: Context) = 
    Intent(context, HomeActivity::class.java)
        .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)

Tuve que cambiar las banderas y agregar un orbit a bit ( |en Java) conIntent.FLAG_ACTIVITY_NEW_TASK

Entonces resulta en:

fun intent(context: Context) = 
    Intent(context, HomeActivity::class.java)
        .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK)

0

Versión Kotlin

val intent = Intent(Intent.ACTION_EDIT, ContactsContract.Profile.CONTENT_URI)
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
this.startActivity(intent)
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.