在 IntentService 中创建 AlertDialog 时无法添加 window

Unable to add window when creating AlertDialog inside an IntentService

我想在 IntentService 中创建一个 AlertDialog,但是当在 AlertDialog.Builder 构造函数中传递上下文时,它显示以下错误:

06-30 00:01:31.265 11994-11994/com.alwa7y W/System.err: android.view.WindowManager$BadTokenException: Unable to add window -- token null is not for an application
06-30 00:01:31.267 11994-11994/com.alwa7y W/System.err:     at android.view.ViewRootImpl.setView(ViewRootImpl.java:572)
    at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:310)
    at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:86)
    at android.app.Dialog.show(Dialog.java:319)
    at com.go.mushaf.mushafapplication.services.DownloadService$override.showAlert(DownloadService.java:176)
    at com.go.mushaf.mushafapplication.services.DownloadService$override.access$dispatch(DownloadService.java)
    at com.go.mushaf.mushafapplication.services.DownloadService.showAlert(DownloadService.java:0)
    at com.go.mushaf.mushafapplication.services.DownloadService$BackGroundTask.onPostExecute(DownloadService.java:88)
    at com.go.mushaf.mushafapplication.services.DownloadService$BackGroundTask.onPostExecute(DownloadService.java:61)
    at android.os.AsyncTask.finish(AsyncTask.java:651)
    at android.os.AsyncTask.access0(AsyncTask.java:180)
    at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:668)
    at android.os.Handler.dispatchMessage(Handler.java:102)
    at android.os.Looper.loop(Looper.java:148)
06-30 00:01:31.268 11994-11994/com.alwa7y W/System.err:     at android.app.ActivityThread.main(ActivityThread.java:5451)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)

这是创建 AlertDialog 的方法:

    public void showAlert(String message, String header) {
        if (header.equals(""))
            header = "Alert!";
        try {
            AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(getApplicationContext());
//            Log.d(TAG, "show: " + alertDialog.getOwnerActivity());
            alertDialogBuilder.setTitle(header);
            alertDialogBuilder.setMessage(message);
            alertDialogBuilder.setPositiveButton("موافق",
                    new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog, int which) {
                            ((Activity) context).finish();
                            dialog.dismiss();

                            showEndLoadingNotification(context);
                        }
                    });
//            alertDialogBuilder.show();
            alertDialogBuilder.setOnCancelListener(new DialogInterface.OnCancelListener() {
                @Override
                public void onCancel(DialogInterface dialog) {
                    ((Activity) context).finish();
                }
            });
            AlertDialog alertDialog = alertDialogBuilder.create();
            alertDialog.show();
        } catch (Exception ignored) {
            ignored.printStackTrace();
        }//when app trying to display a dialog using a previously finished activity as a context
    }

这是 IntentService class:

    package com.go.mushaf.mushafapplication.services;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.IntentService;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.support.annotation.Nullable;
import android.util.Log;
import android.widget.TextView;

import com.bumptech.glide.Glide;
import com.bumptech.glide.RequestBuilder;
import com.bumptech.glide.load.DataSource;
import com.bumptech.glide.load.engine.GlideException;
import com.bumptech.glide.request.RequestListener;
import com.bumptech.glide.request.target.Target;
import com.go.mushaf.mushafapplication.DownloadActivity;
import com.go.mushaf.mushafapplication.MainActivity;

import java.util.ArrayList;

import static com.go.mushaf.mushafapplication.DownloadActivity.BUNDLE;
import static com.go.mushaf.mushafapplication.DownloadActivity.CONTEXT;
import static com.go.mushaf.mushafapplication.DownloadActivity.TEXT_ID;
import static com.go.mushaf.mushafapplication.DownloadActivity.getLoadingText;
import static com.go.mushaf.mushafapplication.DownloadActivity.mTxtProgress;
import static com.go.mushaf.mushafapplication.DownloadActivity.showEndLoadingNotification;
import static com.go.mushaf.mushafapplication.Utility.getPages;


public class DownloadService extends IntentService {

    public int viewId;
    Context context;
    public static final String TAG = "servicee";

    public DownloadService() {
        super("DownloadService");
    }

    @Override
    protected void onHandleIntent(Intent intent) {

        if (intent.hasExtra(BUNDLE)) {
            viewId = intent.getBundleExtra(BUNDLE).getInt(TEXT_ID);
            Log.d(TAG, "onHandleIntent: ");
        }
        new BackGroundTask().execute();
    }

