Memanggil startActivity () dari luar konteks Aktivitas


368

Saya telah menerapkan ListViewdalam aplikasi Android saya. Saya mengikat ini ListViewmenggunakan subkelas kustom ArrayAdapterkelas. Di dalam ArrayAdapter.getView(...)metode yang diganti , saya menetapkan sebuah OnClickListener. Dalam onClickmetode OnClickListener, saya ingin meluncurkan aktivitas baru. Saya mendapatkan pengecualian:

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

Bagaimana saya bisa mendapatkan Contextbahwa ListView(saat ini Activity) bekerja di bawah?


1
Saya pikir jawaban Alex harus menjadi solusi 'diterima' untuk masalah Anda, karena itu memperbaiki kesalahan yang Anda sebutkan dengan cara yang lebih umum
devanshu_kaushik

10
Saya suka itu, "Apakah ini yang Anda inginkan?" ... Saya punya pesan sebelumnya yang mengatakan "Apakah Anda yakin tidak lupa membatalkan registrasi penerima siaran di suatu tempat?" LUAR BIASA! Angkat topi untuk siapa pun yang menaruh semua pesan kecil ini untuk membantu kami bertengkar.
Nerdy Bunz

1
Saya bertemu masalah ini. ketika saya memperbarui targetSdkVersion ke 28.
illusionJJ

Jawaban:


575

Antara

  • cache objek Konteks melalui konstruktor di adaptor Anda, atau
  • dapatkan dari pandanganmu.

Atau sebagai pilihan terakhir,

  • tambahkan - FLAG_ACTIVITY_NEW_TASK panji untuk maksud Anda:

_

myIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

Sunting - saya akan menghindari pengaturan bendera karena akan mengganggu aliran normal tumpukan peristiwa dan riwayat.


6
Bagaimana dengan fitur autoLink dari TextView di mana saya tidak dapat mengontrol Intent (dan dengan demikian menandai) yang dibuat oleh sistem?
Alex Semeniuk

75
Saya mendapatkan pengecualian ini ketika saya melakukan sesuatu seperti ini context.startActivity(intent);saya hanya berubah contextdari ApplicationContextke Activityjenis. Ini memperbaiki masalah.
Sufian

@AlexSemeniuk pernah menemukan solusi?

@AlexSemeniuk - tautan otomatis akan berfungsi selama Anda meneruskan aktivitas sebagai konteks ke adaptor
Georges

Saya melewati objek Konteks melalui konstruktor tetapi tidak berfungsi. tapi FLAG_ACTIVITY_NEW_TASK bekerja sangat baik untuk saya, terima kasih.
Hiren

100

Anda dapat mencapainya dengan addFlags alih-alihsetFlags

myIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

Menurut dokumentasi yang dilakukannya:

Tambahkan bendera tambahan ke maksud (atau dengan nilai bendera yang ada).


EDIT

Berhati-hatilah jika Anda menggunakan bendera yang Anda ubah tumpukan riwayat seperti yang dikatakan Alex Volovoy :

... hindari pengaturan flag karena akan mengganggu aliran normal dari peristiwa dan tumpukan sejarah.


1
Saya memiliki masalah yang sangat mirip. Pernahkah Anda mengalami masalah dengan tumpukan riwayat atau apa pun sebagai jawaban di atas sugggest?
Einar Sundgren

1
Saya tidak yakin apa yang Anda cari tetapi Anda dapat memulai aktivitas tanpa riwayat seperti itu: Intent intent = new Intent (Intent.ACTION_VIEW, "http: \\ www.google.com")); intent. addFlags (Intent.FLAG_ACTIVITY_NO_HISTORY); startActivity (niat);
Bruno Bieri

Mengapa tidak disarankan untuk menambahkan Flags di sini? Seberapa penting hal itu mengganggu aliran peristiwa dan tumpukan riwayat yang normal?
Jason Krs

@JasonKrs Anda dapat menggunakan addFlags. Perlu diketahui bahwa Anda dapat mengubah tumpukan riwayat tergantung pada bendera yang Anda tambahkan. FLAG_ACTIVITY_NEW_TASK dapat digunakan dalam situasi ini. Untuk lebih jelasnya baca: developer.android.com/reference/android/content/…
Bruno Bieri


40

