창 관리자 충돌에 첨부되지 않은 보기
저는 ACRA를 사용하여 앱 충돌을 보고하고 있습니다. 있었습니다.View not attached to window manager
줄.pDialog.dismiss();
if에서:
if (pDialog!=null)
{
if (pDialog.isShowing())
{
pDialog.dismiss();
}
}
은 의 .View not attached to window manager
제가 받은 충돌 사고는 있지만, 아직 사고가 나고 있는데 어떻게 해결해야 할지 잘 모르겠습니다.
오류 메시지:
java.lang.IllegalArgumentException: View not attached to window manager
at android.view.WindowManagerGlobal.findViewLocked(WindowManagerGlobal.java:425)
at android.view.WindowManagerGlobal.removeView(WindowManagerGlobal.java:327)
at android.view.WindowManagerImpl.removeView(WindowManagerImpl.java:83)
at android.app.Dialog.dismissDialog(Dialog.java:330)
at android.app.Dialog.dismiss(Dialog.java:312)
at com.package.class$LoadAllProducts.onPostExecute(class.java:624)
at com.package.class$LoadAllProducts.onPostExecute(class.java:1)
at android.os.AsyncTask.finish(AsyncTask.java:631)
at android.os.AsyncTask.access$600(AsyncTask.java:177)
at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:644)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:176)
at android.app.ActivityThread.main(ActivityThread.java:5419)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:525)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1046)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:862)
at dalvik.system.NativeStart.main(Native Method)
코드 조각:
class LoadAllProducts extends AsyncTask<String, String, String>
{
/**
* Before starting background thread Show Progress Dialog
* */
@Override
protected void onPreExecute()
{
super.onPreExecute();
pDialog = new ProgressDialog(CLASS.this);
pDialog.setMessage("Loading. Please wait...");
pDialog.setIndeterminate(false);
pDialog.setCancelable(false);
pDialog.show();
}
/**
* getting All products from url
* */
protected String doInBackground(String... args)
{
// Building Parameters
doMoreStuff("internet");
return null;
}
/**
* After completing background task Dismiss the progress dialog
* **/
protected void onPostExecute(String file_url)
{
// dismiss the dialog after getting all products
if (pDialog!=null)
{
if (pDialog.isShowing())
{
pDialog.dismiss(); //This is line 624!
}
}
something(note);
}
}
매니페스트:
<activity
android:name="pagename.CLASS"
android:configChanges="keyboard|keyboardHidden|orientation|screenSize|screenLayout"
android:label="@string/name" >
</activity>
이 사고가 일어나지 않게 하려면 제가 무엇을 놓치나요?
버그를 재현하는 방법
- 단말기에서 다음 옵션을 사용하도록 설정합니다.
Settings -> Developer Options -> Don't keep Activities
. AsyncTask
이며,ProgressDialog
상영 중입니다.
Android OS는 활동을 숨기자마자 이를 파괴합니다..onPostExecute
다이라고 .Activity
"finishing" 상태에 있을 것이고ProgressDialog
.Activity
.
수정 방법:
- 합니다에서 합니다.
onPostExecute
방법. - 합니다를 합니다.
ProgressDialog
인에onDestroy
방법.그렇지않으면,android.view.WindowLeaked
예외는 삭제됩니다.이 예외는 일반적으로 활동이 완료될 때에도 여전히 활성화된 대화상자에서 발생합니다.
다음 고정 코드를 사용해 보십시오.
public class YourActivity extends Activity {
private void showProgressDialog() {
if (pDialog == null) {
pDialog = new ProgressDialog(StartActivity.this);
pDialog.setMessage("Loading. Please wait...");
pDialog.setIndeterminate(false);
pDialog.setCancelable(false);
}
pDialog.show();
}
private void dismissProgressDialog() {
if (pDialog != null && pDialog.isShowing()) {
pDialog.dismiss();
}
}
@Override
protected void onDestroy() {
dismissProgressDialog();
super.onDestroy();
}
class LoadAllProducts extends AsyncTask<String, String, String> {
// Before starting background thread Show Progress Dialog
@Override
protected void onPreExecute() {
showProgressDialog();
}
//getting All products from url
protected String doInBackground(String... args) {
doMoreStuff("internet");
return null;
}
// After completing background task Dismiss the progress dialog
protected void onPostExecute(String file_url) {
if (YourActivity.this.isDestroyed()) { // or call isFinishing() if min sdk version < 17
return;
}
dismissProgressDialog();
something(note);
}
}
}
가 될 수 Activity
가본 적 있다finished
아니면progress of finishing
.
isFinishing
합니다.false
if (!YourActivity.this.isFinishing() && pDialog != null) {
pDialog.dismiss();
}
is Finishing : 합니다에 활동이 합니다. 전화를 거셨기 때문에.finish
다른 사람이 완료를 요청했습니다.
위해서Dialog
Fragment
합니다
ProgressDialog myDialog = new ProgressDialog(getActivity());
myDialog.setOwnerActivity(getActivity());
...
Activity activity = myDialog.getOwnerActivity();
if( activity!=null && !activity.isFinishing()) {
myDialog.dismiss();
}
는 이 하여 합니다 시합니다.Fragment
다에서 될 수 .Activity
.
Code가 어떻게 작동하는지 여기에서 확인하십시오.
비동기 작업을 호출한 후 비동기 작업이 백그라운드에서 실행됩니다.그것이 바람직합니다.이제 이 비동기 작업에는 Activity(활동)에 첨부된 진행 대화상자가 있습니다. 코드를 보는 방법을 묻는다면 다음과 같습니다.
pDialog = new ProgressDialog(CLASS.this);
은 하고 있습니다.Class.this
논쟁의 맥락으로서 ) 대화 는 여전히 .따라서 Progress(진행률) 대화 상자가 여전히 활동에 연결되어 있습니다.
이제 시나리오를 생각해 보겠습니다.), 즉다 Finish()이 됩니다.progress bar
더 이상 활동이 없을 때 말입니다.
따라서 다음을 얻을 수 있습니다.
java.lang.IllegalArgumentException: View not attached to the window manager
이에 대한 해결책:
1) 활동이 완료되기 전에 대화상자가 삭제되거나 취소되었는지 확인합니다.
2) 대화상자가 종료된 후에만 활동을 종료합니다. 즉, 비동기 작업이 종료됩니다.
@erakitin answer 기준이지만 Android 버전 < API level 17에도 호환됩니다.안타깝게도 Activity.isDestroyed()는 API 레벨 17부터만 지원되므로 저와 같은 오래된 API 레벨을 대상으로 한다면 직접 확인해야 할 것입니다.아직 못 구했어요.View not attached to window manager
그 후에는 예외입니다.
예제코드
public class MainActivity extends Activity {
private TestAsyncTask mAsyncTask;
private ProgressDialog mProgressDialog;
private boolean mIsDestroyed;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (condition) {
mAsyncTask = new TestAsyncTask();
mAsyncTask.execute();
}
}
@Override
protected void onResume() {
super.onResume();
if (mAsyncTask != null && mAsyncTask.getStatus() != AsyncTask.Status.FINISHED) {
Toast.makeText(this, "Still loading", Toast.LENGTH_LONG).show();
return;
}
}
@Override
protected void onDestroy() {
super.onDestroy();
mIsDestroyed = true;
if (mProgressDialog != null && mProgressDialog.isShowing()) {
mProgressDialog.dismiss();
}
}
public class TestAsyncTask extends AsyncTask<Void, Void, AsyncResult> {
@Override
protected void onPreExecute() {
super.onPreExecute();
mProgressDialog = ProgressDialog.show(MainActivity.this, "Please wait", "doing stuff..");
}
@Override
protected AsyncResult doInBackground(Void... arg0) {
// Do long running background stuff
return null;
}
@Override
protected void onPostExecute(AsyncResult result) {
// Use MainActivity.this.isDestroyed() when targeting API level 17 or higher
if (mIsDestroyed)// Activity not there anymore
return;
mProgressDialog.dismiss();
// Handle rest onPostExecute
}
}
}
@Override
public void onPause() {
super.onPause();
if(pDialog != null)
pDialog .dismiss();
pDialog = null;
}
이것을 참고하세요.
ConfigurationChanged에서 재정의하고 진행률 대화 상자를 취소합니다.진행률 대화상자가 세로로 작성되고 가로로 삭제되면 View not attached to window manager 오류가 발생합니다.
또한 진행 표시줄을 중지하고 일시 중지(), BackPressed 및 destroy 메서드에서 비동기 작업을 중지합니다.
if(asyncTaskObj !=null && asyncTaskObj.getStatus().equals(AsyncTask.Status.RUNNING)){
asyncTaskObj.cancel(true);
}
활동 파기 및 대화 상자 해제를 재정의하고 null로 만듭니다.
protected void onDestroy ()
{
if(mProgressDialog != null)
if(mProgressDialog.isShowing())
mProgressDialog.dismiss();
mProgressDialog= null;
}
dismiss()
방법은 다음과 같습니다.
@Override
public void dismiss() {
Window window = getWindow();
if (window == null) {
return;
}
View decor = window.getDecorView();
if (decor != null && decor.getParent() != null) {
super.dismiss();
}
}
문제를 재생하려면 해제 대화 상자를 열기 전에 작업을 마치기만 하면 됩니다.
먼저 충돌 이유는 decoView의 인덱스는 -1이고, 안드로이드 소스 코드를 통해 알 수 있으며, 코드 스니펫이 있습니다.
class:android.view.WindowsManagerGlobal
파일:WindowManagerGlobal.java
private int findViewLocked(View view, boolean required) {
final int index = mViews.indexOf(view);
//here, view is decorView,comment by OF
if (required && index < 0) {
throw new IllegalArgumentException("View=" + view + " not attached to window manager");
}
return index;
}
따라서 우리는 해결책을 따르고 decView의 인덱스를 판단하여 0을 초과하는 경우 계속 진행하거나 복귀하여 종료를 포기하고 다음과 같이 코드화합니다.
try {
Class<?> windowMgrGloable = Class.forName("android.view.WindowManagerGlobal");
try {
Method mtdGetIntance = windowMgrGloable.getDeclaredMethod("getInstance");
mtdGetIntance.setAccessible(true);
try {
Object windownGlobal = mtdGetIntance.invoke(null,null);
try {
Field mViewField = windowMgrGloable.getDeclaredField("mViews");
mViewField.setAccessible(true);
ArrayList<View> mViews = (ArrayList<View>) mViewField.get(windownGlobal);
int decorViewIndex = mViews.indexOf(pd.getWindow().getDecorView());
Log.i(TAG,"check index:"+decorViewIndex);
if (decorViewIndex < 0) {
return;
}
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
if (pd.isShowing()) {
pd.dismiss();
}
이 문제는 해제 기능이 호출되기 전에 작업이 완료되기 때문입니다.예외를 처리하고 정확한 이유가 무엇인지 ADB 로그를 확인합니다.
/**
* After completing background task Dismiss the progress dialog
* **/
protected void onPostExecute(String file_url) {
try {
if (pDialog!=null) {
pDialog.dismiss(); //This is line 624!
}
} catch (Exception e) {
// do nothing
}
something(note);
}
이 예외를 재현할 방법이 있습니다.
2개 사용합니다.AsyncTask
긴 하나는 긴 일을 하고 다른 하나는 짧은 일을 합니다.합니다를 합니다.finish()
하면 .Dialog.dismiss()
요,
제 샘플 코드는 다음과 같습니다.
public class MainActivity extends Activity {
private static final String TAG = "MainActivity";
private ProgressDialog mProgressDialog;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.d(TAG, "onCreate");
new AsyncTask<Void, Void, Void>(){
@Override
protected void onPreExecute() {
mProgressDialog = ProgressDialog.show(MainActivity.this, "", "plz wait...", true);
}
@Override
protected Void doInBackground(Void... nothing) {
try {
Log.d(TAG, "long thread doInBackground");
Thread.sleep(20000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return null;
}
@Override
protected void onPostExecute(Void result) {
Log.d(TAG, "long thread onPostExecute");
if (mProgressDialog != null && mProgressDialog.isShowing()) {
mProgressDialog.dismiss();
mProgressDialog = null;
}
Log.d(TAG, "long thread onPostExecute call dismiss");
}
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
new AsyncTask<Void, Void, Void>(){
@Override
protected Void doInBackground(Void... params) {
try {
Log.d(TAG, "short thread doInBackground");
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return null;
}
@Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
Log.d(TAG, "short thread onPostExecute");
finish();
Log.d(TAG, "short thread onPostExecute call finish");
}
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
@Override
protected void onDestroy() {
super.onDestroy();
Log.d(TAG, "onDestroy");
}
}
이 문제를 해결하는 가장 좋은 방법이 무엇인지 확인할 수 있습니다.제 연구에 의하면, 적어도 네 가지 해결 방법이 있습니다.
- @erakitin 의: Call @erakitin
isFinishing()
- @Kapé의 답: 활동 상태를 확인할 수 있는 플래그 설정
- Try/Catch를 사용하여 처리합니다.
- .
AsyncTask.cancel(false)
인에onDestroy()
.을(를) 비동기 작업을 할 수 .onPostExecute()
행을 합니다.onCancelled()
대신.
고:onPostExecute()
AsyncTask.cancel(false)
안드로이드 2.X.X와 같은 오래된 Android OS에서.
당신은 당신에게 가장 적합한 것을 선택할 수 있습니다.
최선의 해결책.인지 또는 하고 활동이 만 확인한 합니다.dialog.show()
아니면dialog.dismiss();
아래 샘플 코드 참조...도움이 되기를 바랍니다!
디스플레이 대화상자
if (context instanceof Activity) {
if (!((Activity) context).isFinishing())
dialog.show();
}
취소 대화상자
if (context instanceof Activity) {
if (!((Activity) context).isFinishing())
dialog.dismiss();
}
항목을 하려면 합니다를 합니다.dialog.isShowing()
아니면dialog !-null
&&
조건.
는 또한 했습니다에 했습니다.onPause
ronDestroy
d
@Override
protected void onPause() {
super.onPause();
dialog.dismiss();
}
@Override
protected void onDestroy() {
super.onDestroy();
dialog.dismiss();
}
pDialog를 전역적으로 초기화한 다음 pDialog를 제거하고 로컬에서 보기 또는 대화 상자를 초기화할 수 있습니다.저도 같은 문제가 있어요, 제가 이 일을 했고 제 문제는 해결되었습니다.당신에게 효과가 있기를 바랍니다.
이 솔루션을 확인하거나 아래 솔루션을 사용해 볼 수 있습니다.
if (pDialog instanceof Activity && !((Activity) mContext).isFinishing())
pDialog.show();
소유자 활동이 아직 활성화되어 있는지 확인합니다.
if (dialog.getOwnerActivity() ==null || dialog.getOwnerActivity().isFinishing()) {
dialog.dismiss();
}
저는 이 간단한 확장 기능을 사용하여 활동이 파괴되는지 여부를 확인하고 있습니다.
protected fun Activity?.isNoMore(): Boolean {
return this?.let {
isFinishing || isDestroyed
} ?: true
}
아래에 언급된 것처럼 활동에 사용합니다.
if (!isNoMore()) {
//show your dialog. Also, make the null check for dialog object.
}
제안된 솔루션 중 어떤 것도 사용자 지정 Dialog 클래스를 사용하고 있고 모든 활동에서 중지/파괴 방법을 무시하고 싶지 않기 때문에 클래스에 매개 변수를 하나 더 추가하여 인스턴스에서 전송하는 것이 더 쉽습니다. 이 솔루션은 저에게 적합합니다.
class CustomLoadingClass(var activity: Activity?, var lifecycle: Lifecycle? = null) {
lateinit var dialog: Dialog
fun show(cancelable: Boolean = false, title: String? = null) {
lifecycle?.let {
val defaultLifecycleObserver = object : DefaultLifecycleObserver {
override fun onCreate(owner: LifecycleOwner) {
super.onCreate(owner)
activity?.let { it ->
if (!it.isFinishing && !it.isDestroyed) {
dialog = Dialog(it, android.R.style.Theme_Translucent_NoTitleBar)
dialog.setContentView(it.layoutInflater.inflate(R.layout.full_screen_progress_bar,null)!!)
dialog.setCancelable(cancelable)
dialog.show()
}
}
}
override fun onPause(owner: LifecycleOwner) {
super.onPause(owner)
dismiss()
}
override fun onStop(owner: LifecycleOwner) {
super.onStop(owner)
dismiss()
}
override fun onDestroy(owner: LifecycleOwner) {
super.onDestroy(owner)
dismiss()
}
}
it.addObserver(defaultLifecycleObserver)
}
}
fun dismiss() {
activity?.let { it ->
if (!it.isFinishing && !it.isDestroyed)
dialog.dismiss()
}
}
}
if (progressDialog.is Showing() & progressDialog != null){ progressDialog.dismiss();
언급URL : https://stackoverflow.com/questions/22924825/view-not-attached-to-window-manager-crash
'programing' 카테고리의 다른 글
POSIX C API 기능 목록은 어디에 있습니까? (0) | 2023.10.10 |
---|---|
선택2()는 함수가 아닙니다. (0) | 2023.10.05 |
콘솔에서 Android 앱 중지 (0) | 2023.10.05 |
ActiveRecord 마이그레이션에서 SQL 문을 병렬로 안전하게 실행하려면 어떻게 해야 합니까? (0) | 2023.10.05 |
XML 스키마를 프로그램적으로 시각화하는 방법은? (0) | 2023.10.05 |