android - exported - 안드로이드 path-permission




편안한 API 서비스 (8)

또한 게시물 (Config.getURL ( "login"), 값)을 치면 앱이 잠시 멈춘 것처럼 보입니다. (이상한 것 같습니다. 서비스 뒤에있는 아이디어가 다른 스레드에서 실행되는 것입니다!)

아니요 직접 스레드를 만들어야 합니다. 로컬 서비스는 기본적으로 UI 스레드에서 실행됩니다.

웹 기반 REST API를 호출하는 데 사용할 수있는 서비스를 찾고 있습니다.

기본적으로 나는 app init에서 서비스를 시작하고 싶습니다. 그런 다음 서비스에 url을 요청하고 결과를 반환하도록 요청할 수 있기를 원합니다. 그 동안 나는 진도 창 또는 비슷한 것을 표시 할 수 있기를 원합니다.

나는 IDL을 사용하는 서비스를 만들었습니다. 어딘가에는 앱 간 통신을 위해이 애플리케이션이 정말로 필요하다는 것을 알았습니다. 따라서 이러한 필요성은 없어지지만 콜백을 수행하지 않는 방법은 확실치 않습니다. 또한 post(Config.getURL("login"), values) 치면 앱이 잠시 멈춘 것처럼 보입니다. (이상한 것 같습니다. 서비스 뒤에있는 아이디어가 다른 스레드에서 실행되는 것입니다!)

현재 게시물이있는 서비스가 있고 내부에 http 메서드가 있고 AIDL 파일 (양방향 통신의 경우), ServiceManager가 시작, 중지, 바인딩 등의 서비스를 처리하며 특정 코드로 처리기를 동적으로 생성합니다 필요에 따라 콜백합니다.

나는 누군가가 나에게 완전한 코드 기반을 제공하기를 원하지 않는다. 그러나 약간의 포인터는 크게 감사 할 것이다.

코드는 (대부분) 전체 :

public class RestfulAPIService extends Service  {

final RemoteCallbackList<IRemoteServiceCallback> mCallbacks = new RemoteCallbackList<IRemoteServiceCallback>();

public void onStart(Intent intent, int startId) {
    super.onStart(intent, startId);
}
public IBinder onBind(Intent intent) {
    return binder;
}
public void onCreate() {
    super.onCreate();
}
public void onDestroy() {
    super.onDestroy();
    mCallbacks.kill();
}
private final IRestfulService.Stub binder = new IRestfulService.Stub() {
    public void doLogin(String username, String password) {

        Message msg = new Message();
        Bundle data = new Bundle();
        HashMap<String, String> values = new HashMap<String, String>();
        values.put("username", username);
        values.put("password", password);
        String result = post(Config.getURL("login"), values);
        data.putString("response", result);
        msg.setData(data);
        msg.what = Config.ACTION_LOGIN;
        mHandler.sendMessage(msg);
    }

    public void registerCallback(IRemoteServiceCallback cb) {
        if (cb != null)
            mCallbacks.register(cb);
    }
};

private final Handler mHandler = new Handler() {
    public void handleMessage(Message msg) {

        // Broadcast to all clients the new value.
        final int N = mCallbacks.beginBroadcast();
        for (int i = 0; i < N; i++) {
            try {
                switch (msg.what) {
                case Config.ACTION_LOGIN:
                    mCallbacks.getBroadcastItem(i).userLogIn( msg.getData().getString("response"));
                    break;
                default:
                    super.handleMessage(msg);
                    return;

                }
            } catch (RemoteException e) {
            }
        }
        mCallbacks.finishBroadcast();
    }
    public String post(String url, HashMap<String, String> namePairs) {...}
    public String get(String url) {...}
};

AIDL 파일 몇 개 :

package com.something.android

oneway interface IRemoteServiceCallback {
    void userLogIn(String result);
}

package com.something.android
import com.something.android.IRemoteServiceCallback;

interface IRestfulService {
    void doLogin(in String username, in String password);
    void registerCallback(IRemoteServiceCallback cb);
}

및 서비스 관리자 :

public class ServiceManager {