Jika Anda mendapat kesalahan karena menggunakan create chooser seperti di bawah ini:

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"));

Atur bendera untuk membuat pemilih seperti ini:

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);

4
Itu sangat berguna. Maksud pemilih yang tepat harus memiliki bendera ini!
Mahdi

2
Ini adalah soluction yang benar, dan apa yang harus dilakukan, new_task di intent.chooser
Rafael Guimarães

15

Selain itu: jika Anda menampilkan tautan dalam tampilan daftar dalam fragmen , jangan buat seperti ini

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

alih-alih menelepon

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

Adaptor berfungsi dengan baik dalam kedua kasus, tetapi tautan hanya berfungsi di yang terakhir.


@ user2676468: ini menyelesaikan masalah tautan otomatis untuk saya.
Kepala Geek

Ini seharusnya jawaban yang diterima, daripada menggunakan flag, ini lebih baik !!
Gastón Saillén

@ GastónSaillén, saya tidak menggunakan getApplicationContext()(kecuali inisialisasi aplikasi), tetapi menangkap pengecualian ini. Jadi, situasinya bisa berbeda.
CoolMind

Ini adalah masalah saya, saya menggunakan getApplicationContext () untuk konteks. Pengaturan thissebagai konteks berfungsi karena terkait dengan aktivitas saat ini.
Brlja

14

Saya pikir mungkin Anda menerapkan OnClickListener di tempat yang salah - biasanya Anda harus menerapkan OnItemClickListener di Aktivitas Anda dan meletakkannya di ListView sebagai gantinya, atau Anda akan mendapatkan masalah dengan acara Anda ...


2
Anda menuntun saya ke solusinya. Saya perlu menggunakan OnItemClickListener, yang ditugaskan ke ListView. Berikut ini beberapa tautan untuk orang lain: developer.android.com/reference/android/widget/… androidpeople.com/... Terima kasih atas bantuannya.
Sako73

Harap berikan jawaban umum. Jawaban Alex Volovoy di bawah ini memecahkan masalah secara umum.
devanshu_kaushik

Untuk keturunan: Jika Anda secara langsung mendefinisikannya sebagai setListener (Listener baru) pada komponen yang memerlukan suatu Konteks, Anda membuat referensi implisit untuk seluruh aktivitas yang akan membocorkan memori seperti yang tidak akan Anda percayai. Ini dapat dielakkan dengan membuat pendengar kelas dalam statis atau dengan memindahkan pendengar ke kelas yang terpisah jika perlu dapat menangani input dari lebih dari satu asal.
G_V

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

atau

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

ubah ke bawah

CustomAdapter mAdapter = new CustomAdapter( this, yourlist);

8

Di Android 28(Android P)startActivity

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?");
}

Jadi cara terbaik adalah menambahkan 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);

Ini diperlukan untuk 28 perangkat di atas.
Md Mohsin

7

Lihat, jika Anda membuat maksud dalam listiner dalam beberapa metode

override onClick (View v).

kemudian panggil konteks melalui tampilan ini juga:

v.getContext ()

Bahkan tidak akan membutuhkan SetFlags ...


Dan situasi apa yang salah? v.getApplicationContext ()?
CoolMind

3

Bagi siapa pun yang menggunakan Xamarin.Android (MonoDroid) bahkan ketika StartActivity dipanggil dari aktivitas - ini sebenarnya adalah bug Xamarin dengan runtime ART baru, lihat https://bugzilla.xamarin.com/show_bug.cgi?id=17630


Ya Anda hanya perlu melakukan apa yang telah dijelaskan di atas, tetapi kata-katanya telah berubah ... niat. SetFlags (ActivityFlags.NewTask);
Luke Alderton

3

Menguraikan jawaban Alex Volovoy sedikit lagi -

jika Anda mendapatkan masalah ini dengan fragmen, getActivity () berfungsi dengan baik untuk mendapatkan konteksnya

Dalam kasus lain:

Jika Anda tidak ingin menggunakan-

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

lalu buat fungsi seperti ini di OutsideClass Anda -

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

Sekarang, dalam aktivitas utama Anda kapan pun Anda membuat OutsideClass baru panggil metode di atas segera setelah Anda menentukan OutsideClass yang memberikan konteks aktivitas sebagai argumen. Juga dalam aktivitas utama Anda membuat fungsi-

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