    @Override
    public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
        context = getApplicationContext();
        return super.onStartCommand(intent, flags, startId);
    }

    public class BackGroundTask extends AsyncTask<Void, Integer, Void> {

        private final String ASYNC_ERROR = this.getClass().getName();
        private RequestBuilder<Drawable> x;
        private ArrayList<String> pagesList = getPages();

        @Override
        protected Void doInBackground(Void... arg0) {

            // FIXME: 6/27/2018
            doAllCache(mTxtProgress);
            return null;
        }

        @Override
        protected void onProgressUpdate(Integer... values) {
            super.onProgressUpdate(values);
        }

        @Override
        protected void onPostExecute(Void result) {
            super.onPostExecute(result);
//            if(x!=null) {
//                x.preload();
////                if (!cancelFlag || count < MainActivity.mushafTotal)
////                    new BackGroundTask().execute(++count);
//            }
            showAlert("تم اكتمال التحميل بنجاح", "تم التحميل");
            // getApplicationContext(), unable to add window
            // DownladService.this, unable to add window
            // getBaseContext(), unable to add window
        }

        private void doAllCache(final TextView mTxtProgress) {
            Log.d(TAG, "doAllCache: " + mTxtProgress.getText().toString());
            Log.d(TAG, "doAllCache: " + pagesList.size());
            for (int i=0; i<pagesList.size(); i++) {
                String pageNumber = pagesList.get(i); //get string for page number
                Log.d(TAG, "doAllCache: " + pageNumber);
                String url = MainActivity.mainUril + pageNumber + ".gif"; // get page url
                final int finalI = i;
                x = Glide.with(DownloadService.this)
                        .load(url)
                        .listener(new RequestListener<Drawable>() {
                            @Override
                            public boolean onResourceReady(Drawable resource, Object model, Target<Drawable> target, DataSource dataSource, boolean isFirstResource) {
//                                Log.i("Image Loading End", String.valueOf(i));
                                mTxtProgress.setText(getLoadingText(getApplicationContext(), finalI));
                                Log.d(TAG, "onResourceReady: " + resource +"\n"+model.toString()+"\n"+target+"\n"+dataSource);
////                                //check cancel
////                                if (cancelFlag) {
////                                    finish();
////                                } else {
//
//                                    if (finalI < MainActivity.mushafTotal) {
//                                        final int ii = finalI + 1;
//                                        new BackGroundTask().execute();
//
////                                    new Handler().postDelayed(new Runnable() {
////                                        @Override
////                                        public void run() {//Use your "bitmap" here
////                                            doAllCache(ii);
////                                        }
////                                    }, 100);
//                                    }
////                                    else{
////                                        cancelFlag = true;
////                                    }
////                                }
                                return true;
                            }

                            @Override
                            public boolean onLoadFailed(@Nullable GlideException e, Object model, Target target, boolean isFirstResource) {
                                Log.d(ASYNC_ERROR, String.valueOf(finalI));
                                Log.d(ASYNC_ERROR, "onLoadFailed: " + e);
                                return false;
                            }

                        });
            }




        }

    }

    public void showAlert(String message, String header) {
        if (header.equals(""))
            header = "Alert!";
        try {
            AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(getApplicationContext());
//            Log.d(TAG, "show: " + alertDialog.getOwnerActivity());
            alertDialogBuilder.setTitle(header);
            alertDialogBuilder.setMessage(message);
            alertDialogBuilder.setPositiveButton("موافق",
                    new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog, int which) {
                            ((Activity) context).finish();
                            dialog.dismiss();

                            showEndLoadingNotification(context);
                        }
                    });
//            alertDialogBuilder.show();
            alertDialogBuilder.setOnCancelListener(new DialogInterface.OnCancelListener() {
                @Override
                public void onCancel(DialogInterface dialog) {
                    ((Activity) context).finish();
                }
            });
            AlertDialog alertDialog = alertDialogBuilder.create();
            alertDialog.show();
        } catch (Exception ignored) {
            ignored.printStackTrace();
        }//when app trying to display a dialog using a previously finished activity as a context
    }
}

这就是我启动服务的方式:

@Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.download_btn:
                startLoadingNotification();

                Bundle bundle = new Bundle();
                bundle.putInt(TEXT_ID, R.id.txt_load);
//                bundle.putSerializable(CONTEXT, (Serializable) DownloadActivity.this);
                startService(new Intent(DownloadActivity.this, DownloadService.class).putExtra(BUNDLE, bundle));

                mViewDownload.setVisibility(View.GONE);
                mViewCancel.setVisibility(View.VISIBLE);
                break;
            case R.id.cancel_btn:
                createLogoutDialog().show();
                break;
        }
    }

我想在 onPostExecute 方法中显示对话框。 我试过:

getApplicationContext(), DownloadService.this, this, getBaseContext()

以上都是同样的错误。

提前致谢。

您不能从 Service 显示 AlertDialog。您只能显示 Activity 中的 AlertDialog。在这种情况下,显示来自 activity 的正在启动此服务的对话框。或者,不使用对话框,而是使用 Notification.

除此之外:

  • 不要在 IntentService 内执行异步操作,因为服务会在 onHandleIntent() returns 后立即消失。一旦服务消失,您的进程可能会终止,在工作完成之前杀死您的后台线程。删除 BackGroundTask 并将其所有要执行的逻辑移至 onHandleIntent()。另外,摆脱 Glide 或弄清楚如何让它同步下载图像(据我所知,它做不到)。

  • IntentService 将无法在 Android 8.0+ 上正常运行,除非您将其设为前台服务并使用 startForegroundService()。考虑使用 JobIntentService 或在 2019 年及以后使用 WorkManager.