简体   繁体   English

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

[英]having error when showing alertDialog in asyncTask that is called from service?

I have a service that doing some work and at the end I execute my asynctask(its name is background). 我有一项服务做一些工作,最后我执行我的asynctask(它的名字是背景)。 In asyncTask,In onPostExecute() I want to show an alertDialog. 在asyncTask中,在onPostExecute()中我想显示一个alertDialog。 but when i debug my app, error accures in my service at the line that i execute my asyncTask. 但是当我调试我的应用程序时,错误在我的服务中执行我执行asyncTask的行。 this line: 这一行:

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

I know that the error accures because of the context that i send to asyncTask. 我知道错误是因为我发送给asyncTask的上下文。 I apply getApplicationContext(); 我应用getApplicationContext(); & getBaseContext();& service's context,too; &getBaseContext();&service的上下文也是; but error doesn't disapear. 但错误不会消失。 I apply this code in the mainActivity with its context and no error occures,so I am sure this error is because of the context that i send it from my service to asyncTask's constructor. 我在mainActivity中使用它的上下文应用此代码并且没有错误发生,所以我确定这个错误是因为我将它从我的服务发送到asyncTask的构造函数的上下文。

So, what can I do? 那么,我该怎么办? I appreciate any help. 我感谢任何帮助。

Edited:this is the error. 编辑:这是错误。

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)

this is my asyncTask class: 这是我的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();
}

this is my service's code: 这是我服务的代码:

 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;



}

and this is my doSomeThingReapetedly() method that i called it in onStartcommand() 这是我在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);

After adding "Pravin Divraniya's" solution, it works fine but an error occurs in asyncTask after debuging onPostExecute() and intering to doInBackground(), that error is: 添加“Pravin Divraniya”解决方案之后,它工作正常,但是在调试onPostExecute()并插入doInBackground()之后,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)

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

I think that the error come from the fact that you want to launch an ui from a service witch is not running on the main thread and Service does not have an implementation for runOnUiThread the work arround is to use a LocalBroadcastManager and a broadcastreceiver on any activity and open the dialog from the activity below a sample example 我认为这个错误来自这样一个事实:你想从一个服务启动一个ui没有在主线程上运行而Service没有runOnUiThread的实现工作arround是在任何活动上使用LocalBroadcastManager和broadcastreceiver并从示例示例下方的活动中打开对话框

In your service 在您的服务中

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

In any activity on frgament 在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
        }
    }
};

And dont forget to register the receiver 并且不要忘记注册接收器

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

As per AsynkTask documentation (Read Threading rules section) 根据AsynkTask文档(读取线程规则部分)

  1. The AsyncTask class must be loaded on the UI thread. 必须在UI线程上加载AsyncTask类。 This is done automatically as of JELLY_BEAN. 这是从JELLY_BEAN开始自动完成的。
  2. The task instance must be created on the UI thread. 必须在UI线程上创建任务实例。
  3. execute(Params...) must be invoked on the UI thread. 必须在UI线程上调用execute(Params ...)。
  4. Do not call onPreExecute(), onPostExecute(Result), doInBackground(Params...), onProgressUpdate(Progress...) manually. 不要手动调用onPreExecute(),onPostExecute(Result),doInBackground(Params ...),onProgressUpdate(Progress ...)。
  5. The task can be executed only once (an exception will be thrown if a second execution is attempted.) 该任务只能执行一次(如果尝试第二次执行,则会抛出异常。)

If you want to do repeated operation you can do it using Handler . 如果要重复操作,可以使用Handler Create Handler in onStartCommand (so, from the UI thread). onStartCommand创建Handler(因此,从UI线程)。 Then use that Handler to trigger AsyncTask . 然后使用该Handler触发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.
    }

create Runnable class instance inside your service class and call AsyncTask from there. 在服务类中创建Runnable类实例,并从那里调用AsyncTask。

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

If you wish to stop repeted calls to runnable, simply call mHandler.removeCallbacks(runnable); 如果你想停止对runnable的重复调用,只需调用mHandler.removeCallbacks(runnable);

Update :- We cant show normal Alert dialog with service context so below is two possible solutions. 更新: -我们无法显示带服务上下文的正常警报对话框,因此下面是两种可能的解决方案。

Solution 1 :- 解决方案1: -

We can show dialog from service only if it is a system alert dialog. 只有在系统警报对话框中,我们才能显示来自服务的对话框。 So, set TYPE_SYSTEM_ALERT window layout parameter to Dialog as follows: 因此,将TYPE_SYSTEM_ALERT窗口布局参数设置为Dialog,如下所示:

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

But, it needs SYSTEM_ALERT_WINDOW permission. 但是,它需要SYSTEM_ALERT_WINDOW权限。 So, don't forget to add this permissin in Manifest file. 所以,不要忘记在Manifest文件中添加此权限。

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

Solution 2 :- 解决方案2: -

Try to start an Activity and set the Activity's Theme to Theme.Dialog. 尝试启动一个Activity并将Activity的主题设置为Theme.Dialog。 There is a demo in ApiDemo Project. ApiDemo项目中有一个演示。 Check this link on how to apply theme to an activity or application. 检查链接,了解如何将主题应用于活动或应用程序。

Just for Information 仅供参考

  1. A Service runs in the main thread of its hosting process—the service does not create its own thread and does not run in a separate process (unless you specify in manifest otherwise). Service在其托管进程的主线程中运行 - 该服务不会创建自己的线程,也不会在单独的进程中运行(除非您在清单中指定)。 IntentService runs on worker thread(non UIThread). IntentService在工作线程(非UIThread)上运行。

  2. You can call mHandler.postDelayed from any thread, because once we are create handler instance it is associated with the Thread in which it create. 您可以从任何线程调用mHandler.postDelayed ,因为一旦我们创建了处理程序实例,它就会与它创建的Thread相关联。 in our case it is UIThread as we are creating it in onStartCommand method. 在我们的例子中,它是UIThread,因为我们在onStartCommand方法中创建它。

Feel free to ask any query. 随意询问任何查询。

Hope this will help you and clear your doubts. 希望这会帮助你并清除你的疑虑。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM