javaandroid-studioandroid-asynctaskandroidhttpclient

ArrayIndexOutOfBoundsException in doInBackground method


Please help me with this error. Even after passing value in execute() method I'm still unable to fix this issue.

Caused by: java.lang.ArrayIndexOutOfBoundsException: length=0; index=0 at com.iamsharzil.constraintlayoutproject.DownloadNews.doInBackground(DownloadNews.java:54) at com.iamsharzil.constraintlayoutproject.DownloadNews.doInBackground(DownloadNews.java:22)

DownloadNews.java

String NEWS_SOURCE = "bbc-news";
ArrayList<HashMap<String, String>> dataList = new ArrayList<HashMap<String, String>>();

private Activity mContext;

String API_KEY = "4f5f4fbf57f7476ba41c276b28379a6b";
ListView listNews;

static final String KEY_AUTHOR = "author";
static final String KEY_TITLE = "title";
static final String KEY_DESCRIPTION = "description";
static final String KEY_URL = "url";
static final String KEY_URLTOIMAGE = "urlToImage";
static final String KEY_PUBLISHEDAT = "publishedAt";


public DownloadNews(BaseDrawerActivity mContext) {
    this.mContext = mContext;
    Log.i("Constructor", "Download News called");
}

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

protected String doInBackground(String... args) {

    String xml = "";

       String url = args[0];
        Log.i("URL", url);

        xml = Function.executeGet(url);
        return xml;

}

@Override
protected void onPostExecute(String xml) {

    if(null != xml && xml.length()>10) {
        try {
            JSONObject jsonResponse = new JSONObject(xml);
            JSONArray jsonArray = jsonResponse.optJSONArray("articles");

            for (int i = 0; i < jsonArray.length(); i++) {
                JSONObject jsonObject = jsonArray.getJSONObject(i);
                HashMap<String, String> map = new HashMap<String, String>();
                map.put(KEY_AUTHOR, jsonObject.optString(KEY_AUTHOR).toString());
                map.put(KEY_TITLE, jsonObject.optString(KEY_TITLE).toString());
                map.put(KEY_DESCRIPTION, jsonObject.optString(KEY_DESCRIPTION).toString());
                map.put(KEY_URL, jsonObject.optString(KEY_URL).toString());
                map.put(KEY_URLTOIMAGE, jsonObject.optString(KEY_URLTOIMAGE).toString());
                map.put(KEY_PUBLISHEDAT, jsonObject.optString(KEY_PUBLISHEDAT).toString());
                dataList.add(map);
            }
        } catch (JSONException e) {
            Toast.makeText(mContext, "Unexpected error", Toast.LENGTH_SHORT).show();
        }

        listNews = (ListView) mContext.findViewById(R.id.listNews);
        ListNewsAdapter adapter = new ListNewsAdapter((Activity) mContext, dataList);
        listNews.setAdapter(adapter);

        listNews.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            public void onItemClick(AdapterView<?> parent, View view,
                                    int position, long id) {
                Intent i = new Intent(mContext, DetailsActivity.class);
                i.putExtra("url", dataList.get(+position).get(KEY_URL));
                mContext.startActivity(i);
            }
        });


    }else{
        Toast.makeText(mContext, "No news found", Toast.LENGTH_SHORT).show();
    }
}

}

BaseDrawerActivity.java

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_base_drawer);
    Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
    setSupportActionBar(toolbar);

    toolbar.setTitle("NEWS");

    listNews = (ListView) findViewById(R.id.listNews);

    DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);

    ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
            this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
    drawer.addDrawerListener(toggle);
    toggle.syncState();

    navigationView = (NavigationView) findViewById(R.id.nav_view);
    navigationView.setNavigationItemSelectedListener(this);

    if(Function.isNetworkAvailable(getApplicationContext()))
    {
        DownloadNews newsTask = new DownloadNews(this);
        newsTask.execute();
    }else{
        Toast.makeText(getApplicationContext(), "No Internet Connection", Toast.LENGTH_LONG).show();
    }
}

