รับกิจกรรมจากบริบทใน Android


184

อันนี้ทำให้ฉันนิ่งงัน

ฉันต้องการเรียกวิธีกิจกรรมจากภายในคลาสเลย์เอาต์ที่กำหนดเอง ปัญหาของเรื่องนี้คือฉันไม่รู้วิธีเข้าถึงกิจกรรมจากภายในโครงร่าง

โปรไฟล์ของ

public class ProfileView extends LinearLayout
{
    TextView profileTitleTextView;
    ImageView profileScreenImageButton;
    boolean isEmpty;
    ProfileData data;
    String name;

    public ProfileView(Context context, AttributeSet attrs, String name, final ProfileData profileData)
    {
        super(context, attrs);
        ......
        ......
    }

    //Heres where things get complicated
    public void onClick(View v)
    {
        //Need to get the parent activity and call its method.
        ProfileActivity x = (ProfileActivity) context;
        x.activityMethod();
    }
}

ProfileActivity

public class ProfileActivityActivity extends Activity
{
    //In here I am creating multiple ProfileViews and adding them to the activity dynamically.

    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.profile_activity_main);
    }

    public void addProfilesToThisView()
    {
        ProfileData tempPd = new tempPd(.....)
        Context actvitiyContext = this.getApplicationContext();
        //Profile view needs context, null, name and a profileData
        ProfileView pv = new ProfileView(actvitiyContext, null, temp, tempPd);
        profileLayout.addView(pv);
    }
}

ดังที่คุณเห็นด้านบนฉันกำลังสร้างโปรไฟล์ viewView แบบเป็นโปรแกรมและส่งต่อในกิจกรรมContextด้วย 2 คำถาม:

  1. ฉันกำลังส่งบริบทที่ถูกต้องไปยัง Profileview หรือไม่
  2. ฉันจะรับกิจกรรมที่มีจากบริบทได้อย่างไร

คำตอบ:


472

จากคุณActivityเพียงแค่ผ่านในthisขณะที่Contextสำหรับรูปแบบของคุณ:

ProfileView pv = new ProfileView(this, null, temp, tempPd);

หลังจากนั้นคุณจะมีContextเลย์เอาต์ แต่คุณจะรู้ว่ามันเป็นของคุณActivityและคุณสามารถส่งมันเพื่อให้คุณมีสิ่งที่คุณต้องการ:

Activity activity = (Activity) context;

53
คุณไม่สามารถรับประกันได้ว่าบริบทที่คุณกำลังทำงานคือบริบทของกิจกรรมหรือบริบทของแอปพลิเคชัน ลองส่งบริบทของแอปพลิเคชันไปยัง DialogView ดูว่ามันขัดข้องและคุณจะเห็นความแตกต่าง
Sky Kelsey

6
Boris คำถามถามว่ามีวิธีรับกิจกรรมจากบริบทหรือไม่ สิ่งนี้เป็นไปไม่ได้ แน่นอนคุณสามารถส่ง แต่เป็นทางเลือกสุดท้าย หากคุณต้องการที่จะปฏิบัติต่อบริบทว่าเป็นกิจกรรมแล้วอย่าย่อส่วนลงในกิจกรรม มันทำให้รหัสง่ายขึ้นและมีแนวโน้มที่จะเกิดข้อผิดพลาดน้อยกว่าในภายหลังเมื่อบุคคลอื่นกำลังรักษารหัสของคุณ
Sky Kelsey

6
โปรดทราบว่า 'getApplicationContext ()' แทน 'this' จะไม่ทำงาน
dwbrito

