ฉันจะกลับไปที่กิจกรรมหลักได้อย่างถูกต้องได้อย่างไร?


179

ฉันมี 2 กิจกรรม (A และ B) ในแอปพลิเคชัน Android ของฉันและฉันใช้ความตั้งใจที่จะได้รับจากกิจกรรม A ถึงกิจกรรม B การใช้ parent_activity ถูกเปิดใช้งาน:

 <activity
        android:name=".B"
        android:label="B" >
        <meta-data
            android:name="android.support.PARENT_ACTIVITY"
            android:value="com.example.app_name.A" />
  </activity>

ฉันยังใช้ชุดรูปแบบที่มีปุ่มขึ้น

ดังนั้นหลังจากที่ฉันเรียกกิจกรรม BI สามารถใช้ปุ่มขึ้นเพื่อกลับไปที่กิจกรรม A ปัญหาคือแอปพลิเคชันดูเหมือนจะเรียกonCreate () -ฟังก์ชั่นของกิจกรรม A อีกครั้งและนี่ไม่ใช่พฤติกรรมที่ฉันต้องการ ฉันต้องการกิจกรรม A เพื่อให้ดูเหมือนกับที่ฉันเรียกก่อนหน้านี้ว่ากิจกรรม B

มีวิธีที่จะบรรลุเป้าหมายนี้หรือไม่?

ขอบคุณล่วงหน้า

แก้ไข:

ฉันไม่ได้เขียนโค้ดใด ๆ เพื่อเริ่มกิจกรรม B จากกิจกรรม A. ฉันคิดว่ามันสร้างโดย eclipse

คลาส B ดูเหมือนว่า:

    @Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_b);
    getActionBar().setDisplayHomeAsUpEnabled(true);
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.activity_b, menu);
    return true;
}


@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
        case android.R.id.home:
            NavUtils.navigateUpFromSameTask(this);
            return true;
    }
    return super.onOptionsItemSelected(item);
}

โพสต์รหัสของคุณสำหรับการเริ่มต้นกิจกรรม A จาก B ..
user370305

ถ้าฉันเข้าใจคุณถูกต้องคุณสามารถใช้ startActivityForResult () และส่งกลับ resultCode หรืออะไรก็ได้
Law Gimenez

โปรดอัปเดตคำตอบที่ถูกต้องที่ติดแท็กของคุณ! คำตอบที่ถูกต้องมาจาก LorenzCK - ไม่ใช่จากผู้ใช้ ...... ! การแท็กสิ่งนี้ถูกต้องทำให้เข้าใจผิดและทำให้โปรแกรมเมอร์เข้าใจผิดมากขึ้นเมื่อเทียบกับการนำทางด้านหลัง!
Zordid

Gee มีคำตอบที่ผิดมากมายที่นี่คุณช่วยทำความสะอาดสิ่งนี้ได้ไหม?
Zordid

@ashiaka - คำตอบที่ถูกต้องตามการออกแบบรหัสของคุณมีการปรับปรุง
user370305

คำตอบ:


334

คุณประกาศกิจกรรม A พร้อมกับมาตรฐานlaunchModeในรายการ Android ตามเอกสารหมายถึงสิ่งต่อไปนี้:

ระบบจะสร้างอินสแตนซ์ใหม่ของกิจกรรมในงานเป้าหมายและกำหนดเส้นทางเจตนา

ดังนั้นระบบจึงถูกบังคับให้สร้างกิจกรรม A (เช่นการเรียกonCreate) แม้ว่าจะมีการจัดการภาระงานอย่างถูกต้อง

ในการแก้ไขปัญหานี้คุณต้องเปลี่ยนรายการโดยเพิ่มแอตทริบิวต์ต่อไปนี้ในการประกาศกิจกรรม:

android:launchMode="singleTop"

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


11
นี่คือคำอธิบายจากเอกสาร Android,โหมด "มาตรฐาน" และ "singleTop" จะแตกต่างกันไปในแง่หนึ่ง: ทุกครั้งที่มีเจตนาใหม่สำหรับกิจกรรม "มาตรฐาน" อินสแตนซ์ใหม่ของคลาสจะถูกสร้างขึ้นเพื่อตอบสนองต่อ ความตั้งใจนั้น แต่ละอินสแตนซ์จัดการเจตนาเดียว ในทำนองเดียวกันอินสแตนซ์ใหม่ของกิจกรรม "singleTop" อาจถูกสร้างขึ้นเพื่อจัดการกับเจตนาใหม่ อย่างไรก็ตามหากภารกิจเป้าหมายมีอินสแตนซ์ที่มีอยู่ของกิจกรรมอยู่ที่ด้านบนสุดของสแต็กอินสแตนซ์นั้นจะได้รับเจตนาใหม่ (ในการเรียก onNewIntent ()); ไม่ได้สร้างอินสแตนซ์ใหม่
kpsfoo

