การเรียก startActivity () จากด้านนอกของบริบทกิจกรรม


367

ฉันใช้งานListViewแอปพลิเคชัน Android ของฉันแล้ว ฉันผูกกับสิ่งนี้ListViewโดยใช้คลาสย่อยที่กำหนดเองของArrayAdapterชั้นเรียน ภายในแทนที่วิธีการที่ผมกำหนดArrayAdapter.getView(...) OnClickListenerในonClickวิธีการOnClickListenerฉันต้องการเปิดกิจกรรมใหม่ ฉันได้รับการยกเว้น:

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

ฉันจะทราบได้อย่างไรContextว่าListView(ปัจจุบันActivity) ทำงานภายใต้


1
ฉันคิดว่าคำตอบของ Alex ควรเป็นคำตอบที่ 'ยอมรับ' สำหรับปัญหาของคุณเนื่องจากจะแก้ไขข้อผิดพลาดที่คุณพูดในลักษณะทั่วไปมากกว่านี้
devanshu_kaushik

10
ฉันชอบที่ "นี่คือสิ่งที่คุณต้องการจริง ๆ ?" ... ฉันเคยมีข้อความก่อนหน้านั้นพูดว่า "คุณแน่ใจหรือว่าคุณไม่ลืมยกเลิกการลงทะเบียนเครื่องรับบางแห่ง?" น่ากลัว! สวมหมวกกับใครก็ตามที่ใส่ข้อความเล็ก ๆ เหล่านี้เพื่อช่วยพวกเรา
Nerdy Bunz

1
ฉันพบปัญหานี้แล้ว เมื่อฉันอัปเดต targetSdkVersion เป็น 28
ภาพลวงตา

คำตอบ:


574

ทั้ง

  • แคชวัตถุบริบทผ่านตัวสร้างในอะแดปเตอร์ของคุณหรือ
  • รับจากมุมมองของคุณ

หรือเป็นทางเลือกสุดท้าย

  • เพิ่ม - FLAG_ACTIVITY_NEW_TASK ตั้งค่าสถานะตามที่คุณต้องการ:

_

myIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

แก้ไข - ฉันจะหลีกเลี่ยงการตั้งค่าสถานะเนื่องจากจะรบกวนการไหลปกติของเหตุการณ์และสแต็คประวัติ


6
สิ่งที่เกี่ยวกับคุณสมบัติautoLinkของ TextView ที่ฉันไม่สามารถควบคุม Intent (และตั้งค่าสถานะ) ที่สร้างโดยระบบได้
Alex Semeniuk

75
ฉันได้รับข้อยกเว้นนี้เมื่อฉันทำอะไรเช่นนี้context.startActivity(intent);ฉันเพิ่งเปลี่ยนcontextจากApplicationContextเป็นActivityประเภท วิธีนี้แก้ไขปัญหาได้
Sufian

@AlexSemeniuk เคยพบทางออกหรือไม่

@AlexSemeniuk - autoLink จะทำงานได้ตราบใดที่คุณผ่านกิจกรรมตามบริบทของอะแดปเตอร์
Georges

ฉันผ่านวัตถุบริบทผ่านตัวสร้าง แต่มันไม่ทำงาน แต่ FLAG_ACTIVITY_NEW_TASK ใช้งานได้ดีมากสำหรับฉันขอบคุณ
Hiren

100

คุณสามารถทำได้ด้วยaddFlagsแทนsetFlags

myIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

ตามเอกสารมัน:

เพิ่มการตั้งค่าสถานะเพิ่มเติมลงในเจตนา (หรือด้วยค่าสถานะที่มีอยู่)


แก้ไข

ระวังถ้าคุณใช้แฟล็กที่คุณเปลี่ยนสแต็กประวัติตามคำตอบของ Alex Volovoyพูดว่า:

... หลีกเลี่ยงการตั้งค่าสถานะเนื่องจากจะรบกวนการไหลปกติของเหตุการณ์และประวัติสแต็ก


1
ฉันมีปัญหาที่คล้ายกันมาก คุณเคยประสบปัญหาใด ๆ กับสแต็คประวัติหรือสิ่งอื่นใดเป็นคำตอบข้างต้นที่ดีที่สุด?
Einar Sundgren

