Android의 컨텍스트에서 활동 가져 오기


184

이건 내가 엉망이야

사용자 정의 레이아웃 클래스 내에서 활동 메소드를 호출해야합니다. 이것의 문제는 레이아웃 내에서 활동에 액세스하는 방법을 모른다는 것입니다.

ProfileView

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

위에서 볼 수 있듯이 프로그래밍 방식으로 profileView를 인스턴스화하고 activityContext를 전달합니다. 두 가지 질문 :

  1. 올바른 컨텍스트를 Profileview에 전달하고 있습니까?
  2. 컨텍스트에서 포함 활동을 얻으려면 어떻게해야합니까?

답변:


472

에서 레이아웃 으로 다음 을 Activity전달 하십시오.thisContext

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

나중에 Context레이아웃에 표시되지만 실제로 레이아웃임을 알 Activity수 있으며 필요한 것을 갖도록 캐스팅 할 수 있습니다.

Activity activity = (Activity) context;

53
작업중인 컨텍스트가 활동 컨텍스트 또는 애플리케이션 컨텍스트임을 보장 할 수 없습니다. 응용 프로그램 컨텍스트를 DialogView에 전달하고 충돌을 관찰하면 차이가 나타납니다.
스카이 켈지

6
보리스, 질문은 컨텍스트에서 활동을 얻는 방법이 있는지 묻습니다. 이건 불가능 해. 물론 당신은 캐스팅 할 수 있지만 그것은 최후의 수단입니다. 컨텍스트를 활동으로 취급하려면 활동으로 다운 캐스트하지 마십시오. 코드가 간단 해지며 나중에 다른 사람이 코드를 관리 할 때 버그가 발생하기 쉽습니다.
스카이 켈시

6
'this'대신 'getApplicationContext ()'가 작동하지 않습니다.
dwbrito

1
@BorisStrandjev 나는 당신의 의견을 이해하지 못했습니다. 어쨌든, 나는 당신의 예제를 시도했지만 'this'대신 getApplicationContext ()를 사용하고 응용 프로그램이 응용 프로그램 자체를 캐스팅하려고 시도했기 때문에 활동 대신 캐스팅 오류가 발생했다고 말했습니다. 당신이 대답 한대로 'this'로 전환 한 후에 효과가있었습니다.
dwbrito

1
귀하의 링크에서 가장 많이 제기 된 답변은 냄새가 나면 질문에 도전하는 것을 암시합니다. 이 질문은 확실히 냄새가납니다. OP는 먼저 "사용자 정의 레이아웃 클래스 내에서 액티비티 메소드를 호출해야합니다."라고 말했습니다. 인터페이스를 적절하게 사용하면 완전히 달성 할 수 있습니다. "이것의 문제점은 레이아웃 내에서 액티비티에 액세스하는 방법을 모른다는 것입니다." 이것은 오해에 대한 중요한 힌트입니다. 사람들은 프로그래밍에서 항상 잘못된 일을하려고 노력하기 때문에 눈을 멀게하지 않아야합니다.
Sam

39

이것은 프래그먼트 또는 사용자 정의보기의 UI 내에서 작동 ContextActivity때 성공적으로 변환 하는 데 사용한 것입니다 . ContextWrapper를 재귀 적으로 풀거나 실패하면 null을 반환합니다.

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 (활동, 조각 등) 내에서만 작동합니다.
Theo

31
  1. 아니
  2. 넌 못해

Android에는 두 가지 컨텍스트가 있습니다. 하나는 응용 프로그램 (BIG 하나라고 함)과 각보기 (활동 컨텍스트라고 함)마다 하나입니다.

linearLayout은 뷰이므로 활동 컨텍스트를 호출해야합니다. 활동에서 호출하려면 간단히 "this"를 호출하십시오. 너무 쉽지 않습니까?

사용할 때

this.getApplicationContext();

애플리케이션을 설명하고 뷰를 관리 할 수없는 BIG 컨텍스트를 호출합니다.

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 개의 서로 다른 것 R). 구글 사람들은 어휘력을 풍부하게해야합니다.
an00b

3
BTW, @BorisStrandjev가 정확합니다 : 2. 그렇습니다 . (작업 코드로 논쟁 할 수 없음)
an00b

2
2. 실제로는 아닙니다. 컨텍스트가 애플리케이션 컨텍스트 인 경우 앱이 중단됩니다.
StackOverflowed

정적 인스턴스?! @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 : theme 속성 덕분에) 개인적 으로이 캐스트를 수행하지 않습니다.

짧은 대답은 뷰의 컨텍스트에서 활동을 안정적으로 검색 할 수 없다는 것입니다. 활동을 매개 변수로 사용하는 메소드를 호출하여 활동을보기에 전달하십시오.


3

getApplicationContext ()를 사용하지 마십시오뷰와 함께 를 .

보기가 활동에 첨부되어 있으므로 항상 활동의 컨텍스트 여야합니다. 또한 사용자 정의 테마 세트가있을 수 있으며 응용 프로그램 컨텍스트를 사용할 때 모든 테마가 손실됩니다. 다양한 버전의 컨텍스트에 대한 자세한 내용은 여기를 참조하십시오 .


3

그리고 코 틀린에서 :

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

0

액티비티는 컨텍스트를 전문화 한 것이므로 컨텍스트가있는 경우 사용하려는 액티비티를 이미 알고 있으며 단순히 ac 로 캐스트 할 수 있습니다 . 여기서 a 는 활동이고 c 는 컨텍스트입니다.

Activity a = (Activity) c;

7
별도의 주석에서 언급했듯이 컨텍스트가 항상 활동이 아닐 수도 있으므로 위험합니다.

4
typecast only if (context instanceof Activity) {// 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;

    }

도움이 되길 바랍니다 .. 즐거운 코딩!


전달한 컨텍스트가 null이 아닌지 확인하십시오. 문제 일 가능성이 큽니다.
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.