หมายเหตุว่าตามเอกสาร navigateUpFromSameTask(...)ที่ควรจะเพิ่มFLAG_ACTIVITY_CLEAR_TOPไปupIntent(ผ่านnavigateUpTo(...)ซึ่งจะส่งผลให้พฤติกรรมเดียวกัน (ตามคำแนะนำนี้ ) แต่ธงไม่เคยตั้ง - และดังนั้นคำตอบนี้ทำให้รู้สึก
AniGif

82

คำตอบที่อัปเดต: การออกแบบการนำทางขึ้น

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

ดังนั้นคุณต้องประกาศกิจกรรมหลักของคุณในแท็กกิจกรรมพร้อมแอตทริบิวต์

android:parentActivityName

ชอบ,

<!-- The main/home activity (it has no parent activity) -->
    <activity
        android:name="com.example.app_name.A" ...>
        ...
    </activity>
    <!-- A child of the main activity -->
    <activity
        android:name=".B"
        android:label="B"
        android:parentActivityName="com.example.app_name.A" >
        <!-- Parent activity meta-data to support 4.0 and lower -->
        <meta-data
            android:name="android.support.PARENT_ACTIVITY"
            android:value="com.example.app_name.A" />
    </activity>

ด้วยกิจกรรมหลักที่ประกาศด้วยวิธีนี้คุณสามารถนำทางไปยังผู้ปกครองที่เหมาะสมเช่นด้านล่าง

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
    // Respond to the action bar's Up/Home button
    case android.R.id.home:
        NavUtils.navigateUpFromSameTask(this);
        return true;
    }
    return super.onOptionsItemSelected(item);
}

ดังนั้นเมื่อคุณเรียกNavUtils.navigateUpFromSameTask(this);วิธีนี้มันจะเสร็จสิ้นกิจกรรมปัจจุบันและเริ่มต้น (หรือดำเนินการต่อ) กิจกรรมหลักที่เหมาะสม FLAG_ACTIVITY_CLEAR_TOPหากผู้ปกครองกิจกรรมเป้าหมายที่อยู่ในงานของสแต็คกลับมาก็จะนำไปข้างหน้าตามที่กำหนดโดย

และเพื่อแสดงปุ่มขึ้นคุณต้องประกาศ setDisplayHomeAsUpEnabled():

@Override
public void onCreate(Bundle savedInstanceState) {
    ...
    getActionBar().setDisplayHomeAsUpEnabled(true);
}

คำตอบเก่า: (ไม่มีการนำทางขึ้นไปการนำทางย้อนกลับเริ่มต้น)

มันจะเกิดขึ้นเฉพาะเมื่อคุณเริ่มกิจกรรม A อีกครั้งจากกิจกรรม B

startActivity()การใช้

แทนที่จะเป็นสิ่งนี้จากกิจกรรม A ให้เริ่มกิจกรรม B โดยใช้startActivityForResult()และแทนที่onActivtyResult()ในกิจกรรม A

ตอนนี้ในกิจกรรม B เพียงfinish()กดปุ่มขึ้น ดังนั้นตอนนี้คุณนำไปที่กิจกรรม A onActivityResult()โดยไม่ต้องสร้างกิจกรรม A อีกครั้ง ..


ฉันไม่รู้ว่าจะเรียก startActivity () ในกิจกรรม B ได้อย่างไร ฉันโพสต์ซอร์สโค้ดของกิจกรรม B ...
ashiaka

18
แทนที่จะรหัสบรรทัด เขียนNavUtils.navigateUpFromSameTask(this); finish()
user370305

4
มันเป็นคำถามที่ว่าทำไม Google ถึงไม่พูดถึงอะไรเกี่ยวกับfinish()หรือstartActivityForResult()ในเอกสารประกอบใน Navigation ( developer.android.com/design/patterns/navigation.html )
wired00

ฟังดูเหมือนเป็นการแก้ปัญหาที่ลำบาก @ LorenzCK คำตอบน่าจะดีกว่ามาก
carmen_munich

ขอบคุณมากที่ใช้ NavUtils.navigateUpFromSameTask (อันนี้) บวกใหญ่! ฉันกำลังมองหาวิธีเช่นนี้เพื่อแทนที่ finish () ซึ่งไม่ได้กลับไปใช้กิจกรรมหลักภายใต้สถานการณ์บางอย่าง เสร็จสิ้น () เป็นหลักจะกลับไปที่กิจกรรมก่อนหน้าซึ่งไม่จำเป็นต้องเป็นกิจกรรมหลัก
ฮง

