-2

I created an app that reads data from url once a button is clicked.

Then, I use this data to display some of it in a new activity.

The url reading is done by using ASynctask as follows:

package com.example.test;

import android.os.AsyncTask;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;

public class Read_URL extends AsyncTask<Void,Void,Void> {

    String data = "";
    String [] list;

    ArrayList <String>  hiscore_skill_rank = new ArrayList<>();
    ArrayList <String>  hiscore_skill_level = new ArrayList<>();
    ArrayList <String>  hiscore_skill_exp = new ArrayList<>();

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

        try {
            URL url = new URL("https://......");
            HttpURLConnection httpURLConnection =(HttpURLConnection) url.openConnection();

            InputStream inputStream = httpURLConnection.getInputStream();

            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));

            String line;
            for (int j = 0; j <24; j++) {
                line = bufferedReader.readLine();
                data = data + line;

                list = line.split(",");

                hiscore_skill_rank.add(list[0]);
                hiscore_skill_level.add(list[1]);
                hiscore_skill_exp.add(list[2]);

            }
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return null;
    }

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

    }
}

Where the main code is as follows:

import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;

public class MainActivity extends AppCompatActivity {
    Button button;
    EditText name;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.opening_screen);

        button = findViewById(R.id.continue_button);
        name = findViewById(R.id.username_text);

        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                openHiScore();
            }
        });
    }

        public void openHiScore(){

            Read_URL process = new Read_URL();
            process.execute();

            Intent intent = new Intent(this,HiScore.class);

            intent.putStringArrayListExtra("hiscore_skill_rank",process.hiscore_skill_rank);
            intent.putStringArrayListExtra("hiscore_skill_level",process.hiscore_skill_level);
            intent.putStringArrayListExtra("hiscore_skill_exp",process.hiscore_skill_exp);
            intent.putExtra("name",name.getText().toString());

            startActivity(intent);

        }

}

the result from process.execute is 3 arraylists of 24 variables.

My problem is that when I launch the app it crashes however when I launch it in debug mode everything works.

I was thinking maybe since it takes time for the url to read in regular mode it does not know what to display however when in debug mode it has more time to finish obtaining the info from the url.

Is there any reason that reading url can crash an app if it hasnt finished reading the data?

Thank you!

Zoe
  • 27,060
  • 21
  • 118
  • 148
Ben
  • 1,737
  • 2
  • 30
  • 61

1 Answers1

0

The problem is with this method:

    public void openHiScore(){

        Read_URL process = new Read_URL();
        process.execute();

        Intent intent = new Intent(this,HiScore.class);

        intent.putStringArrayListExtra("hiscore_skill_rank",process.hiscore_skill_rank);
        intent.putStringArrayListExtra("hiscore_skill_level",process.hiscore_skill_level);
        intent.putStringArrayListExtra("hiscore_skill_exp",process.hiscore_skill_exp);
        intent.putExtra("name",name.getText().toString());

        startActivity(intent);

    }

process.execute() is going to start the Async Task, but then immediately move on to creating the new Intent before the doInBackground code has even run. If possible, you should try to move all of the Intent/startActivity code into the onPostEvent of the Read_URL class. Or, create a callback function in your main activity that Read_Url could call from onPostEvent, and that function would do all of the Intent/startActivity stuff back in Main.

Here is an example of how to integrate a callback function. To make it easier, I make Read_URL an internal class defined inside of the MainActivity class.

MainActivity.java

            // Imports from MainActivity
            import android.content.Intent;
            import android.support.v7.app.AppCompatActivity;
            import android.os.Bundle;
            import android.view.View;
            import android.widget.Button;
            import android.widget.EditText;

            // Imports from Read_URL
            import android.os.AsyncTask;
            import java.io.BufferedReader;
            import java.io.IOException;
            import java.io.InputStream;
            import java.io.InputStreamReader;
            import java.net.HttpURLConnection;
            import java.net.MalformedURLException;
            import java.net.URL;
            import java.util.ArrayList;


            public class MainActivity extends AppCompatActivity {
                Button button;
                EditText name;
                public Activity myActivity;

                @Override
                protected void onCreate(Bundle savedInstanceState) {
                    super.onCreate(savedInstanceState);
                    setContentView(R.layout.opening_screen);

                    button = findViewById(R.id.continue_button);
                    name = findViewById(R.id.username_text);
                    myActivity = this;

                    button.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View v) {
                            openHiScore();
                        }
                    });
                }

                public void openHiScore(){

                    Read_URL process = new Read_URL();
                    process.execute();


                }

                public void processResults(ArrayList hiscore_skill_rank, ArrayList hiscore_skill_level, ArrayList hiscore_skill_exp) {

                    Intent intent = new Intent(this,HiScore.class);

                    intent.putStringArrayListExtra("hiscore_skill_rank",hiscore_skill_rank);
                    intent.putStringArrayListExtra("hiscore_skill_level",hiscore_skill_level);
                    intent.putStringArrayListExtra("hiscore_skill_exp",hiscore_skill_exp);
                    intent.putExtra("name",name.getText().toString());

                    startActivity(intent);

                }                       


                // I think you can include the Read_URL class inside of your MainActivity class
                // In that way, it can access the public variables declared in the MainActivity class

                public class Read_URL extends AsyncTask<Void,Void,Void> {

                    String data = "";
                    String [] list;

                    ArrayList <String>  hiscore_skill_rank = new ArrayList<>();
                    ArrayList <String>  hiscore_skill_level = new ArrayList<>();
                    ArrayList <String>  hiscore_skill_exp = new ArrayList<>();

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

                        try {
                            URL url = new URL("https://......");
                            HttpURLConnection httpURLConnection =(HttpURLConnection) url.openConnection();

                            InputStream inputStream = httpURLConnection.getInputStream();

                            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));

                            String line;
                            for (int j = 0; j <24; j++) {
                                line = bufferedReader.readLine();
                                data = data + line;

                                list = line.split(",");

                                hiscore_skill_rank.add(list[0]);
                                hiscore_skill_level.add(list[1]);
                                hiscore_skill_exp.add(list[2]);

                            }
                        } catch (MalformedURLException e) {
                            e.printStackTrace();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }

                        return null;
                    }

                    @Override
                    protected void onPostExecute(Void aVoid) {
                        super.onPostExecute(aVoid);
                        myActivity.processResults(hiscore_skill_rank, hiscore_skill_level, hiscore_skill_exp);

                    }
                } // end of Read_URL
            }  // end of MainActivity
Michael Dougan
  • 1,698
  • 1
  • 9
  • 13
  • Thank you Michael, I tried moving it to OnPost however had problems finding how to pass 3 arraylists from doInBackground to OnPost. – Ben May 01 '19 at 03:40
  • Yes, that would be tricky, I think the idea to create a callback function in your main activity is a better idea. In main, you would just need to declare a public function. Then, pass the Context of the main activity to the Read_URL class' initialization method. Finally, when onPost calls the main function, pass the three arraylists back as parameters. – Michael Dougan May 01 '19 at 16:40
  • any chance for good full example of how to use callback here? – Ben May 01 '19 at 19:02
  • I expanded my answer above! – Michael Dougan May 01 '19 at 20:45
  • I only needed to change last line to be processResults(hiscore_skill_rank, hiscore_skill_level, hiscore_skill_exp); without myActivity. Thank you very much! – Ben May 02 '19 at 18:20
  • Even better! :-) – Michael Dougan May 02 '19 at 18:22