在从服务调用的asyncTask中显示alertDialog时出错?

时间:2016-09-08 14:04:11

标签: android service android-asynctask android-alertdialog android-context

我有一项服务,做一些工作,最后我执行我的asynctask(它的名字是背景)。 在asyncTask中,在onPostExecute()中我想显示一个alertDialog。 但是当我调试我的应用程序时,错误在我的服务中执行我执行asyncTask的行。这一行:

backGround=new BackGround(context); backGround.execute(String.valueOf(send_json))

我知道错误是因为我发送给asyncTask的上下文而产生的。 我应用getApplicationContext(); &安培; getBaseContext();&安培;服务的背景也是如此;但错误并没有消失。 我在mainActivity中使用它的上下文应用此代码并且没有错误发生,所以我确定这个错误是因为我将它从我的服务发送到asyncTask的构造函数的上下文。

那么,我该怎么办? 我感谢任何帮助。

编辑:这是错误。

09-08 18:39:35.253 20251-20813/ir.blog.trafik E/AndroidRuntime: FATAL EXCEPTION: Timer-0
                                                                      java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
                                                                          at android.os.Handler.<init>(Handler.java:197)
                                                                          at android.os.Handler.<init>(Handler.java:111)
                                                                          at android.app.Dialog.<init>(Dialog.java:111)
                                                                          at android.app.AlertDialog.<init>(AlertDialog.java:114)
                                                                          at android.app.AlertDialog$Builder.create(AlertDialog.java:931)
                                                                          at ir.blog.trafik.BackGround.onPreExecute(BackGround.java:88)
                                                                          at android.os.AsyncTask.executeOnExecutor(AsyncTask.java:586)
                                                                          at android.os.AsyncTask.execute(AsyncTask.java:534)
                                                                          at ir.blog.trafik.locationService.json_maker(locationService.java:538)
                                                                          at ir.blog.trafik.locationService$1.run(locationService.java:588)
                                                                          at java.util.Timer$TimerImpl.run(Timer.java:284)

这是我的asyncTask类:

public class BackGround   extends AsyncTask < String , Void , String > {
Context context;
AlertDialog alertDialog;
public BackGround(Context context){
    this.context=context;
}

@Override
protected String doInBackground(String... params){
String location_url ="http://192.168.1.90/server_connection.php";
    try{
        URL url1=new URL(location_url);
        HttpURLConnection httpURLConnection =          (HttpURLConnection)url1.openConnection();
        httpURLConnection.setRequestMethod("POST");
        httpURLConnection.setDoOutput(true);
        httpURLConnection.setDoInput(true);
        OutputStream stream_upload=httpURLConnection.getOutputStream();
        BufferedWriter buffer_writer=new BufferedWriter(new OutputStreamWriter(stream_upload,"UTF-8"));
        // String PostData= URLEncoder.encode()

        buffer_writer.write(String.valueOf(params));


        buffer_writer.flush();
        buffer_writer.close();
        stream_upload.close();





        InputStream stream_dawnload=httpURLConnection.getInputStream();
        BufferedReader bufferreader=new BufferedReader(new InputStreamReader(stream_dawnload,"iso-8859-1"));
        String result="";
        String line;
        while ((line = bufferreader.readLine()) != null) {
            result += line;}
        bufferreader.close();
        stream_upload.flush();
        stream_dawnload.close();
        httpURLConnection.disconnect();

        return result;



    }catch (Exception e){
        e.printStackTrace();
    }

    return null;

}

@Override
protected void onPreExecute() {
    alertDialog = new AlertDialog.Builder(context).create();
    alertDialog.setTitle("Login status");
}

 @Override
protected void onPostExecute(String result) {

    alertDialog.setMessage(result);
   alertDialog.show();
}

这是我的服务代码:

 public class locationService extends Service{Context context;BackGround backGround ;


@Override
public void onCreate() {
      context =this;
     }

 @Override
public int onStartCommand(Intent intent, int flags, int startId) {

Toast.makeText(context,"service started",Toast.LENGTH_LONG).show();


    doSomeThingRepeatedly(context);


    return Service.START_FLAG_REDELIVERY;



}

这是我在onStartcommand()中调用的doSomeThingReapetedly()方法