sekarang kembali ke OutsideClass Anda, dan untuk memulai aktivitas baru lakukan sesuatu seperti ini-

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

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

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

Dengan cara ini Anda akan dapat memulai berbagai aktivitas yang dipanggil dari OutsideClass yang berbeda tanpa mengacaukan bendera.

Catatan-Usahakan untuk tidak men-cache objek konteks melalui konstruktor untuk fragmen (dengan adaptor, baik-baik saja). Sebuah fragmen harus memiliki konstruktor kosong jika tidak aplikasi crash dalam beberapa skenario.

ingatlah untuk menelepon

OutsideClass.gettingContext(Context context);

dalam fungsi onResume () juga.


3

Kesalahan ini terjadi ketika mulai aktif tidak tahu mana aktivitasnya. Jadi, Anda harus menambahkan aktivitas sebelum startActivity ()

Anda harus mengatur

context.startActivity(yourIntent);

Jika Anda menelepon startActivitydari Fragment, penelepon sering kali dapat berupa fragmen, bukan aktivitas.
CoolMind

2

Menurut pendapat saya, lebih baik menggunakan metode startActivity()hanya dalam kode Anda Activity.class. Jika Anda menggunakannya di kelas Adapteratau lainnya, itu akan menghasilkan itu.


2

Saya juga punya masalah yang sama. Periksa semua konteks yang telah Anda lewati. Untuk ' tautan ' perlu Konteks Aktivitas, bukan konteks Aplikasi .

Ini adalah tempat di mana Anda harus memeriksa:

1.) Jika Anda menggunakan LayoutInflater maka periksa konteks apa yang telah Anda lewati.

2.) Jika Anda menggunakan Adaptor apa pun periksa konteks apa yang telah Anda lewati.


2

Saya memiliki masalah yang sama. Masalahnya dengan konteks. Jika Anda ingin membuka tautan apa pun (misalnya berbagi tautan apa saja melalui pemilih), lewati konteks aktivitas, bukan konteks aplikasi.

Jangan lupa menambahkan myIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)jika Anda tidak ada dalam aktivitas Anda.


2

Gunakan kode ini di Adapter_Activity Anda dan gunakan context.startActivity(intent_Object)danintent_Object.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

Seperti ini:

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

Berhasil....


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

Saya harap ini akan berhasil.


1

Menghadapi masalah yang sama kemudian diimplementasikan

intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

dan dipecahkan masalahnya.

Mungkin ada alasan lain yang terkait dengan adaptor tampilan daftar.
Anda dapat melihat blog ini , menggambarkannya dengan sangat baik.


blog bermanfaat, Terima kasih. :)
Rucha Bhatt Joshi

1

Gunakan kode ini. Bekerja dengan baik untuk saya. Bagikan Sesuatu dari Luar Aktivitas:

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);

Menyiapkan bendera mengacaukan riwayat stacktrace
Ezio

1

Karena menambahkan flag mempengaruhi event_flowdan stack_historylebih baik meneruskan 'konteks aplikasi' ke non-aktivitas dari mana Anda perlu memanggil kelas aktivitas dengan cara berikut:

"ActivityClassName.this" (Saat Anda melewati konteks dengan cara ini, itu akan berisi semua detail dan info yang Anda butuhkan untuk memanggil Aktivitas dari skenario non-aktivitas)

Jadi tidak perlu mengatur atau menambahkan flag, ini akan berfungsi dengan baik dalam setiap kasus.


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

0

Jika Anda meminta bagian Intent dalam plugin Cordova, pengaturan Bendera tidak akan membantu. Alih-alih gunakan ini -

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

0

Situasi saya sedikit berbeda, saya sedang menguji aplikasi saya menggunakan Espressodan saya harus meluncurkan Kegiatan saya dengan ActivityTestRuledari instrumentasi Context(yang bukan yang berasal dari suatu Activity).

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

Saya harus mengubah flag dan menambahkan orbitwise ( |di Java) denganIntent.FLAG_ACTIVITY_NEW_TASK

Jadi itu menghasilkan:

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

0

Versi Kotlin

val intent = Intent(Intent.ACTION_EDIT, ContactsContract.Profile.CONTENT_URI)
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
this.startActivity(intent)
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.