Search code examples
androidandroid-volleythread-sleep

Constantly checking for new data in web service results in java.lang.OutOfMemoryError


I am doing long polling in my app, checking for new data every 500ms then update my textview when there is a new change. It's doing fine but after a few minutes, my app just crashes and gives me this error:

java.lang.OutOfMemoryError: pthread_create (1040KB stack) failed: Try again
                                                                                 at java.lang.Thread.nativeCreate(Native Method)
                                                                                 at java.lang.Thread.start(Thread.java:1063)
                                                                                 at com.android.volley.RequestQueue.start(RequestQueue.java:142)
                                                                                 at com.android.volley.toolbox.Volley.newRequestQueue(Volley.java:66)
                                                                                 at com.android.volley.toolbox.Volley.newRequestQueue(Volley.java:78)
                                                                                 at com.example.rendell.longpolling.MainActivity.sendRequest(MainActivity.java:96)
                                                                                 at com.example.rendell.longpolling.MainActivity$1$1.run(MainActivity.java:59)
                                                                                 at android.os.Handler.handleCallback(Handler.java:739)
                                                                                 at android.os.Handler.dispatchMessage(Handler.java:95)
                                                                                 at android.os.Looper.loop(Looper.java:135)
                                                                                 at android.app.ActivityThread.main(ActivityThread.java:5253)
                                                                                 at java.lang.reflect.Method.invoke(Native Method)
                                                                                 at java.lang.reflect.Method.invoke(Method.java:372)
                                                                                 at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:900)
                                                                                 at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:695)

MainActivity.java

public class MainActivity extends AppCompatActivity {

TextView text;
Date noteTS;

public static final String JSON_URL = "http://192.168.0.100/androidphp/data.php";

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

    text = (TextView) findViewById(R.id.text);

    (new Thread(new Runnable()
    {

        @Override
        public void run()
        {
            while (!Thread.interrupted())
                try
                {
                    Thread.sleep(500);
                    runOnUiThread(new Runnable() // start actions in UI thread
                    {

                        @Override
                        public void run()
                        {
                        // this action have to be in UI thread
                            /*noteTS = Calendar.getInstance().getTime();

                            String time = "hh:mm"; // 12:00
                            text.setText(DateFormat.format(time, noteTS));*/
                            sendRequest();
                        }
                    });
                }
                catch (InterruptedException e)
                {
                    // ooops
                }
        }
    })).start(); // the while thread will start in BG thread
}

public void sendRequest(){

    //While the app fetched data we are displaying a progress dialog
    //final ProgressDialog loading = ProgressDialog.show(this,"Fetching Data","Please wait...",false,false);

    StringRequest stringRequest = new StringRequest(JSON_URL,
            new Response.Listener<String>() {
                @Override
                public void onResponse(String response) {

                    //text.setText(response);

                    //loading.dismiss();
                    try{
                        showJSON(response);
                    }catch(Exception e) {}
                }
            },
            new Response.ErrorListener() {
                @Override
                public void onErrorResponse(VolleyError error) {
                    //Toast.makeText(MainActivity.this, error.getMessage(), Toast.LENGTH_LONG).show();
                }
            });

    RequestQueue requestQueue = Volley.newRequestQueue(this);
    requestQueue.add(stringRequest);
}

private void showJSON(String json){
    ParseJson pj = new ParseJson(json);
    pj.parseJSON();
    text.setText(ParseJson.playing[0]);
    }
}

ParseJson.java

public class ParseJson {
public static String[] playing;

public static final String JSON_ARRAY = "result";
public static final String RESULT_ID = "playing";

private JSONArray users = null;

private String json;

public ParseJson(String json){
    this.json = json;
}

public void parseJSON(){
    JSONObject jsonObject=null;
    try {
        jsonObject = new JSONObject(json);
        users = jsonObject.getJSONArray(JSON_ARRAY);

        playing = new String[users.length()];

        for(int i=0;i<users.length();i++){
            JSONObject jo = users.getJSONObject(i);
            playing[i] = jo.getString(RESULT_ID);
        }
    } catch (JSONException e) {
        e.printStackTrace();
    }
    }
}

Solution

  • I'm not sure what is wrong with your code but I can give you few tips

    first of all, Read the android documentations on how to make a singleton class for volley, you are creating a new RequestQueue every time you send a request, I use one queue for my whole app, maybe in some cases you create more but I can't think of any right now, most probably this is your main problem since the error is happening at newQueue method

    you don't have to make the singleton class but at least try to make the queue as instance variable and add to it each time.

    second of all there are simpler ways to perform a task every x seconds, I heared (NOT SURE) that using thread.sleep in android is not recommended

    here is how I usually perform such tasks:

    Timer timer = new Timer();
        final Handler handler = new Handler(){
            @Override
            public void handleMessage(Message msg) {
                // do something on UI
            }
        };
        TimerTask task = new TimerTask () {
            @Override
            public void run () {
                //send volley request here
            }
        };
        timer.schedule(task, 0, 60000); // 60000 is time in ms