1
ฉันไม่แน่ใจว่าสิ่งที่คุณกำลังมองหา แต่คุณสามารถเริ่มต้นกิจกรรมที่ไม่มีประวัติเช่นนั้น: เจตนาเจตนา = เจตนาใหม่ (Intent.ACTION_VIEW, "http: \\ www.google.com")); เจตนา addFlags (Intent.FLAG_ACTIVITY_NO_HISTORY); startActivity (เจตนา);
Bruno Bieri

ทำไมถึงไม่แนะนำให้เพิ่มFlagsที่นี่ การแทรกแซงเหตุการณ์และสแต็คประวัติเป็นเรื่องสำคัญเพียงใด
Jason Krs

@ JasonKrs คุณสามารถใช้ addFlags เพิ่งทราบว่าคุณสามารถเปลี่ยนสแต็คประวัติขึ้นอยู่กับการตั้งค่าสถานะที่คุณเพิ่ม FLAG_ACTIVITY_NEW_TASK สามารถใช้ได้ในสถานการณ์นี้ สำหรับรายละเอียดเพิ่มเติมอ่านได้ที่: developer.android.com/reference/android/content/…
Bruno Bieri

64

แทนที่จะใช้การ(getApplicationContext)ใช้งานYourActivity.this


สิ่งนี้ใช้ได้กับฉันเช่นใช้activity.startActivityแทนcontext.startActivity
Phani Rithvij

คำตอบที่ดีที่สุด!
amirhossein

มันใช้งานได้สำหรับฉัน
user5722540

40

หากคุณมีข้อผิดพลาดเนื่องจากการใช้ create chooser เช่นด้านล่าง:

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

ตั้งค่าสถานะเพื่อสร้างตัวเลือกเช่นนี้:

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
มันมีประโยชน์มาก ผู้เลือกเจตนาที่แน่นอนควรมีธงนี้!
มาห์ดี

2
นี่คือ Soluction ที่ถูกต้องและสิ่งที่ต้องทำใน new_task intent.chooser
ราฟาเอลGuimarães

15

นอกจากนี้: หากคุณแสดงลิงก์ใน listview เป็นส่วนอย่าสร้างมันขึ้นมาเช่นนี้

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

แทนการโทร

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

อะแดปเตอร์ทำงานได้ดีในทั้งสองกรณี แต่การเชื่อมโยงใช้งานได้ในครั้งสุดท้ายเท่านั้น


@ user2676468: วิธีนี้แก้ไขปัญหาการล็อกอัตโนมัติสำหรับฉัน
Head Geek

นี่ควรเป็นคำตอบที่ยอมรับได้แทนที่จะใช้ธงนี่ดีกว่า !!
GastónSaillén

@ GastónSaillénฉันไม่ได้ใช้getApplicationContext()(ยกเว้นการเริ่มต้นแอปพลิเคชัน) แต่พบข้อยกเว้นนี้ ดังนั้นสถานการณ์อาจแตกต่างกัน
CoolMind

นี่เป็นปัญหาของฉันฉันใช้ getApplicationContext () สำหรับบริบท การตั้งค่าthisเป็นบริบททำงานตามที่เกี่ยวข้องกับกิจกรรมปัจจุบัน
Brlja

14

ฉันคิดว่าบางทีคุณกำลังใช้งาน OnClickListener ในที่ที่ไม่ถูกต้อง - โดยปกติคุณควรใช้ OnItemClickListener ในกิจกรรมของคุณและตั้งไว้ที่ ListView แทนหรือคุณจะได้รับปัญหาเกี่ยวกับกิจกรรมของคุณ ...


2
คุณนำฉันไปสู่ทางออก ฉันต้องการใช้ OnItemClickListener ที่กำหนดให้กับ ListView : ที่นี่เชื่อมโยงบางอย่างสำหรับคนอื่นที่มีdeveloper.android.com/reference/android/widget/... androidpeople.com/... ขอบคุณสำหรับความช่วยเหลือ
Sako73

โปรดระบุคำตอบทั่วไป คำตอบของ Alex Volovoy ด้านล่างแก้ปัญหาในลักษณะทั่วไป
devanshu_kaushik

