programing

getApplication()을 컨텍스트로 사용하여 "창을 추가할 수 없음 - 응용 프로그램에 대한 토큰 null이 아닙니다"를 던지는 대화 상자

cafebook 2023. 7. 17. 21:25
반응형

getApplication()을 컨텍스트로 사용하여 "창을 추가할 수 없음 - 응용 프로그램에 대한 토큰 null이 아닙니다"를 던지는 대화 상자

내 활동에서 컨텍스트를 매개 변수로 사용하는 경보 대화 상자를 만들려고 합니다.다음을 사용하면 예상대로 작동합니다.

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

그러나 화면 회전과 같은 간단한 작업을 수행하는 동안에도 활동이 삭제 및 재생성될 때 메모리 누수의 가능성이 있으므로 "이"를 컨텍스트로 사용하는 것은 신중하지 않습니다.안드로이드 개발자 블로그의 관련 게시물에서:

컨텍스트 관련 메모리 누수를 방지하는 두 가지 쉬운 방법이 있습니다.가장 분명한 것은 자신의 범위 밖에서 맥락을 벗어나는 것을 피하는 것입니다.위의 예는 정적 참조의 경우를 보여주었지만 내부 클래스와 외부 클래스에 대한 암묵적 참조도 마찬가지로 위험할 수 있습니다.두 번째 해결책은 응용프로그램 컨텍스트를 사용하는 것입니다.이 컨텍스트는 응용프로그램이 활성화되어 있고 활동 수명 주기에 따라 달라지지 않는 한 유지됩니다.컨텍스트가 필요한 수명이 긴 개체를 유지할 계획이라면 애플리케이션 개체를 기억해야 합니다.Context.getApplicationContext() 또는 Activity.getApplication()을 호출하면 쉽게 얻을 수 있습니다.

하지만 그것을 위하여.AlertDialog()둘 다 아니다.getApplicationContext()또는getApplication()됩니다.는 다음과 .

"창을 추가할 수 없습니다. 응용 프로그램에 대한 토큰 null이 아닙니다."

참조: 1, 2, 3 등.

그래서, 우리가 공식적으로 사용하도록 조언을 받았기 때문에, 이것이 정말 "버그"로 여겨져야 합니까?Activity.getApplication()그런데도 광고대로 작동하지 않는 건가요?

짐.

에 에.getApplicationContext() 냥쓰기를 합니다.ActivityName.this.

용사를 합니다.this를 위해 나를위일않는만지았지하해,만지▁did않▁but았▁for,는,MyActivityName.this

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

매니페스트에 다음 권한을 추가합니다.

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

"AlertDialog()에 대해 getApplicationContext() 또는 getApplication()은 컨텍스트로 허용되지 않습니다. 예외가 발생합니다. '창을 추가할 수 없습니다. 토큰 null은 응용 프로그램에 해당되지 않습니다.'"

대화상자를 만들려면 응용프로그램 컨텍스트가 아닌 활동 컨텍스트 또는 서비스 컨텍스트가 필요합니다(getApplicationContext() 및 getApplication() 모두 응용프로그램 컨텍스트 반환).

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

활동 또는 서비스의 경우:

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

조으로각:AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());

메모리 누수는 "이" 참조에 내재된 문제가 아니며, 이는 개체 자체에 대한 참조(즉, 개체의 데이터를 저장하기 위해 실제 할당된 메모리에 대한 참조)입니다.이 문제는 할당된 메모리가 유효 수명을 초과한 후 GC(가비지 수집기)를 해제할 수 없는 할당된 메모리에서 발생합니다.