 private  void doSomeThingRepeatedly(final Context context) {
    timer.scheduleAtFixedRate(new TimerTask() {

        @Override
        public void run() {
......
      backGround=new BackGround(context);
    backGround.execute(String.valueOf(send_json));
}


    }, 0, UPDATE_INTERVAL);

添加&#34; Pravin Divraniya&#34;&#34;解决方案,它工作正常,但在onPostExecute()和interInBackground()之间的asyncTask中发生错误,该错误是:

FATAL EXCEPTION: main
                                                                      android.view.WindowManager$BadTokenException: Unable to add window -- token null is not for an application
                                                                          at android.view.ViewRootImpl.setView(ViewRootImpl.java:804)
                                                                          at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:288)
                                                                          at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:73)
                                                                          at android.app.Dialog.show(Dialog.java:287)
                                                                          at ir.blog.trafik.BackGround.onPostExecute(BackGround.java:103)
                                                                          at ir.blog.trafik.BackGround.onPostExecute(BackGround.java:22)
                                                                          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:5493)
                                                                          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:1225)
                                                                          at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1041)
                                                                          at dalvik.system.NativeStart.main(Native Method)

3 个答案:

答案 0 :(得分:0)

您正在doInBackground()内创建一个在工作线程中运行的对话框,请尝试在onPreExecuteonPostExecute中创建,具体取决于您的要求。

答案 1 :(得分:0)

我认为错误来自这样一个事实:你想从一个服务启动一个ui没有在主线程上运行而Service没有runOnUiThread的实现工作arround是使用LocalBroadcastManager和一个广播接收器在任何活动上,从示例

下面的活动中打开对话框

在您的服务中

Intent intent = new Intent("showDialog");
    LocalBroadcastManager.getInstance(this).sendBroadcast(intent);

在frgament的任何活动

private BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        if(action.equals("showDialog")) {
            // Show your dialog here
        }
    }
};

不要忘记注册接收器

// Register receiver onStart/onCreate
    LocalBroadcastManager.getInstance(this).registerReceiver(broadcastReceiver,new IntentFilter("showDialog"));
    // Unregister onDestroy
    LocalBroadcastManager.getInstance(this).unregisterReceiver(broadcastReceiver);

答案 2 :(得分:0)

根据AsynkTask文档(阅读线程规则部分)

  1. 必须在UI线程上加载AsyncTask类。这是从JELLY_BEAN开始自动完成的。
  2. 必须在UI线程上创建任务实例。
  3. 必须在UI线程上调用
  4. execute(Params ...)。
  5. 不要手动调用onPreExecute(),onPostExecute(Result),doInBackground(Params ...),onProgressUpdate(Progress ...)。
  6. 任务只能执行一次(如果尝试第二次执行,则会抛出异常。)
  7. 如果您想重复操作,可以使用Handler进行操作。在onStartCommand中创建处理程序(因此,从UI线程)。然后使用该处理程序触发AsyncTask

        private Handler mHandler = null;
    
        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            ...
            mHandler = new Handler();
            mHandler.postDelayed(runnable,1000);
    //Here 1000 is delayMillis,  you can set your delay here.
        }
    

    在服务类中创建Runnable类实例,并从那里调用AsyncTask。

    Runnable runnable = new Runnable() {
            @Override
            public void run() {
                backGround=new BackGround(context);
                backGround.execute(String.valueOf(send_json));
            }
        };
    

    如果您希望停止对runnable进行重复调用,只需致电mHandler.removeCallbacks(runnable);

    即可

    更新: - 我们无法显示具有服务上下文的正常警报对话框,因此下面是两种可能的解决方案。

    解决方案1: -

    只有在系统警报对话框中,我们才能显示来自服务的对话框。因此,将TYPE_SYSTEM_ALERT窗口布局参数设置为Dialog,如下所示:

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

    但是,它需要SYSTEM_ALERT_WINDOW权限。所以,不要忘记在Manifest文件中添加此权限。

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

    解决方案2: -

    尝试启动一个Activity并将Activity的主题设置为Theme.Dialog。 ApiDemo项目中有一个演示。查看有关如何将主题应用于活动或应用程序的this链接。

    仅供参考

    1. Service在其托管进程的主线程中运行 - 该服务不会创建自己的线程,也不会在单独的进程中运行(除非您在清单中指定)。 IntentService在工作线程(非UIThread)上运行。

    2. 您可以从任何线程调用mHandler.postDelayed,因为一旦我们创建了处理程序实例,它就会与它创建的Thread相关联。在我们的例子中,它是UIThread,因为我们正在onStartCommand方法中创建它。

    3. 随意询问任何问题。

      希望这会帮助你并清除你的怀疑。