    final RemoteCallbackList<IRemoteServiceCallback> mCallbacks = new RemoteCallbackList<IRemoteServiceCallback>();
    public IRestfulService restfulService;
    private RestfulServiceConnection conn;
    private boolean started = false;
    private Context context;

    public ServiceManager(Context context) {
        this.context = context;
    }

    public void startService() {
        if (started) {
            Toast.makeText(context, "Service already started", Toast.LENGTH_SHORT).show();
        } else {
            Intent i = new Intent();
            i.setClassName("com.something.android", "com.something.android.RestfulAPIService");
            context.startService(i);
            started = true;
        }
    }

    public void stopService() {
        if (!started) {
            Toast.makeText(context, "Service not yet started", Toast.LENGTH_SHORT).show();
        } else {
            Intent i = new Intent();
            i.setClassName("com.something.android", "com.something.android.RestfulAPIService");
            context.stopService(i);
            started = false;
        }
    }

    public void bindService() {
        if (conn == null) {
            conn = new RestfulServiceConnection();
            Intent i = new Intent();
            i.setClassName("com.something.android", "com.something.android.RestfulAPIService");
            context.bindService(i, conn, Context.BIND_AUTO_CREATE);
        } else {
            Toast.makeText(context, "Cannot bind - service already bound", Toast.LENGTH_SHORT).show();
        }
    }

    protected void destroy() {
        releaseService();
    }

    private void releaseService() {
        if (conn != null) {
            context.unbindService(conn);
            conn = null;
            Log.d(LOG_TAG, "unbindService()");
        } else {
            Toast.makeText(context, "Cannot unbind - service not bound", Toast.LENGTH_SHORT).show();
        }
    }

    class RestfulServiceConnection implements ServiceConnection {
        public void onServiceConnected(ComponentName className, IBinder boundService) {
            restfulService = IRestfulService.Stub.asInterface((IBinder) boundService);
            try {
            restfulService.registerCallback(mCallback);
            } catch (RemoteException e) {}
        }

        public void onServiceDisconnected(ComponentName className) {
            restfulService = null;
        }
    };

    private IRemoteServiceCallback mCallback = new IRemoteServiceCallback.Stub() {
        public void userLogIn(String result) throws RemoteException {
            mHandler.sendMessage(mHandler.obtainMessage(Config.ACTION_LOGIN, result));

        }
    };

    private Handler mHandler;

    public void setHandler(Handler handler) {
        mHandler = handler;
    }
}

서비스 초기화 및 바인딩 :

// this I'm calling on app onCreate
servicemanager = new ServiceManager(this);
servicemanager.startService();
servicemanager.bindService();
application = (ApplicationState)this.getApplication();
application.setServiceManager(servicemanager);

서비스 함수 호출 :

// this lot i'm calling as required - in this example for login
progressDialog = new ProgressDialog(Login.this);
progressDialog.setMessage("Logging you in...");
progressDialog.show();

application = (ApplicationState) getApplication();
servicemanager = application.getServiceManager();
servicemanager.setHandler(mHandler);

try {
    servicemanager.restfulService.doLogin(args[0], args[1]);
} catch (RemoteException e) {
    e.printStackTrace();
}

...later in the same file...

Handler mHandler = new Handler() {
    public void handleMessage(Message msg) {

        switch (msg.what) {
        case Config.ACTION_LOGIN:

            if (progressDialog.isShowing()) {
                progressDialog.dismiss();
            }

            try {
                ...process login results...
                }
            } catch (JSONException e) {
                Log.e("JSON", "There was an error parsing the JSON", e);
            }
            break;
        default:
            super.handleMessage(msg);
        }

    }

};

또한 게시물 (Config.getURL ( "login"), 값)을 치면 앱이 잠시 멈춘 것처럼 보입니다. (이상한 것 같습니다. 서비스 뒤에있는 아이디어가 다른 스레드에서 실행되는 것입니다!)

이 경우에는 다른 스레드에서 실행되고 완료시 ui 스레드로 결과를 리턴하는 asynctask를 사용하는 것이 더 좋습니다.


