android GCM Error…

안드로이드 개발시 이런 애러가 나올 경우가 있다.

원인을 찾지 못해서  gcm.jar이 deprecated가 되었다고 해서 모두 google cloud messaging  라이브러리를 사용했는데 해당 에러가 동일하게 발생했다.

06-12 14:44:43.553: E/BroadcastReceiver(27011): java.lang.RuntimeException: BroadcastReceiver trying to return result during a non-ordered broadcast
06-12 14:44:43.553: E/BroadcastReceiver(27011): 	at android.content.BroadcastReceiver.checkSynchronousHint(BroadcastReceiver.java:783)
06-12 14:44:43.553: E/BroadcastReceiver(27011): 	at android.content.BroadcastReceiver.setResultCode(BroadcastReceiver.java:549)
06-12 14:44:43.553: E/BroadcastReceiver(27011): 	at com.kamsung.anvang.gcm.GcmBroadcastReceiver.onReceive(GcmBroadcastReceiver.java:30)
06-12 14:44:43.553: E/BroadcastReceiver(27011): 	at android.app.ActivityThread.handleReceiver(ActivityThread.java:2535)
06-12 14:44:43.553: E/BroadcastReceiver(27011): 	at android.app.ActivityThread.access$1600(ActivityThread.java:165)
06-12 14:44:43.553: E/BroadcastReceiver(27011): 	at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1402)
06-12 14:44:43.553: E/BroadcastReceiver(27011): 	at android.os.Handler.dispatchMessage(Handler.java:99)
06-12 14:44:43.553: E/BroadcastReceiver(27011): 	at android.os.Looper.loop(Looper.java:176)
06-12 14:44:43.553: E/BroadcastReceiver(27011): 	at android.app.ActivityThread.main(ActivityThread.java:5455)
06-12 14:44:43.553: E/BroadcastReceiver(27011): 	at java.lang.reflect.Method.invokeNative(Native Method)
06-12 14:44:43.553: E/BroadcastReceiver(27011): 	at java.lang.reflect.Method.invoke(Method.java:525)
06-12 14:44:43.553: E/BroadcastReceiver(27011): 	at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1209)
06-12 14:44:43.553: E/BroadcastReceiver(27011): 	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1025)
06-12 14:44:43.553: E/BroadcastReceiver(27011): 	at dalvik.system.NativeStart.main(Native Method)

원인은 삼성 런처를 위한 코드를 넣었을  때 발생했다.

아래와 같은 코드를 사용했을 경우.

Intent badgeIntent = new Intent("android.intent.action.BADGE_COUNT_UPDATE");
badgeIntent.putExtra("badge_count", notiCnt);
badgeIntent.putExtra("badge_count_package_name", context.getPackageName());
badgeIntent.putExtra("badge_count_class_name", getLauncherClassName(context));
context.sendBroadcast(badgeIntent);

위의 코드로 뱃지를 업데이트 했을 경우 broadcast 한 인텐트를 지금 개발하는 앱에서 받아서 문제가 생긴다.

 

이럴때는 해당 인텐트를 예외처리 해서 처리할 수 있다.

아래 코드는 필자가 사용한 코드다.

참고 해서 인텐트를 확인해보자.

인텐트의 key 와 value 는 다를 수 있으니 한번 찍어서 확인해보자

내가 원하는 인텐트가 아닐 경우를 찾아내서 예외처리를 해준다면 에러가 나지 않을 것이다.

@Override
public void onReceive(Context context, Intent intent) {
    Bundle bundle = intent.getExtras();
    // registration_id가 있는 경우만 receive 한다.
    boolean foundexceptionKey = false;
    for (String key : bundle.keySet()) {
	Object value = bundle.get(key);
	if (key.equals("CMD") && value.toString().equals("RST_FULL")) foundexceptionKey = true;
    }
    if (foundexceptionKey) return; 
    // Explicitly specify that GcmIntentService will handle the intent.
    ComponentName comp = new ComponentName(context.getPackageName(),
    GcmIntentService.class.getName());
    // Start the service, keeping the device awake while it is launching.
    startWakefulService(context, intent.setComponent(comp));
    setResultCode(Activity.RESULT_OK);
}

 

[android] AsyncTask too late problem..

안드로이드 AsyncTask

android AsyncTask 는 안드로이드에서 자주쓰고, 자주 보는 클래스이다.

