컨텍스트로 getApplication ()을 사용하여 "창을 추가 할 수 없음-토큰 널이 애플리케이션에 해당되지 않음"을 표시하는 대화 상자


665

내 활동은 컨텍스트를 매개 변수로 필요로하는 AlertDialog를 만들려고합니다. 내가 사용하면 예상대로 작동합니다.

AlertDialog.Builder builder = new AlertDialog.Builder(this);

그러나 화면 회전과 같은 간단한 작업 중에도 액티비티가 파괴되고 다시 생성 될 때 메모리 누수 가능성으로 인해 "this"를 컨텍스트로 사용하는 것은 부적절합니다. A로부터 안드로이드 개발자 블로그에 관련 포스트 :

컨텍스트 관련 메모리 누수를 피하는 두 가지 쉬운 방법이 있습니다. 가장 분명한 것은 컨텍스트가 자신의 범위를 벗어나는 것을 피하는 것입니다. 위의 예는 정적 참조의 경우를 보여 주지만 내부 클래스와 외부 클래스에 대한 암시 적 참조는 똑같이 위험 할 수 있습니다. 두 번째 해결책은 응용 프로그램 컨텍스트를 사용하는 것입니다. 이 컨텍스트는 애플리케이션이 활성 상태이고 활동 수명주기에 의존하지 않는 한 지속됩니다. 컨텍스트가 필요한 오래 지속되는 오브젝트를 유지하려는 경우 애플리케이션 오브젝트를 기억하십시오. Context.getApplicationContext () 또는 Activity.getApplication ()을 호출하여 쉽게 얻을 수 있습니다.

그러나 예외를 던지기 때문에 컨텍스트로 허용 AlertDialog()되지 않는 getApplicationContext()또는 getApplication()허용되는 경우 :

"창을 추가 할 수 없음-토큰 널이 응용 프로그램 용이 아닙니다"

참조 당 : 1 , 2 , 3

따라서 공식적으로 사용하는 것이 좋지만 Activity.getApplication()광고 된대로 작동하지 않기 때문에 이것이 실제로 "버그"로 간주되어야 합니까?


R.Guy가 getApplication을 사용하여 조언하는 첫 번째 항목에 대한 참조 : android-developers.blogspot.com/2009/01/…
gymshoe




답변:


1354

대신을 getApplicationContext()사용하십시오 ActivityName.this.


67
큰! 그것에 대해 언급하기 만하면됩니다. 예를 들어 자체적으로 'this'를 가진 리스너의 구현 된 메소드 내에서 액세스하기 위해 "this"를 전역 적으로 저장해야 할 수도 있습니다. 이 경우 전역 적으로 "컨텍스트 컨텍스트"를 정의한 다음 onCreate에서 "context = this"를 설정 한 다음 "context"를 참조하십시오. 그것이 도움이되기를 바랍니다.
Steven L

8
실제로, Listener수업은 종종 익명 으로 진행되기 때문에, 나는 그냥하는 경향이 final Context ctx = this;있고 멀리 있습니다;)
Alex

28
@StevenL 무슨 말을하기 위해서는 ExternalClassName.this를 사용하여 외부 클래스의 "this"를 명시 적으로 참조해야합니다.
Artem Russakovskii

11
대화 상자가 콜백에 사용되고 콜백이 호출되기 전에 활동을 종료하면 "this"를 사용하지 않습니까? 적어도 그것이 안드로이드가 logcat에서 불평하는 것 같습니다.
Artem Russakovskii

6
onDestroy-Artem의 정적 참조를 지우는 것을 기억하지 않으면 해당 활동의 메모리를 쉽게 누출 할 수 있으므로 @StevenLs 접근 방식을 권장하지 않습니다. StevenL의 접근 방식은 Java 작동 방식에 대한 이해 부족으로 인해 발생합니다
Dori

192

사용 this은 나에게 효과가 없었지만 MyActivityName.this그랬습니다. 이것이 this일 을 할 수없는 사람에게 도움이되기를 바랍니다 .


63
그것은 당신 this이 내부 클래스 내부에서 사용할 때 일어나는 일 입니다. 외부 클래스의 인스턴스를 참조하려면와 같이 지정해야합니다 OuterClass.this. 그냥 사용하면 this항상 가장 내부 클래스의 인스턴스를 참조합니다.
kaka