Robby Pond의 솔루션은 다소 부족합니다. IntentService는 한 번에 하나의 인 텐트 만 처리하므로 한 번에 하나의 API 호출 만 할 수 있습니다. 종종 병렬 API 호출을 수행하려고합니다. 이 작업을 수행하려면 IntentService 대신 Service를 확장하고 고유 한 스레드를 만들어야합니다.


Robby는 훌륭한 답변을 제공합니다. 그러나 나는 아직도 당신이 더 많은 정보를 찾고있는 것을 볼 수 있습니다. REST API를 구현하면 쉽게 잘못된 방법으로 호출됩니다. 이 Google I / O 비디오 를 보면서 내가 잘못 된 곳을 이해할 때가 아니 었습니다. AsyncTask와 HttpUrlConnection get / put 호출을 함께 사용하는 것만 큼 간단하지 않습니다.


기본적으로 요청의 전체 관리를 잊어 버리는 데 도움이되는 또 다른 방법이 있습니다. 비동기 대기열 방법과 호출 가능 / 콜백 기반 응답을 기반으로합니다. 주요 이점은이 방법을 사용하면 전체 프로세스 (요청, 가져 오기 및 구문 분석 응답, sabe에 db)를 완전히 투명하게 만들 수 있다는 것입니다. 일단 응답 코드를 받으면 작업이 이미 완료된 것입니다. 그 후에 당신은 당신의 DB에 전화를 걸면 당신은 끝난다. 귀하의 활동이 활발하지 않을 때 어떤 일이 일어나는지에 대한 문제도 도움이됩니다. 여기서 일어날 일은 모든 데이터를 로컬 데이터베이스에 저장하지만 응답은 활동에 의해 처리되지 않는다는 것이 이상적인 방법입니다.

나는 여기에 일반적인 접근법에 대해 썼다. http://ugiagonzalez.com/2012/07/02/theres-life-after-asynctasks-in-android/

앞으로의 게시물에 특정 샘플 코드를 넣을 것입니다. 도움이되기를 바랍니다. 접근 방식을 공유하고 잠재적 인 의문이나 문제점을 해결하기 위해 저에게 연락하십시오.



버튼의 이벤트 onItemClicked ()에서 서비스를 시작하려고한다고 가정 해 봅시다. 이 경우 Receiver 메커니즘이 작동하지 않습니다. -
a) OnItemClicked ()에서 Receiver를 Intent extra처럼 서비스에 전달했습니다.
b) 활동이 배경으로 이동합니다. onPause ()에서 Activity가 누출되지 않도록 ResultReceiver 내의 수신기 참조를 null로 설정했습니다.
c) 활동이 파괴됩니다.
d) 활동이 다시 생성됩니다. 그러나이 시점에서 서비스는 해당 수신자 참조가 손실되어 Activity에 대한 콜백을 수행 할 수 없습니다.
이러한 시나리오에서는 제한된 브로드 캐스트 또는 PendingIntent의 메커니즘이 더 유용 할 것 같습니다. 서비스에서 알림 활동을 참조하십시오.


Android REST 클라이언트 애플리케이션을 개발 하는 것은 나에게 멋진 자료였습니다. 화자는 코드를 보여주지 않으며, 단지 안드로이드에 단단한 Rest Api를 넣을 때 디자인 고려 사항과 기술을 설명합니다. 당신의 팟 캐스트 일종의 사람이든 아니든, 적어도 하나는 듣는 것이 좋겠지 만, 개인적으로 나는 지금까지 네 번이나 다섯 번 듣고 있었고 아마 다시 듣게 될 것입니다.

Android REST 클라이언트 애플리케이션 개발
저자 : Virgil Dobjanschi
기술:

이 세션에서는 Android 플랫폼에서 RESTful 애플리케이션을 개발하기위한 아키텍처 고려 사항을 제시합니다. Android 플랫폼에 고유 한 디자인 패턴, 플랫폼 통합 및 성능 문제에 중점을 둡니다.

그리고 리팩터링을해야했던 API의 첫 번째 버전에서 내가 작성하지 않은 많은 고려 사항이 있습니다.





rest