우리 회사에서 서비스중인 안드로이드 앱에서도 AsyncTask를 많이 쓰고 있다.

그런데, 회사에서 서비스 중인 안드로이드가 너무 느려서 원인을 찾기위해 이것저것 로그를 찍어본 결과.
AsyncTask를 실행하고, doInBackground() 호출이 너무 느렸다. 무려 3초에서 4초정도 딜레이가 되고 있었다.

원인을 열심히 찾아봤는데 허니콤 이전 버전에선 AsyncTask의 개수제한이 있었다.

core pool size와 max pool size가 있었던것 같은데, 필요하면 아래 글 참고 하면 될듯.

AsyncTask 참고1
AsyncTask 참고2

수정하려고 봤더니 여기저기 AsyncTask를 마구마구 쓰고 있고, 여러 depth에 걸처서 부르는 로직도 있어서 수정 규모가 너무 크다고 판단.

일단 심플하게 thread를 이용해서 AsyncTask역할을 그대로 하는 코드를 만들었다.

Why?

AsyncTask 자리에 그대로 바꿔치기 하기 위함이다.
일단 이것으로 속도확보를 했으니 다음 차례는 쓰레드 풀이든 스케쥴링이던 하면 될 듯하고. 일단 지금은 스케쥴러를 별도로 만들어 관리하도록 수정.

혹시 몰라서 여기에 올려놓는다. 자료 백업 목적 및 필요한 사람들이 있을지도 모르니 공유의 목적도…

/****
 * title: AsyncThread
 * description: Simple thread extension like AsyncTask. 
 * 				But the AsyncThread is non atomic no use thread pool.
 *
 * author: weep
 * blog: weeppp.com
 * email: ktg@weeppp.com
 * Copyright (c) 2015 Teukgeon, Kwon. All rights reserved.
 ****/

package com.weeppp.tklib;

import android.os.Handler;
import android.os.Message;

public abstract class AsyncThread<Params, Progress, Result> extends Thread implements Runnable {
    protected void onPreExecute() {};
    abstract protected Result doInBackground(Params... params);
    protected void onPostExecute(Result result) {};
    protected void onCancell() {};

    Params[] params;
    static final int MESSAGE_POST_RESULT = 30;

    enum Status {
        PENDING,
        RUNNING,
        FINISHED
    }

    private Status status = Status.PENDING;
    private boolean isCancel = false;
    final InternalHandler internalHandler = new InternalHandler();

    public AsyncThread()
    {

    }

    public AsyncThread<Params, Progress, Result> execute(Params... params)
    {
        if (status != Status.PENDING) {
            switch (status) {
                case RUNNING:
                    throw new IllegalStateException("Cannot execute task:"
                            + " the task is already running.");
                case FINISHED:
                    throw new IllegalStateException("Cannot execute task:"
                            + " the task has already been executed "
                            + "(a task can be executed only once)");
                default:
                    break;
            }
        }
        status = Status.RUNNING;

        this.params = params;
        onPreExecute();
        start();
        return this;
    }

    public final Status getStatus() {
        return status;
    }

    public final boolean isCancelled() {
        return isCancel;
    }

    public final boolean cancel() {
        isCancel = true;
        return isCancel;
    }

    public final boolean cancel(boolean mayInterruptIfRunning) {
        isCancel = true;
        return isCancel;
    }

    public void run()
    {
        final Result result = doInBackground(params);

        Message msg = internalHandler.obtainMessage(MESSAGE_POST_RESULT);
        msg.obj = new AsyncResult(this, result);
        internalHandler.sendMessage(msg);
    }

    protected void onCancell(Result result)
    {
        onCancell();
    }

    private void finish(Result result)
    {
        if (isCancelled()) {
            onCancell(result);
        }
        else {
            onPostExecute(result);
        }
        status = Status.FINISHED;
    }

    private static class InternalHandler extends Handler {
        @SuppressWarnings({"unchecked"})
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case MESSAGE_POST_RESULT:
                    AsyncResult aResult = (AsyncResult)msg.obj;
                    aResult.thread.finish(aResult.result);
                    break;
            }
        }
    }

    @SuppressWarnings({"rawtypes"})
    static class AsyncResult {
        final AsyncThread thread;
        final Object result;
        public AsyncResult(AsyncThread thread, Object result)
        {
            this.thread = thread;
            this.result = result;
        }
    }
}