สำหรับลูกหลาน: หากคุณกำหนดโดยตรงเป็น setListener (ผู้ฟังใหม่) ในองค์ประกอบที่ต้องใช้บริบทคุณจะสร้างการอ้างอิงโดยนัยไปยังกิจกรรมทั้งหมดซึ่งจะทำให้หน่วยความจำรั่วเหมือนที่คุณไม่เชื่อ สิ่งนี้สามารถหลีกเลี่ยงได้โดยการสร้างผู้ฟังชั้นในแบบคงที่หรือโดยการย้ายผู้ฟังไปยังชั้นที่แยกต่างหากถ้ามันจะต้องสามารถที่จะจัดการกับอินพุตจากแหล่งกำเนิดมากกว่าหนึ่ง
G_V

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

หรือ

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

เปลี่ยนเป็นด้านล่าง

CustomAdapter mAdapter = new CustomAdapter( this, yourlist);

8

ที่จุดAndroid 28(Android P)เริ่มต้นกิจกรรม

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

ดังนั้นวิธีที่ดีที่สุดคือการเพิ่ม 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);

จำเป็นสำหรับอุปกรณ์ 28 เครื่องขึ้นไป
Md Mohsin

7

ดูว่าคุณกำลังสร้างเจตนาภายในตัวสร้างรายชื่อในบางวิธี

override onClick (View v).

จากนั้นเรียกบริบทผ่านมุมมองนี้เช่นกัน:

v.getContext ()

ไม่จำเป็นต้องมีแม้แต่ SetFlags ...


และสถานการณ์ผิดปกติคืออะไร? v.getApplicationContext ()?
CoolMind

3

สำหรับใครก็ตามที่ได้รับสิ่งนี้บนXamarin.Android (MonoDroid)แม้ว่าจะเรียก StartActivity จากกิจกรรม - นี่คือข้อผิดพลาด Xamarin จริง ๆ กับ ART runtime ใหม่ให้ดูhttps://bugzilla.xamarin.com/show_bug.cgi?id=17630


ใช่คุณเพียงแค่ต้องทำตามที่อธิบายไว้ข้างต้น แต่ข้อความได้เปลี่ยนไปแล้ว ... intent.SetFlags (ActivityFlags.NewTask);
ลุคอัลเดอร์ตัน

3

อธิบายคำตอบของ Alex Volovoy ให้ละเอียดยิ่งขึ้น -

ในกรณีที่คุณได้รับปัญหานี้ด้วยชิ้นส่วน getActivity () ทำงานได้ดีเพื่อให้ได้บริบท

ในกรณีอื่น ๆ :

หากคุณไม่ต้องการใช้ -

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

จากนั้นสร้างฟังก์ชันเช่นนี้ใน OutsideClass ของคุณ -

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

ตอนนี้ในกิจกรรมหลักของคุณเมื่อคุณทำการ OutsideClass ใหม่เรียกเมธอดด้านบนทันทีหลังจากที่คุณกำหนด OutsideClass ให้บริบทของกิจกรรมเป็นอาร์กิวเมนต์ ในกิจกรรมหลักของคุณ

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

ตอนนี้กลับมาที่ OutsideClass ของคุณและเริ่มกิจกรรมใหม่ทำสิ่งนี้ -

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

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

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

วิธีนี้คุณจะสามารถเริ่มต้นกิจกรรมที่แตกต่างกันที่เรียกว่า OutsideClass ที่แตกต่างกันโดยไม่ต้องยุ่งกับการตั้งค่าสถานะ

หมายเหตุ - พยายามอย่าแคชอ็อบเจ็กต์บริบทผ่านตัวสร้างสำหรับแฟรกเมนต์ (ด้วยอะแด็ปเตอร์มันใช้ได้) แฟรกเมนต์ A ควรมีคอนสตรัคเตอร์เปล่ามิฉะนั้นแอปพลิเคชันขัดข้องในบางสถานการณ์

อย่าลืมโทร

OutsideClass.gettingContext(Context context);

ในฟังก์ชั่น onResume () เช่นกัน


3

ข้อผิดพลาดนี้เกิดขึ้นเมื่อ startactivity ไม่รู้ว่ากิจกรรมของเขาคืออะไร ดังนั้นคุณต้องเพิ่มกิจกรรมก่อน startActivity ()

