質問

I am developing my first android app. I have been created a Service class which role is to check if any new information on an external webpage. The HTTP request and service work as i should, but after a while I get these OutOfMemoryError.

Are someone able to see where the Service gather all that memory?

Error message 1.

java.lang.OutOfMemoryError: pthread_create (stack size 16384 bytes) failed: Try again
at java.lang.VMThread.create(Native Method)
at java.lang.Thread.start(Thread.java:1029)
at org.apache.http.impl.conn.tsccm.AbstractConnPool.enableConnectionGC(AbstractConnPool.java:140)
at org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager.createConnectionPool(ThreadSafeClientConnManager.java:120)
at org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager.(ThreadSafeClientConnManager.java:98)
at com.loopj.android.http.AsyncHttpClient.(AsyncHttpClient.java:210)
at com.loopj.android.http.AsyncHttpClient.(AsyncHttpClient.java:149)
at com.loopj.android.http.AsyncHttpClient.(AsyncHttpClient.java:119)
at com.quickit.app.MyService.checkUpdates(MyService.java:89)
at com.quickit.app.MyService.access$1(MyService.java:75)
at com.quickit.app.MyService$TimeDisplayTimerTask$1.run(MyService.java:68)
at android.os.Handler.handleCallback(Handler.java:733)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:136)
at android.app.ActivityThread.main(ActivityThread.java:5105)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:792)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:608)
at dalvik.system.NativeStart.main(Native Method)

Error message 2.

java.lang.OutOfMemoryError: thread creation failed
at java.lang.VMThread.create(Native Method)
at java.lang.Thread.start(Thread.java:1050)
at java.util.concurrent.ThreadPoolExecutor.addWorker(ThreadPoolExecutor.java:913)
at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1295)
at java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:81)
at com.loopj.android.http.AsyncHttpClient.sendRequest(AsyncHttpClient.java:893)
at com.loopj.android.http.AsyncHttpClient.post(AsyncHttpClient.java:688)
at com.loopj.android.http.AsyncHttpClient.post(AsyncHttpClient.java:671)
at com.loopj.android.http.AsyncHttpClient.post(AsyncHttpClient.java:658)
at com.quickit.app.MyService.checkUpdates(MyService.java:90)
at com.quickit.app.MyService.access$1(MyService.java:75)
at com.quickit.app.MyService$TimeDisplayTimerTask$1.run(MyService.java:68)
at android.os.Handler.handleCallback(Handler.java:725)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:213)
at android.app.ActivityThread.main(ActivityThread.java:5092)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:797)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:564)
at dalvik.system.NativeStart.main(Native Method)

My service class.

public class MyService extends Service {
    boolean login = false;
    // constant
    public static final long NOTIFY_INTERVAL = 10 * 1000; // 10 seconds
    String address = Utilities.getAPIUrl();
    // run on another Thread to avoid crash
    private Handler mHandler = new Handler();
    // timer handling
    private Timer mTimer = null;

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onCreate() {
       SharedPreferences prefs = getSharedPreferences("com.quickit.app", Context.MODE_PRIVATE);
       login = prefs.getBoolean("login", false);

        // cancel if already existed
        if(mTimer != null) {
            mTimer.cancel();
        } else {
            // recreate new
            mTimer = new Timer();
        }
        // schedule task
        mTimer.scheduleAtFixedRate(new TimeDisplayTimerTask(), 0, NOTIFY_INTERVAL);
    }

    public class TimeDisplayTimerTask extends TimerTask {
        @Override

            public void run() {
                // run on another thread
                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        if(login) {
                            checkUpdates();
                        }
                    }
                });
            }
        }

private void checkUpdates() {
        final SharedPreferences prefs = getSharedPreferences("com.quickit.app", Context.MODE_PRIVATE);
        final String from_id =  prefs.getInt("user", 0)+"";
        final String lastCheck =  prefs.getString("last_check", "0");

        RequestParams params = new RequestParams();
        params.put("type", "get_ask_questions");
        params.put("fromid", from_id);
        params.put("last_check", lastCheck);

        AsyncHttpClient client = new AsyncHttpClient();
        client.post(address, params, new AsyncHttpResponseHandler() {
            @Override
            public void onSuccess(String response) {
                try {
                        notification(response);
                } catch (JSONException e) {
                    e.printStackTrace();
                }

            }
        });
    }
役に立ちましたか?

解決

Your code is constantly creating a new AsyncHttpClient object every time that timer expires! If the object never finishes its work, at some point, you will run out of memory.

Since you are just periodically checking for updates, you should make the AsyncHttpClient object static and just reuse it.

Look at http://loopj.com/android-async-http/ specifically, the Recommended Usage section.

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top