22

ฉันมีการตั้งค่าเดียวกันที่นำไปสู่พฤติกรรมที่ไม่พึงประสงค์เหมือนกัน สำหรับฉันสิ่งนี้ได้ผล: เพิ่มแอตทริบิวต์ต่อไปนี้ให้กับกิจกรรม A ในManifest.xmlแอพของฉัน:

android:launchMode="singleTask"

ดูบทความนี้สำหรับคำอธิบายเพิ่มเติม


1
จากมุมมองของฉันทางออกที่ถูกต้องในการแก้ไขปัญหา สิ่งนี้จะทำงานเหมือนกับว่าคุณเรียกว่าเสร็จสิ้น () หากมีกิจกรรมอยู่ในกองงาน หากไม่เป็นเช่นนั้นจะมีการสร้างและเริ่มต้น
Johan

5
นี่ไม่ใช่วิธีที่ถูกต้องเนื่องจากจะสร้างงานใหม่โดยไม่จำเป็นทุกครั้งคุณควรใช้ launchMode = "singleTop" แทน
kpsfoo

19

แม้ว่าจะเป็นคำถามเดิมที่นี่เป็นอีกหนึ่ง imho (ที่สะอาดและดีที่สุด) วิธีการแก้ปัญหาทั้งหมด answeres ก่อนหน้านี้ไม่ได้ทำงานให้ผมตั้งแต่deeplinked กิจกรรม BจากWidget

public void navigateUp() {
final Intent upIntent = NavUtils.getParentActivityIntent(this);
if (NavUtils.shouldUpRecreateTask(this, upIntent) || isTaskRoot()) {
    Log.v(logTag, "Recreate back stack");
        TaskStackBuilder.create(this).addNextIntentWithParentStack(upIntent).startActivities();
  } else {
    NavUtils.navigateUpTo(this, upIntent);
  }
}