60

을 계속 사용할 수 getApplicationContext()있지만 사용하기 전에이 플래그를 추가해야합니다 dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT). 오류가 표시되지 않습니다.

매니페스트에 다음 권한을 추가하십시오.

<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />

1
창 android.view.ViewRootImpl$W@426ce670을 추가 할 수 없습니다.이 창 유형에 대한 권한이 거부되었습니다.
Ram G.

권한 추가 : <uses-permission android : name = "android.permission.SYSTEM_ALERT_WINDOW"/>
codezjx


1
API 23 이상에서 사용할 수 있지만 startActivityForResult (new Intent (Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse ( "package :"+ getPackageName ()))), OVERLAY_PERMISSION_REQ_CODE); 그러나, 당신은 여부를 해야 사용이 또 다른 문제는 ...이다
벤 닐

2
진행중인 대화 내부 서비스를 보여주는 때 유용합니다
아난드 Savjani

37

"... AlertDialog ()에 대해 getApplicationContext () 또는 getApplication ()을 컨텍스트로 사용할 수 없다고 말했을 때 문제를 올바르게 식별했습니다. '창을 추가 할 수 없습니다.-토큰 null은 지원서'"

대화 상자를 작성하려면 애플리케이션 컨텍스트가 아닌 활동 컨텍스트 또는 서비스 컨텍스트 가 필요합니다 (getApplicationContext () 및 getApplication () 모두 애플리케이션 컨텍스트를 리턴 함).

활동 컨텍스트 를 얻는 방법은 다음과 같습니다 .

(1) 활동 또는 서비스에서 :

AlertDialog.Builder builder = new AlertDialog.Builder(this);

(2) 조각에서 : AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());

메모리 누수는 "this"참조에 내재 된 문제가 아니며, 이는 객체 자체에 대한 참조입니다 (즉, 객체 데이터를 저장하기 위해 실제로 할당 된 메모리에 대한 참조). 그것은 일어나는 모든 가비지 콜렉터 (GC)가 할당 된 메모리가 유용한 수명을 지났다 후 확보 할 수없는있는 할당 된 메모리.

대부분의 경우 변수가 범위를 벗어나면 GC가 메모리를 회수합니다. 그러나 변수가 보유한 개체 (예 : "x")에 대한 참조가 개체의 유효 수명보다 오래 지속 된 후에도 메모리 누수가 발생할 수 있습니다. 따라서 "x"가 참조를 보유하는 한 할당 된 메모리는 손실됩니다. GC 해당 메모리가 여전히 참조되는 동안 메모리를 해제 하지 않기 때문 입니다. 할당 된 메모리 에 대한 참조 체인으로 인해 메모리 누수가 명확하지 않은 경우가 있습니다. 이 경우 GC는 해당 메모리에 대한 모든 참조가 제거 될 때까지 메모리를 비우지 않습니다.

메모리 누수를 방지하려면 할당 된 메모리가 "this"(또는 다른 참조)에 의해 무한정 참조되도록하는 논리적 오류가 있는지 코드를 확인하십시오. 체인 참조도 확인하십시오. 다음은 메모리 사용을 분석하고 성가신 메모리 누수를 찾는 데 도움이되는 몇 가지 도구입니다.


액티비티를 들어 당신은 또한 사용할 수 있습니다 ActivityName.this ActivityName는 (분명히) (예를 들어, MainActivity에 대한) 활동의 이름입니다
루이스 카브레라 베니토

34

대화 상자는 "컨텍스트가 필요한 오래 지속되는 개체"가되어서는 안됩니다. 문서가 혼란 스럽다. 기본적으로 다음과 같은 작업을 수행하는 경우 :

static Dialog sDialog;

( 정적 참고 )

그런 다음 어딘가 활동에서

 sDialog = new Dialog(this);

회전 또는 이와 유사한 작업을 수행하는 동안 원래 활동이 유출되어 활동이 중단 될 수 있습니다. (onDestroy에서 정리하지 않는 한 Dialog 객체를 정적으로 만들지 않을 것입니다)