대부분의 경우 변수가 범위를 벗어나면 GC가 메모리를 회수합니다.그러나 "x"와 같은 변수가 보유한 개체에 대한 참조가 개체의 유효 수명을 초과한 후에도 지속될 때 메모리 누수가 발생할 수 있습니다.따라서 할당된 메모리는 "x"가 참조를 유지하는 동안 손실됩니다. GC는 해당 메모리가 계속 참조되는 동안 메모리를 확보하지 않기 때문입니다.할당된 메모리에 대한 일련의 참조로 인해 메모리 누수가 나타나지 않는 경우가 있습니다.이러한 경우 GC는 해당 메모리에 대한 모든 참조가 제거될 때까지 메모리를 확보하지 못합니다.

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

대화 상자는 "콘텍스트가 필요한 수명이 긴 개체"가 아니어야 합니다.그 문서는 혼란스럽습니다.기본적으로 다음과 같은 작업을 수행하면 됩니다.

static Dialog sDialog;

(정적 참고)

그리고 당신이 했던 어딘가의 활동에서.

 sDialog = new Dialog(this);

회전 또는 유사한 회전 중에 원래 활동이 유출되어 활동이 파괴될 수 있습니다. (Destroy에서 정리하지 않는 한 Dialog 개체를 정적으로 만들지 않을 수 있습니다.)

일부 데이터 구조의 경우 애플리케이션의 컨텍스트를 기반으로 정적으로 만드는 것이 타당하지만, 일반적으로 대화상자와 같은 UI 관련 작업에는 적합하지 않습니다.그래서 다음과 같은 것이 있습니다.

Dialog mDialog;

...

mDialog = new Dialog(this);

mDialog는 정적이지 않으므로 활동과 함께 해제되므로 활동이 유출되지 않아야 합니다.

활동에서는 다음을 사용합니다.

MyActivity.this

조각으로:

getActivity();

fragment에 표시된 사용자 지정 어댑터의 생성자를 통해 컨텍스트를 전송해야 했고 getApplicationContext()에 문제가 있었습니다.다음을 통해 해결 방법을 해결했습니다.

this.getActivity().getWindow().getContext()으로에.onCreate콜백

코틀린 버전 *****

은 격해야합다를 통과해야 .this@YourActivityapplicationContext또는baseContext

Activity대화 상자를 표시하는 버튼을 클릭하면

Dialog dialog = new Dialog(MyActivity.this);

나를 위해 일했습니다.

Little hack: GC를 통해 활동을 파괴하는 것을 방지할 수 있습니다(하면 안되지만 일부 상황에서는 도움이 될 수 있습니다).설정하는 것을 잊지 마십시오.contextForDialognull더 이상 필요하지 않을 때):

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

다음을 사용하면 됩니다.

JAVA 사용자용

액티비티를 사용하는 경우 --> AlertDialog.Builder builder = new AlertDialog.Builder(this);

OR

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

fragment를 사용하는 경우 --> AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());

KOTLIN 사용자용

액티비티를 사용하는 경우 --> val builder = AlertDialog.Builder(this)

OR

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

fragment를 사용하는 경우 --> val builder = AlertDialog.Builder(activity!!)

조각을 사용하고 AlertDialog/Toost 메시지를 사용하는 경우 컨텍스트 매개 변수에 getActivity()를 사용합니다.

이것처럼.

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

추가

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

그리고.

"android.permission.SYSTEM_ALERT_WINDOW"/>

이제는 제게 효과가 있어요.심지어 애플리케이션을 닫았다가 열었는데 그때 오류가 발생했습니다.

사용하고 있었습니다.ProgressDialog단편적으로 그리고 통과할 때 이 오류를 받고 있었습니다.getActivity().getApplicationContext()생성자 매개 변수로 사용할 수 있습니다.으로 변경getActivity().getBaseContext()역시 효과가 없었습니다.

제게 효과가 있었던 해결책은getActivity()예를 들면

progressDialog = new ProgressDialog(getActivity());

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

활동 범위 밖에 있는 경우, "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);

하고 fragment를 에는 fragment를 합니다.AlertDialog / Toast 메지, 용사 사용getActivity()컨텍스트 매개 변수에 있습니다.

나를 위해 일했습니다.

건배!

