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?

Sako73
sumber
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.

Alex Volovoy
sumber
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.

Bruno Bieri
sumber
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
64

Alih-alih menggunakan (getApplicationContext)gunakanYourActivity.this

Jeffrey Nyauke
sumber
Ini bekerja untuk saya yaitu menggunakan activity.startActivitybukannyacontext.startActivity
Phani Rithvij
JAWABAN TERBAIK!
amirhossein
Ini bekerja untuk saya.
user5722540
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);
sanath_p
sumber
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.

djdance
sumber
@ 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 ...

mreichelt
sumber
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);
Murtaza Ashraf
sumber
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);
Alen Lee
sumber
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 ...

Paulo Linhares - Packapps
sumber
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

rouen
sumber
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.

Monyet terbang
sumber
3

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

Anda harus mengatur

context.startActivity(yourIntent);
Cabezas
sumber
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.

kaosmys
sumber
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.

codemaniac
sumber
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.

Coder29
sumber
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....

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

Saya harap ini akan berhasil.

Chirag Patel
sumber
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.

Mayank Sharma
sumber
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);
Pooya Hayati
sumber
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.

Musthafa
sumber
0
Intent i= new Intent(context, NextActivity.class);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP);
Chandan Lal
sumber
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"));
Sandeep Kumar
sumber
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)
Rafael Ruiz Muñoz
sumber
0

Versi Kotlin

val intent = Intent(Intent.ACTION_EDIT, ContactsContract.Profile.CONTENT_URI)
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
this.startActivity(intent)
Sazzad Hissain Khan
sumber