คุณต้องตั้งค่า

context.startActivity(yourIntent);

หากคุณโทรstartActivityจากFragmentผู้โทรมักเป็นแฟรกเมนต์ไม่ใช่กิจกรรม
CoolMind

2

ในความคิดของฉันดีกว่าที่จะใช้วิธีการstartActivity()เพียงแค่ในรหัสของActivity.classคุณ ถ้าคุณใช้มันในAdapterคลาสอื่นมันจะส่งผลให้คุณ


2

ฉันก็มีปัญหาเดียวกัน ตรวจสอบบริบททั้งหมดที่คุณได้ผ่าน สำหรับ ' ลิงก์ ' จะต้องมีบริบทของกิจกรรมไม่ใช่บริบทของแอปพลิเคชันประยุกต์ใช้บริบท

นี่คือสถานที่ที่คุณควรตรวจสอบ:

1. ) ถ้าคุณใช้LayoutInflaterตรวจสอบบริบทที่คุณได้ผ่าน

2. ) หากคุณใช้อะแดปเตอร์ใด ๆ ให้ตรวจสอบว่าคุณผ่านบริบทใดไป


2

ผมมีปัญหาเดียวกัน. ปัญหาเกิดขึ้นกับบริบท หากคุณต้องการเปิดลิงก์ใด ๆ (เช่นแชร์ลิงก์ใด ๆ ผ่านตัวเลือก) ผ่านบริบทของกิจกรรมไม่ใช่บริบทของแอปพลิเคชัน

อย่าลืมที่จะเพิ่มmyIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)ถ้าคุณไม่ได้อยู่ในกิจกรรมของคุณ


2

ใช้รหัสนี้ใน Adapter_Activity และใช้context.startActivity(intent_Object)และintent_Object.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

แบบนี้:

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

มันได้ผล....


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

ฉันหวังว่ามันจะใช้ได้


1

ประสบปัญหาเดียวกันแล้วนำไปใช้

intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

และได้แก้ไขปัญหา

อาจมีสาเหตุอื่นที่เกี่ยวข้องกับรายการมุมมองการ์ดเชื่อมต่อ
คุณสามารถดูบล็อกนี้อธิบายได้ดีมาก


บล็อกที่เป็นประโยชน์ขอขอบคุณ :)
Rucha Bhatt Joshi

1

ใช้รหัสนี้ ทำงานได้ดีสำหรับฉัน แบ่งปันบางสิ่งจากภายนอกกิจกรรม:

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

การตั้งค่าสถานะทำให้ยุ่งเหยิงประวัติ stacktrace
Ezio

1

เนื่องจากการเพิ่มค่าสถานะมีผลกับevent_flowและstack_historyเป็นการดีกว่าที่จะส่ง 'บริบทของแอปพลิเคชัน' ไปยังกิจกรรมที่ไม่ใช่กิจกรรมที่คุณต้องเรียกคลาสกิจกรรมด้วยวิธีต่อไปนี้:

"ActivityClassName.this" (ในขณะที่คุณผ่านบริบทในลักษณะนี้จะมีรายละเอียดและข้อมูลทั้งหมดที่คุณต้องเรียกกิจกรรมจากสถานการณ์ที่ไม่ใช่กิจกรรม)

ดังนั้นไม่จำเป็นต้องตั้งค่าหรือเพิ่มแฟล็กซึ่งจะทำงานได้ดีในทุกกรณี



0

หากคุณกำลังเรียกใช้การแชร์ Intent ในปลั๊กอิน Cordova การตั้งค่าสถานะจะไม่ช่วย ใช้สิ่งนี้แทน -

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

0

สถานการณ์ของฉันแตกต่างกันเล็กน้อยฉันกำลังทดสอบแอพของฉันโดยใช้Espressoและฉันต้องเปิดใช้งานกิจกรรมของฉันActivityTestRuleจากเครื่องมือContext(ซึ่งไม่ใช่สิ่งที่มาจากActivity)

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

ฉันต้องเปลี่ยนค่าสถานะและเพิ่มorค่าบิต ( |ใน Java) ด้วยIntent.FLAG_ACTIVITY_NEW_TASK

ดังนั้นผลลัพธ์ใน:

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

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.