1
@ BorisStrandjev ฉันไม่เข้าใจความคิดเห็นของคุณ อย่างไรก็ตามฉันบอกว่าหลังจากลองตัวอย่างของคุณ แต่แทนที่จะเป็น 'this' ฉันใช้ getApplicationContext () และแอปพลิเคชันพยายามที่จะส่งแอพด้วยตัวเองดังนั้นจึงทำให้เกิดข้อผิดพลาดในการส่งแทนที่จะเป็นกิจกรรม หลังจากเปลี่ยนเป็น 'นี้' ตามที่คุณตอบแล้วก็ใช้งานได้
dwbrito

1
คำตอบ upvoted ที่สูงที่สุดในลิงก์ของคุณทั้งคู่แนะนำให้ท้าทายคำถามหากมีกลิ่นเหม็น คำถามนี้ส่งกลิ่นอย่างแน่นอน OP ระบุไว้ก่อน: "ฉันต้องเรียกวิธีการกิจกรรมจากภายในคลาสเลย์เอาต์ที่กำหนดเอง" ซึ่งสามารถทำได้อย่างสมบูรณ์ด้วยการใช้อินเตอร์เฟซที่เหมาะสม จากนั้นเขาก็พูดว่า "ปัญหาของเรื่องนี้คือฉันไม่รู้วิธีเข้าถึงกิจกรรมจากภายในโครงร่าง" ซึ่งเป็นคำใบ้สำคัญต่อความเข้าใจผิด ผู้คนพยายามทำสิ่งที่ผิดตลอดเวลาในการเขียนโปรแกรมและเราไม่ควรเมินมัน
Sam

39

นี่คือสิ่งที่ฉันใช้ในการแปลงContextเป็นActivityปฏิบัติการเมื่อใช้งานภายใน UI ในแฟรกเมนต์หรือมุมมองที่กำหนดเอง มันจะแกะ ContextWrapper ซ้ำหรือคืนค่าว่างถ้ามันล้มเหลว

public Activity getActivity(Context context)
{
    if (context == null)
    {
        return null;
    }
    else if (context instanceof ContextWrapper)
    {
        if (context instanceof Activity)
        {
            return (Activity) context;
        }
        else
        {
            return getActivity(((ContextWrapper) context).getBaseContext());
        }
    }

    return null;
}

นี่คือคำตอบที่ถูกต้อง อีกอันหนึ่งไม่ได้คำนึงถึงลำดับชั้นของ ContentWrapper
Snicolas

นี่คือคำตอบที่แท้จริง :)
lygstate

1
@lygstate: คุณใช้ API เป้าหมายระดับใดในแอปของคุณ ข้อผิดพลาดคืออะไร? ใช้งานได้เฉพาะภายใน UI (กิจกรรมชิ้นส่วน ฯลฯ ) ไม่ได้อยู่ในบริการ
ธีโอ

31
  1. ไม่
  2. คุณทำไม่ได้

มีสองบริบทที่แตกต่างกันใน Android หนึ่งรายการสำหรับแอปพลิเคชันของคุณ (ลองเรียกมันว่าใหญ่) และอีกอันสำหรับแต่ละมุมมอง

linearLayout เป็นมุมมองดังนั้นคุณต้องเรียกบริบทของกิจกรรม หากต้องการโทรจากกิจกรรมเพียงแค่เรียก "นี้" ง่ายมากใช่ไหม

เมื่อคุณใช้

this.getApplicationContext();

คุณเรียกบริบทบิ๊กบริบทที่อธิบายแอปพลิเคชันของคุณและไม่สามารถจัดการมุมมองของคุณ

ปัญหาใหญ่ของ Android คือบริบทไม่สามารถเรียกกิจกรรมของคุณได้ นั่นเป็นเรื่องใหญ่ที่จะหลีกเลี่ยงสิ่งนี้เมื่อมีคนเริ่มต้นด้วยการพัฒนา Android คุณต้องหาวิธีที่ดีกว่าในการเขียนรหัสชั้นเรียนของคุณ (หรือแทนที่ "บริบทบริบท" ด้วย "กิจกรรมกิจกรรม" และเปลี่ยนเป็น "บริบท" เมื่อจำเป็น)