[ https://stackoverflow.com/a/31350642/570168 ]

แต่โปรดดู: https://speakerdeck.com/jgilfelt/this-way-up-implementing-effective-navigation-on-android


7

วิธีที่ดีกว่าในการบรรลุเป้าหมายนี้คือการใช้สองสิ่ง: โทร:

NavUtils.navigateUpFromSameTask(this);

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

โหนดสนับสนุน:

หากคุณต้องการสนับสนุนเวอร์ชันด้านล่างเวอร์ชัน 4 คุณต้องรวมข้อมูลเมตาด้วย คลิกขวาที่กิจกรรมเพิ่ม -> ข้อมูลเมตาชื่อ = android.support.PARENT_ACTIVITY และค่า = your.full.activity.name

เพื่อรับลูกศรที่ดีในรุ่นที่ต่ำกว่าเช่นกัน:

getSupportActionBar().setDisplayHomeAsUpEnabled(true);

โปรดทราบว่าคุณจะต้องมีไลบรารีการสนับสนุนเวอร์ชัน 7 เพื่อให้การทำงานทั้งหมดนี้เป็นไปอย่างคุ้มค่า!


5

สิ่งที่ใช้ได้ผลสำหรับฉันคือการเพิ่ม:

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {

        switch (item.getItemId()) {
            case android.R.id.home:
                onBackPressed();
                return true;
            default:
                return super.onOptionsItemSelected(item);
        }
    }

    @Override
    public void onBackPressed() {
        finish();
    }

ถึงTheRelevantActivity.javaและตอนนี้มันทำงานได้ตามที่คาดไว้

และใช่อย่าลืมเพิ่ม:

getSupportActionbar.setDisplayHomeAsUpEnabled(true);ในonCreate()วิธีการ


4

ฉันพยายามandroid:launchMode="singleTask"แล้ว แต่ก็ไม่ได้ช่วยอะไร ทำงานให้ฉันโดยใช้android:launchMode="singleInstance"


การเพิ่ม android: launchMode = "singleInstance" ไปยังกิจกรรมหลักแก้ไขปัญหาให้ฉัน
emir

4

กำลังเพิ่มไปยังคำตอบของ @ LorenCK เปลี่ยน

NavUtils.navigateUpFromSameTask(this);

ในรหัสด้านล่างหากกิจกรรมของคุณสามารถเริ่มต้นจากกิจกรรมอื่นและสามารถเป็นส่วนหนึ่งของงานที่เริ่มโดยแอปอื่น

Intent upIntent = NavUtils.getParentActivityIntent(this);
if (NavUtils.shouldUpRecreateTask(this, upIntent)) {
    TaskStackBuilder.create(this)
            .addNextIntentWithParentStack(upIntent)
            .startActivities();
} else {
    NavUtils.navigateUpTo(this, upIntent);
}

สิ่งนี้จะเริ่มงานใหม่และเริ่มกิจกรรมหลักของกิจกรรมที่คุณสามารถกำหนดในรายการอย่างด้านล่างของรุ่น SDK ต่ำสุด <= 15

<meta-data
        android:name="android.support.PARENT_ACTIVITY"
        android:value="com.example.app_name.A" />

หรือใช้parentActivityNameถ้ามัน> 15


หมายเหตุ: อย่าประกาศparentActivityNameสำหรับ SDK> 15 มิฉะนั้นจะทำให้คุณเกิดข้อผิดพลาดแบบสุ่ม
Sourabh

3

ฉันมีปัญหาคล้ายกันโดยใช้ android 5.0 ที่มีชื่อกิจกรรมหลักที่ไม่ดี

<activity
        android:name=".DisplayMessageActivity"
        android:label="@string/title_activity_display_message"
        android:parentActivityName=".MainActivity" >
        <meta-data
            android:name="android.support.PARENT_ACTIVITY"
            android:value="com.example.myfirstapp.MainActivity" />
    </activity>

ฉันลบ com.example.myfirstapp ออกจากชื่อกิจกรรมหลักและทำงานได้อย่างถูกต้อง


2

เพิ่มข้อมูลรายการกิจกรรมด้วยแอตทริบิวต์

android:launchMode="singleTask"

ทำงานได้ดีสำหรับฉัน


1
โฟลว์ Comlete เหมือนกับ @Override บูลีนสาธารณะ onOptionsItemSelected (รายการเมนูรายการ) {switch (item.getItemId ()) {case android.R.id.home: NavUtils.navigateUpFromSameTask (นี้); กลับจริง } คืนค่า super.onOptionsItemSelected (รายการ); }
Pravesh Kumar

เพิ่มในรายการ <กิจกรรม android: name = ". MainActivity" android: label = "@ string / title_activity_main"> </activity> <กิจกรรม android: name = ". CreateEventActivity" android: label = "@ string / title_activity_create_event" : launchMode = "singleTask" android: parentActivityName = ". MainActivity"> <meta-data android: name = "android.support.PARENT_ACTIVITY" android: value = ". MainActivity" /> </activity>
Pravesh Kumar

2

ในคลาส Java: -

    toolbar = (Toolbar) findViewById(R.id.apptool_bar);
    setSupportActionBar(toolbar);

    getSupportActionBar().setTitle("Snapdeal");

    getSupportActionBar().setHomeButtonEnabled(true);
    getSupportActionBar().setDisplayHomeAsUpEnabled(true);

ในรายการ: -

<activity
            android:name=".SubActivity"
            android:label="@string/title_activity_sub"
            android:theme="@style/AppTheme" >
            <meta-data android:name="android.support.PARENT_ACTIVITY" android:value=".MainActivity"></meta-data>
    </activity>

มันจะช่วยคุณ


1
    @Override
public boolean onOptionsItemSelected(MenuItem item) {
   switch (item.getItemId()) {
// Respond to the action bar's Up/Home button
    case android.R.id.home:
        finish();
        return true;
}
return super.onOptionsItemSelected(item);

เหมือนกดย้อนกลับ


1

ลองนี้:

Intent intent;
@Override
public void onCreate(Bundle savedInstanceState) {
    intent = getIntent();   
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_b);
    getActionBar().setDisplayHomeAsUpEnabled(true);
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.activity_b, menu);
    return true;
}  

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
        case android.R.id.home:
            NavUtils.navigateUpTo(this,intent);
            return true;
    }
    return super.onOptionsItemSelected(item);
}

0

เข้าไปในรายการของฉันและเพิ่ม android:launchMode="singleTop"เข้าไปในกิจกรรมทำให้ฉันมีเล่ห์เหลี่ยม

นี่เป็นการแก้ไขปัญหาของฉันโดยเฉพาะเพราะฉันไม่ต้องการให้ Android สร้างอินสแตนซ์ใหม่ของกิจกรรมก่อนหน้านี้หลังจากกดปุ่ม Upปุ่มในแถบเครื่องมือ - ฉันต้องการใช้อินสแตนซ์ที่มีอยู่ของกิจกรรมก่อนหน้านี้เมื่อฉันขึ้นไปตามลำดับชั้นการนำทาง

การอ้างอิง: android: launchMode


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