대화 상자 아래에 있을 활동의 컨텍스트를 사용해 보십시오.하지만 "이" 키워드를 사용할 때는 항상 작동하지 않기 때문에 주의해야 합니다.

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

저는 어떤 문서에서도 이 정보를 찾지 못했지만 시도했습니다.이것은 확실한 배경이 없는 저의 해결책입니다. 더 잘 알고 있는 사람이 있다면 언제든지 의견을 말씀해 주십시오.

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

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

ㅠㅠgetParent()새로운 것처럼 맥락이 있는 논쟁의 장소에서.AlertDialog.Builder(getParent());효과가 있기를 바랍니다. 저에게 효과가 있었습니다.

내 경우 작업:

this.getContext();

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

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

메인 UI 스레드가 아닌 스레드에서 대화상자를 보여주려고 하는 경우에도 발생할 수 있다고 생각합니다.

사용하다runOnUiThread()그런 경우에는

API를 확인한 후 대화상자에 자신의 활동을 전달하거나 fragment에 있을 경우 getActivity를 전달한 후 return 메서드에서 dialog.dismiss()로 강제로 정리하여 누수를 방지할 수 있습니다.

제가 아는 곳에는 명시적으로 명시되어 있지 않지만, OnClickHandlers에서 이 작업을 수행하기 위해 대화 상자를 다시 전달한 것 같습니다.

어댑터에서 Dialog(대화 상자)

활동을 어댑터 생성자에게 전달:

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

어댑터에서 수신:

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

이제 Builder에서 사용할 수 있습니다.

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

여러분, 저는 간단한 치트 시트를 가지고 있습니다. 파일을 만들고 아무 이름이나 주면 이 코드를 쓰세요.

fun Context.alertdialog(context: Context, msg: String, icon: Drawable, title:String){
    val alertDialog = AlertDialog.Builder(context)
    alertDialog.setIcon(icon)
        .setTitle(title)
        .setMessage(msg)
    alertDialog.show()
}

이제 경고 대화 상자를 표시해야 할 때는 어디서나 이 방법을 사용합니다.

requireActivity().alertdialog(requireContext(), resources.getString(R.string.pass_title),
                resources.getDrawable(R.drawable.pass_ic_name), "title")

코틀린에게 행운이 있기를.

제게 효과가 있었던 것은 문맥 대신 활동을 통과하는 것이었습니다.

대화 상자에 대한 사용자 지정 레이아웃을 원했지만 코드를 별도로 유지하기 위해 별도의 클래스에 작성했습니다. 그렇지 않으면 대화 상자를 사용할 모든 작업에 코드를 복사하여 붙여넣어야 합니다.

솔루션은 제 상황을 설명하지만 핵심 솔루션은 다음과 같습니다.

  1. View Adapter를 사용하면서 Activity(context ex. ->[kotlin] 활동이 아닌)로 어댑터를 초기화했습니다.활동)을 매개변수로 -> ex.[kotlin] this@주요 활동
  2. 그런 다음 해당 매개 변수를 Viewholder에 전달했습니다.
  3. 그런 다음 클래스에 다시 전달하여 대화 상자를 팽창시킵니다.

활동[선택적 이름] 사용:확장할 대화 상자가 표시될 때까지 활동[필수 유형]

그것은 많은 것을 전달하지만, 같은 코드를 복사하고 모든 곳에 붙여넣는 것보다 더 말이 됩니다.

다음은 응용 프로그램에 대해 동일한 오류를 해결한 방법입니다.
상자를 후 행: " " " " "

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

컨텍스트를 획득할 필요가 없습니다.이 기능은 다른 대화 상자를 현재 팝업 대화 상자에서 팝업할 경우 특히 유용합니다.또는 맥락을 파악하기가 불편할 때도 있습니다.

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

데이빗

언급URL : https://stackoverflow.com/questions/5796611/dialog-throwing-unable-to-add-window-token-null-is-not-for-an-application-wi

반응형