ความนับถือ.


เพียงเพื่ออัปเดตคำตอบของฉัน วิธีที่ง่ายที่สุดในการรับของคุณActivity contextคือการกำหนดเช่นในของคุณstatic Activityตัวอย่างเช่น

public class DummyActivity extends Activity
{
    public static DummyActivity instance = null;

    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);

        // Do some operations here
    }

    @Override
    public void onResume()
    {
        super.onResume();
        instance = this;
    }

    @Override
    public void onPause()
    {
        super.onPause();
        instance = null;
    }
}

จากนั้นในของคุณTask, Dialog, Viewคุณสามารถใช้ชนิดของรหัสที่จะได้รับของคุณActivity context:

if (DummyActivity.instance != null)
{
    // Do your operations with DummyActivity.instance
}

4
+1 สำหรับอธิบายพื้นที่ที่พบบ่อยมากของความสับสนระหว่างทั้ง 2 ชนิดที่แตกต่างกันของบริบท (เช่นเดียวกับมี 2 ที่แตกต่างกันRs) คน Google ต้องเสริมคำศัพท์ของพวกเขา
an00b

3
BTW, @BorisStrandjev คือถูกต้อง: 2 ใช่คุณสามารถ (ไม่สามารถโต้เถียงกับรหัสการทำงาน)
an00b

2
2. ไม่จริง หากบริบทเป็นบริบทของแอปพลิเคชันแอปของคุณก็จะขัดข้อง
StackOverflow

ตัวอย่างแบบคงที่! @Nepster มีทางออกที่ดีที่สุดสำหรับ imo นี้
Sam

14
การสร้างการอ้างอิงแบบคงที่ไปที่กิจกรรมเป็นวิธีที่ดีที่สุดในการสร้างการรั่วไหลของหน่วยความจำ
BladeCoder

8

หากคุณต้องการเรียกวิธีการกิจกรรมจากภายในคลาสเลย์เอาต์ที่กำหนดเอง (ไม่ใช่คลาสกิจกรรม) คุณควรสร้างผู้รับมอบสิทธิ์โดยใช้ส่วนต่อประสาน

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

ก่อนอื่นสร้างและอินเทอร์เฟซ

interface TaskCompleteListener<T> {
   public void onProfileClicked(T result);
}



public class ProfileView extends LinearLayout
{
    private TaskCompleteListener<String> callback;
    TextView profileTitleTextView;
    ImageView profileScreenImageButton;
    boolean isEmpty;
    ProfileData data;
    String name;

    public ProfileView(Context context, AttributeSet attrs, String name, final ProfileData profileData)
    {
        super(context, attrs);
        ......
        ......
    }
    public setCallBack( TaskCompleteListener<String> cb) 
    {
      this.callback = cb;
    }
    //Heres where things get complicated
    public void onClick(View v)
    {
        callback.onProfileClicked("Pass your result or any type");
    }
}

และนำสิ่งนี้ไปใช้กับกิจกรรมใด ๆ

และเรียกว่าชอบ

ProfileView pv = new ProfileView(actvitiyContext, null, temp, tempPd);
pv.setCallBack(new TaskCompleteListener
               {
                   public void onProfileClicked(String resultStringFromProfileView){}
               });

1
นี่คือคำตอบที่ถูกต้องและควรทำเครื่องหมายเป็นคำตอบที่ถูกต้อง ฉันรู้ว่าคำตอบที่ทำเครื่องหมายว่าเป็นคำตอบที่ถูกต้องจริงตอบคำถามของ OP แต่ไม่ควรตอบคำถามเช่นนั้น ความจริงก็คือว่าไม่ใช่วิธีปฏิบัติที่ดีที่จะส่งผ่านกิจกรรมเช่นนั้นในมุมมอง เด็กไม่ควรรู้เกี่ยวกับพ่อแม่ของพวกเขาในกรณีใด ๆ Contextยกเว้นผ่าน ในฐานะที่เป็นรัฐ Nepster วิธีปฏิบัติที่ดีที่สุดคือส่งผ่านการโทรกลับดังนั้นเมื่อใดก็ตามที่มีสิ่งใดที่เกิดความสนใจกับผู้ปกครองการโทรกลับจะถูกไล่ออกพร้อมข้อมูลที่เกี่ยวข้อง
Darwind