public boolean onNavigationItemSelected(MenuItem item) {
    // Handle navigation view item clicks here.
    int id = item.getItemId();
    Fragment fragment = null;

    if (id == R.id.nav_general) {
      String general =  "https://newsapi.org/v2/top-headlines?country=in&apiKey=" + API_KEY;
        new DownloadNews(this).execute(general);

    } else if (id == R.id.nav_sports) {
        String sports =  "https://newsapi.org/v2/top-headlines?categoty=sports&country=in&apiKey=" + API_KEY;

        new DownloadNews(this).execute(sports);
    } else if (id == R.id.nav_business) {
        String business =  "https://newsapi.org/v2/top-headlines?categoty=business&country=in&apiKey=" + API_KEY;

        new DownloadNews(this).execute(business);
    } else if (id == R.id.nav_technology) {
        String technology =  "https://newsapi.org/v2/top-headlines?categoty=technology&country=in&apiKey=" + API_KEY;
        new DownloadNews(this).execute(technology);

    } else if (id == R.id.nav_entertainment) {
        String entertainment =  "https://newsapi.org/v2/top-headlines?categoty=entertainment&country=in&apiKey=" + API_KEY;
        new DownloadNews(this).execute(entertainment);

    } else if (id == R.id.nav_health) {
        String health =  "https://newsapi.org/v2/top-headlines?categoty=health&country=in&apiKey=" + API_KEY;
        new DownloadNews(this).execute(health);

    } else if (id == R.id.nav_science) {
        String science =  "https://newsapi.org/v2/top-headlines?categoty=science&country=in&apiKey=" + API_KEY;
        new DownloadNews(this).execute(science);

    }

    if(fragment!=null) {
        FragmentManager fm = getSupportFragmentManager();
        FragmentTransaction ft = fm.beginTransaction();
        ft.replace(R.id.screen_area, fragment);
        ft.commit();
    }

    DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
    drawer.closeDrawer(GravityCompat.START);
    return true;
}

When a user click on any of the Menu item I want the url to be change.

Function.java

public class Function {

    public static boolean isNetworkAvailable(Context context) {
        return ((ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE)).
                getActiveNetworkInfo()!=null;
    }

    public static String executeGet(String targetURL) {
        URL url;
        HttpURLConnection connection = null;

        try {
            //Create connection
            url = new URL(targetURL);
            connection = (HttpURLConnection)url.openConnection();

            //connection.setRequestMethod("POST");
            //connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");

            connection.setRequestProperty("content-type", "application/json;  charset=utf-8");
            connection.setRequestProperty("Content-Language", "en-US");

            connection.setUseCaches (false);
            connection.setDoInput(true);
            connection.setDoOutput(false);

            InputStream is;

            int status = connection.getResponseCode();

            if (status != HttpURLConnection.HTTP_OK)
                is = connection.getErrorStream();
            else
                is = connection.getInputStream();

            BufferedReader rd = new BufferedReader(new InputStreamReader(is));
            String line;
            StringBuffer response = new StringBuffer();

            while((line = rd.readLine()) != null) {
                response.append(line);
                response.append('\r');
            }
            rd.close();
            return response.toString();
        } catch (Exception e) {
           return null;
        } finally {
            if(connection != null) {
                connection.disconnect();
            }
        }
    }

}


Solution

  • You are calling execute here:

    if(Function.isNetworkAvailable(getApplicationContext()))
    {
        DownloadNews newsTask = new DownloadNews(this);
        newsTask.execute(); // <-
    }else{
        Toast.makeText(getApplicationContext(), "No Internet Connection", Toast.LENGTH_LONG).show();
    }
    

    But are not passing an argument. That will cause your method to fail because you cannot access the zeroth item of a zero length array. You either need to ensure you are always passing data to it, or you need to do something like this:

    protected String doInBackground(String... args) {
      String xml = "";
    
      if (args.length > 0) { 
       String url = args[0];
        Log.i("URL", url);
        xml = Function.executeGet(url);
      }
    
       return xml;
    }
    

    This way, if args is empty, you return an empty string and can then handle for that where you need to.