在 android 中,在没有来自 Web 服务的数据时显示 toast 会导致应用程序崩溃

Displaying toast on no data coming form webservice crashes app in android

全部。我正在使用一个虚拟应用程序,在其中显示来自 weather webservice http://api.openweathermap.org/data/2.5/weather?q=CityName 的数据。一切正常,但我面临的问题是,当我在没有来自服务器的数据或互联网可能不可用时显示 Toast 时在设备上,我的应用程序在模拟器播放中崩溃。

"Unfortunately wheather app stopped working "

只有当设备上没有互联网时才会出现此问题。当我断开 Internet 时为我制造问题的线路是这样的:

Toast.makeText(getApplicationContext(),  "Not able to connect", Toast.LENGTH_LONG).show();

如果我评论这一行,我的应用程序运行良好。我在这个文件上的所有代码都是这样的:

package com.mubu.wheathertoday.wheathertoday;

import android.app.ProgressDialog;
import android.content.Intent;
import android.os.AsyncTask;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

import org.json.JSONObject;
import org.w3c.dom.Text;


public class MainActivity extends ActionBarActivity {
    EditText etCity;
    Button btnShow;
    ProgressDialog pbar;
    String JsonString;
    TextView tvr;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

         etCity=(EditText)findViewById(R.id.etCity);
        btnShow=(Button)findViewById(R.id.btnShow);


        btnShow.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                AsyncGetData gd=new AsyncGetData();
                gd.execute();
            }

        });

    }


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }


    private  class AsyncGetData extends AsyncTask<Void,Void,Void>{


        @Override
        protected Void doInBackground(Void... params) {
  try {
      ServiceHandler sh = new ServiceHandler();
      String url="http://api.openweathermap.org/data/2.5/weather?q="+etCity.getText().toString().trim();
    JsonString = sh.makeServiceCall(url, ServiceHandler.POST);
      if (JsonString != null) {
         Intent i=new Intent(getApplicationContext(),WheatherActivity.class);
          try{
          i.putExtra("jsn",JsonString);
         i.putExtra("city",etCity.getText().toString());
           startActivity(i);
          }catch (Exception e){


      }
      }
      else
      {
    try{

       Toast.makeText(getApplicationContext(),  "Not able to connect", Toast.LENGTH_LONG).show();


 // if I disconnect Internet this line gets executed and my app crashes
            }catch (Exception e){


}
      }

      }
  catch (Exception e){etCity.setText(e.getMessage());}
            return null;

        }

        @Override
        protected void onPreExecute() {
            super.onPreExecute();

              pbar=new ProgressDialog(MainActivity.this);
            pbar.setMessage("Please wait...");
            pbar.setCancelable(false);
            pbar.show();
        }

        @Override
        protected void onPostExecute(Void s) {
            super.onPostExecute(s);
           if(pbar.isShowing() )
                pbar.dismiss();


        }

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

}

也许你不应该在"doInbackground"中做吐司。因为它不是UI线程。

尽量在"onPostExecute".

完成

您正在尝试在 doInBackground 中显示 Toast。不应从此方法调用任何 UI 相关功能,因为这是后台线程。你必须展示来自 onPostExecute.

的吐司

你正在做的是在后台显示 toast,如果你想显示 toast,你必须在 onPostExecute 中编写那段代码

你可以做的是你必须在假设命名为 _Is_Responce_Received=false;

的异步任务中创建一个布尔变量

并在

if (JsonString != null) {
 _Is_Responce_Received=true;
  // rest of your code

 }

并在你的 post 中执行

  @Override
    protected void onPostExecute(Void s) {
        super.onPostExecute(s);

 if(!_Is_Responce_Received){
    Toast.makeText(getApplicationContext(),  "Not able to connect", Toast.LENGTH_LONG).show();
  }
       if(pbar.isShowing() )
            pbar.dismiss();


    }

问题是您正在尝试从 doInBackground 更新您的用户界面。 doInBackground在后台线程中运行,而不是在主线程中运行(也称为 UI 线程)。

正如您在 AsyncTask 文档(强调我的)中所读:

onPreExecute(), invoked on the UI thread before the task is executed. This step is normally used to setup the task, for instance by showing a progress bar in the user interface.

doInBackground(Params...), invoked on the background thread immediately after onPreExecute() finishes executing. This step is used to perform background computation that can take a long time. The parameters of the asynchronous task are passed to this step. The result of the computation must be returned by this step and will be passed back to the last step. This step can also use publishProgress(Progress...) to publish one or more units of progress. These values are published on the UI thread, in the onProgressUpdate(Progress...) step.

onProgressUpdate(Progress...), invoked on the UI thread after a call to publishProgress(Progress...). The timing of the execution is undefined. This method is used to display any form of progress in the user interface while the background computation is still executing. For instance, it can be used to animate a progress bar or show logs in a text field.

onPostExecute(Result), invoked on the UI thread after the background computation finishes. The result of the background computation is passed to this step as a parameter.

所以你需要在别处做那个Toast。例如,您可以使用回调方法在 Asynctask 中定义一个接口:

public interface MyTaskInterface {
    public void onNetworkError();
}

您在 AsyncTask 中定义了一个侦听器:

private MyTaskInterface listener;

为监听器添加getters和setters,你可以这样写:

if (listener != null) {
    listener.onNetworkError();
}

首先确保你有互联网许可。 如果它是正确的,那么按照每年的代码,您将在后台线程上发布一条消息。 虽然 UI 工作不允许在后台进行。 因此,您可以使用 onPost() 方法来吐司消息,也可以应用以下代码。

runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    Toast.makeText(getApplicationContext(),  "Not able to connect", Toast.LENGTH_LONG).show();
                }
            });

所以 **runOnUiThread** 允许我们从后台线程执行 UI 操作。希望对你有帮助。