일부 데이터 구조의 경우 정적 및 애플리케이션의 컨텍스트를 기반으로하는 것이 바람직하지만 일반적으로 대화 상자와 같은 UI 관련 항목에는 적합하지 않습니다. 그래서 이런 식으로 :

Dialog mDialog;

...

mDialog = new Dialog(this);

mDialog가 정적이 아니기 때문에 활동과 함께 해제되므로 활동이 누출되지 않아야합니다.


나는 asynctask에서 그것을 부르고있다, 이것은 나를 위해 일했다 thx 메이트
MemLeak

정적 선언을 제거한 후에는 대화가 정적이었습니다.
Ceddy Muhoza

25

프래그먼트에 표시된 사용자 정의 어댑터의 생성자를 통해 컨텍스트를 보내야했으며 getApplicationContext ()와 관련 하여이 문제가 발생했습니다. 나는 그것을 해결했다 :

this.getActivity().getWindow().getContext()조각의 onCreate콜백에서.


4
이것은 나에게도 효과가 있었고, 사용중인 외부 AsyncTask의 생성자에게 전달했습니다 (진행 대화 상자를 보여줍니다).
Rohan Kandwal

3
이것은 더 복잡한 작업에 대한 실제 답변입니다 :)
teejay December

1
@teejay에 동의합니다
Erdi İzgi


20

에서 Activity의 대화 상자를 표시 버튼의 클릭

Dialog dialog = new Dialog(MyActivity.this);

나를 위해 일했다.


19

***** 코 틀린 버전 *****

또는 this@YourActivity대신에 전달해야합니다applicationContextbaseContext


18

작은 해킹 : GC에 의해 활동이 중단되는 것을 막을 수 있습니다 (하지 말아야하지만 상황에 따라 도움이 될 수 있습니다. 더 이상 필요하지 않은 경우 로 설정 contextForDialog하는 것을 잊지 마십시오 null).

public class PostActivity extends Activity  {
    ...
    private Context contextForDialog = null;
    ...
    public void onCreate(Bundle savedInstanceState) {
        ...
        contextForDialog = this;
    }
    ...
    private void showAnimatedDialog() {
        mSpinner = new Dialog(contextForDialog);
        mSpinner.setContentView(new MySpinner(contextForDialog));
        mSpinner.show();
    }
    ...
}

@MurtuzaKabul이 기능은 == PostActivity에서 상속되는 Activity-> Context에서 상속하므로 대화를 전달하면 컨텍스트를 실제로 전달하는 것입니다
Elad Gelman

13

프래그먼트를 사용하고 AlertDialog / Toast 메시지를 사용하는 경우 컨텍스트 매개 변수에 getActivity ()를 사용하십시오.

이처럼

ProgressDialog pdialog;
pdialog = new ProgressDialog(getActivity());
pdialog.setCancelable(true);
pdialog.setMessage("Loading ....");
pdialog.show();

12

다음을 사용하십시오.

자바 사용자

활동을 사용하는 경우-> AlertDialog.Builder builder = new AlertDialog.Builder(this);

또는

AlertDialog.Builder builder = new AlertDialog.Builder(your_activity.this);

조각을 사용하는 경우-> AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());

코 틀린 사용자를위한

활동을 사용하는 경우-> val builder = AlertDialog.Builder(this)

또는

val builder = AlertDialog.Builder(this@your_activity.this)

조각을 사용하는 경우-> val builder = AlertDialog.Builder(activity!!)


9

첨가

dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);

"android.permission.SYSTEM_ALERT_WINDOW"/> 명백하게

그것은 지금 나를 위해 작동합니다. 응용 프로그램을 닫고 연 후에도 오류가 발생했습니다.


9

ProgressDialog조각에서 사용 getActivity().getApplicationContext()하고 생성자 매개 변수로 전달하면이 오류가 발생했습니다 . 로 변경해도 getActivity().getBaseContext()작동하지 않았습니다.

나를 위해 일한 해결책은 통과하는 것이 었습니다 getActivity(). 즉

progressDialog = new ProgressDialog(getActivity());


6

사용하다 MyDialog md = new MyDialog(MyActivity.this.getParent());


6

활동 외부에있는 경우 "NameOfMyActivity.this"함수에서 활동 활동으로 사용해야합니다 (예 :

public static void showDialog(Activity activity) {
        AlertDialog.Builder builder = new AlertDialog.Builder(activity);
        builder.setMessage("Your Message")
        .setPositiveButton("Yes", dialogClickListener)
        .setNegativeButton("No", dialogClickListener).show();
}


//Outside your Activity
showDialog(NameOfMyActivity.this);

5

조각을 사용하고 AlertDialog / Toast메시지를 사용 getActivity()하는 경우 context 매개 변수에서 사용 하십시오.

나를 위해 일했다.

건배!


5

대화 상자 아래에있는 활동의 컨텍스트를 사용하십시오. 그러나 "this"키워드를 사용할 때는 항상 작동하지 않으므로주의하십시오.

예를 들어, 두 개의 탭이있는 호스트로 TabActivity가 있고 각 탭이 다른 활동이고 탭 (활동) 중 하나에서 대화 상자를 작성하려고 시도하고 "this"를 사용하면 예외가 발생합니다. 사례 대화 상자는 모든 것을 호스트하고 볼 수있는 호스트 활동에 연결되어야합니다. (가장 눈에 띄는 부모 활동의 맥락을 말할 수 있습니다)

나는 어떤 문서 에서도이 정보를 찾지 못했지만 시도했습니다. 이것은 더 강력한 지식이없는 나의 해결책입니다.


4

미래의 독자들에게는 다음과 같은 도움이 될 것입니다.

public void show() {
    if(mContext instanceof Activity) {
        Activity activity = (Activity) mContext;
        if (!activity.isFinishing() && !activity.isDestroyed()) {
            dialog.show();
        }
    }
}

2

내 경우에는 일하십시오 :

this.getContext();

2

또는 다음과 같이 대화 상자를 만들 수도 있습니다.

final Dialog dialog = new Dialog(new ContextThemeWrapper(
            this, R.style.MyThemeDialog));

2

기본 UI 스레드가 아닌 스레드에서 대화 상자를 표시하려고하면이 문제가 발생할 수 있다고 생각합니다.

runOnUiThread()이 경우에 사용하십시오 .


2

getParent()새로운 AlertDialog.Builder(getParent());희망 과 같은 맥락의 논쟁 장소에서 시도해보십시오 .


1

API를 살펴본 후 조각에있는 경우 대화 상자에 활동 또는 getActivity를 전달한 다음 리턴 메소드에서 dialog.dismiss ()를 사용하여 강제로 정리하여 누출을 방지 할 수 있습니다.

내가 아는 곳에서는 명시 적으로 언급되어 있지 않지만 OnClickHandlers의 대화 상자가 다시 전달되는 것처럼 보입니다.


0

대화 상자가 어댑터에서 작성중인 경우 :

활동을 어댑터 생성자에 전달하십시오.

adapter = new MyAdapter(getActivity(),data);

어댑터 수신 :

 public MyAdapter(Activity activity, List<Data> dataList){
       this.activity = activity;
    }

이제 빌더에서 사용할 수 있습니다

            AlertDialog.Builder alert = new AlertDialog.Builder(activity);

-1

내 응용 프로그램에 대해 동일한 오류를 해결하는 방법
은 다음과 같습니다. 대화 상자를 만든 후 다음 줄을 추가하십시오.

dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG);  

컨텍스트를 얻을 필요는 없습니다. 이것은 현재 팝업 대화 상자 위에 다른 대화 상자를 팝업하는 경우 특히 유용합니다. 또는 상황에 맞는 것이 불편할 때.

이것이 앱 개발에 도움이되기를 바랍니다.

데이비드


-1
android.support.v7.app.AlertDialog.Builder builder = new android.support.v7.app.AlertDialog.Builder(getWindow().getDecorView().getRootView().getContext());

builder.setTitle("Confirm");
builder.setMessage("Are you sure you want delete your old account?");

builder.setPositiveButton("YES", new DialogInterface.OnClickListener() {

    public void onClick(DialogInterface dialog, int which) {
        //Do nothing but close the dialog



        dialog.dismiss();

    }
});

builder.setNegativeButton("NO", new DialogInterface.OnClickListener() {

    @Override
    public void onClick(DialogInterface dialog, int which) {

        //Do nothing
        dialog.dismiss();
    }
});

android.support.v7.app.AlertDialog alert = builder.create();
alert.show();
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.