6

บริบทอาจเป็นแอปพลิเคชันบริการกิจกรรมและอื่น ๆ

โดยทั่วไปบริบทของการดูในกิจกรรมคือกิจกรรมดังนั้นคุณอาจคิดว่าคุณสามารถส่งบริบทนี้ไปที่กิจกรรมได้ แต่จริงๆแล้วคุณไม่สามารถทำได้เสมอไปเพราะบริบทอาจเป็น ContextThemeWrapper ในกรณีนี้

ContextThemeWrapper มีการใช้งานอย่างมากใน AppCompat และ Android รุ่นล่าสุด (ขอบคุณ android: คุณลักษณะของชุดรูปแบบในรูปแบบ) ดังนั้นฉันจะไม่แสดงแบบนี้เลย

คำตอบสั้น ๆ คือ: คุณไม่สามารถเรียกคืนกิจกรรมจากบริบทในมุมมองได้อย่างน่าเชื่อถือ ส่งผ่านกิจกรรมไปยังมุมมองโดยเรียกใช้เมธอดซึ่งใช้พารามิเตอร์เป็นกิจกรรม


3

ไม่เคยใช้getApplicationContext ()พร้อมมุมมอง

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


3

และใน Kotlin:

tailrec fun Context.activity(): Activity? = when {
  this is Activity -> this
  else -> (this as? ContextWrapper)?.baseContext?.activity()
}

0

กิจกรรมเป็นความเชี่ยวชาญของบริบทดังนั้นหากคุณมีบริบทที่คุณรู้อยู่แล้วว่ากิจกรรมที่คุณตั้งใจที่จะใช้และสามารถลงเพียงเข้า ; โดยที่aคือกิจกรรมและcคือบริบท

Activity a = (Activity) c;

7
สิ่งนี้เป็นอันตรายเพราะดังที่กล่าวไว้ในความคิดเห็นแยกบริบทอาจไม่ได้เป็นกิจกรรมเสมอไป

4
typecast เฉพาะในกรณี (บริบทของกิจกรรม) {// typecast}
Amit Yadav

0

ฉันใช้การแปลงกิจกรรม

Activity activity = (Activity) context;

2
บริบทแตกต่างกันไป กิจกรรมและแอปพลิเคชันสามารถมีบริบทได้ สิ่งนี้จะใช้งานได้เมื่อบริบทเป็นกิจกรรม
cylov

0

วิธีนี้ควรมีประโยชน์ .. !

public Activity getActivityByContext(Context context){

if(context == null){
    return null;
    }

else if((context instanceof ContextWrapper) && (context instanceof Activity)){
        return (Activity) context;
    }

else if(context instanceof ContextWrapper){
        return getActivity(((ContextWrapper) context).getBaseContext());
    }

return null;

    }

ฉันหวังว่านี้จะช่วย .. การเข้ารหัส Merry!


ตรวจสอบว่าบริบทที่คุณส่งไม่เป็นโมฆะ .. น่าจะเป็นปัญหามากที่สุด
Taslim Oseni

0

วิธีการโทรกลับข้อมูลสด

class ProfileView{
    private val _profileViewClicked = MutableLiveData<ProfileView>()
    val profileViewClicked: LiveData<ProfileView> = _profileViewClicked
}

class ProfileActivity{

  override fun onCreateView(...){

    profileViewClicked.observe(viewLifecycleOwner, Observer { 
       activityMethod()
    })
  }

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