programing

Restful API 서비스

lastmoon 2023. 7. 31. 21:49
반응형

Restful API 서비스

웹 기반 REST API로 통화할 수 있는 서비스를 찾고 있습니다.

기본적으로 앱에서 서비스를 시작한 다음 해당 서비스에 URL을 요청하고 결과를 반환하고 싶습니다.그 사이에 진행률 창이나 비슷한 것을 표시할 수 있기를 원합니다.

저는 현재 IDL을 사용하는 서비스를 만들었습니다. 저는 어디선가 이것이 정말로 필요하다는 것을 읽었기 때문에, 이것들이 제거되어야 한다고 생각하지만 그것 없이 콜백을 하는 방법을 확신하지 못합니다.또한 내가 그것을 쳤을 때.post(Config.getURL("login"), values)앱이 잠시 정지하는 것 같습니다(이상하게도 - 서비스 뒤의 아이디어는 다른 스레드에서 실행된다는 것이라고 생각했습니다!)

현재 저는 post와 get http 메소드가 포함된 서비스를 내부에 가지고 있으며, AIDL 파일 몇 개(양방향 통신용), 서비스 시작, 중지, 바인딩 등을 처리하는 서비스 관리자를 보유하고 있으며, 필요에 따라 콜백을 위한 특정 코드를 가진 핸들러를 동적으로 만들고 있습니다.

나는 누군가가 나에게 작업할 완전한 코드 베이스를 주기를 원하지 않지만, 몇몇 포인터들은 매우 감사할 것입니다.

코드 입력(대부분):

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;
    }
}

서비스 init 및 bind:

// 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);
        }

    }

};

서비스가 애플리케이션의 일부가 될 경우 필요한 것보다 훨씬 더 복잡해집니다.RESTful 웹 서비스에서 데이터를 가져오는 간단한 사용 사례가 있으므로 ResultReceiverIntentService를 조사해야 합니다.

이 서비스 + 결과 수신기 패턴은 일부 작업을 수행하려는 경우 startService()로 서비스를 시작하거나 바인딩하여 작동합니다.수행할 작업을 지정하고 의도에 있는 추가 작업을 통해 결과 수신기(활동)를 전달할 수 있습니다.

서비스에서 HandleIntent에 구현하여 의도에 지정된 작업을 수행합니다.작업이 완료되면 전달된 ResultReceiver를 사용하여 ReceiveResult에서 호출될 활동에 메시지를 다시 보냅니다.

예를 들어, 웹 서비스에서 데이터를 가져오려고 합니다.

  1. 의도를 생성하고 startService를 호출합니다.
  2. 서비스의 작업이 시작되고 작업이 시작되었다는 메시지를 활동에 보냅니다.
  3. 활동이 메시지를 처리하고 진행률을 표시합니다.
  4. 서비스가 작업을 완료하고 일부 데이터를 작업에 다시 보냅니다.
  5. 활동이 데이터를 처리하고 목록 보기에 넣습니다.
  6. 서비스는 완료되었다는 메시지를 보내고 스스로 목숨을 끊습니다.
  7. 활동은 마침 메시지를 받고 진행 대화상자를 숨깁니다.

당신이 코드베이스를 원하지 않는다고 말한 것을 알지만, 오픈 소스 Google I/O 2010 앱은 제가 설명하는 방식으로 서비스를 사용합니다.

샘플 코드를 추가하도록 업데이트됨:

활동.

public class HomeActivity extends Activity implements MyResultReceiver.Receiver {

    public MyResultReceiver mReceiver;

    public void onCreate(Bundle savedInstanceState) {
        mReceiver = new MyResultReceiver(new Handler());
        mReceiver.setReceiver(this);
        ...
        final Intent intent = new Intent(Intent.ACTION_SYNC, null, this, QueryService.class);
        intent.putExtra("receiver", mReceiver);
        intent.putExtra("command", "query");
        startService(intent);
    }

    public void onPause() {
        mReceiver.setReceiver(null); // clear receiver so no leaks.
    }

    public void onReceiveResult(int resultCode, Bundle resultData) {
        switch (resultCode) {
        case RUNNING:
            //show progress
            break;
        case FINISHED:
            List results = resultData.getParcelableList("results");
            // do something interesting
            // hide progress
            break;
        case ERROR:
            // handle the error;
            break;
    }
}

서비스:

public class QueryService extends IntentService {
    protected void onHandleIntent(Intent intent) {
        final ResultReceiver receiver = intent.getParcelableExtra("receiver");
        String command = intent.getStringExtra("command");
        Bundle b = new Bundle();
        if(command.equals("query") {
            receiver.send(STATUS_RUNNING, Bundle.EMPTY);
            try {
                // get some data or something           
                b.putParcelableArrayList("results", results);
                receiver.send(STATUS_FINISHED, b)
            } catch(Exception e) {
                b.putString(Intent.EXTRA_TEXT, e.toString());
                receiver.send(STATUS_ERROR, b);
            }    
        }
    }
}

ResultReceiver 확장 - MyResultReceiver를 구현하려고 편집되었습니다.수신기

public class MyResultReceiver implements ResultReceiver {
    private Receiver mReceiver;

    public MyResultReceiver(Handler handler) {
        super(handler);
    }

    public void setReceiver(Receiver receiver) {
        mReceiver = receiver;
    }

    public interface Receiver {
        public void onReceiveResult(int resultCode, Bundle resultData);
    }

    @Override
    protected void onReceiveResult(int resultCode, Bundle resultData) {
        if (mReceiver != null) {
            mReceiver.onReceiveResult(resultCode, resultData);
        }
    }
}

Android REST 클라이언트 애플리케이션을 개발하는 것은 저에게 훌륭한 자원이었습니다.화자는 코드를 보여주지 않고 안드로이드에 견고한 Rest API를 구축하는 데 있어 디자인 고려 사항과 기술을 검토할 뿐입니다.팟캐스트를 하시는 분이라면 한 번쯤 들어보시는 것이 좋겠지만, 개인적으로 지금까지 4~5번 정도 들었고 아마 다시 들을 것 같습니다.

Android REST 클라이언트 애플리케이션 개발
: 버질 도반스키
설명:

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

그리고 제 api의 첫 번째 버전에서 고려하지 않은 사항이 너무 많아서 리팩터링해야 했습니다.

또한 게시물(Config.getURL("login"), 값)을 누르면 앱이 잠시 일시 중지되는 것 같습니다(이상하게 보입니다 - 서비스 뒤에 있는 아이디어는 다른 스레드에서 실행된다는 것이었습니다!)

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

@Martyn이 전체 코드를 원하지 않는다는 것을 알지만, 이 주석은 이 질문에 적합하다고 생각합니다.

모든 Android 개발자가 조사해야 하는 10가지 오픈 소스 Android 앱

Android용 4제곱은 오픈 소스이며, 4제곱 REST API와 상호 작용하는 흥미로운 코드 패턴을 가지고 있습니다.

REST 고객의 Retrofit을 적극 추천합니다.

저는 이 잘 작성된 블로그 게시물이 매우 도움이 된다는 것을 알게 되었고, 간단한 예제 코드도 포함하고 있습니다.필자는 Retrofit을 사용하여 네트워크 호출을 하고 Otto를 사용하여 데이터 버스 패턴을 구현합니다.

http://www.mdswanson.com/blog/2014/04/07/durable-android-rest-clients.html

모든 기능을 통합한 독립형 클래스의 방향을 알려드리고자 합니다.

http://github.com/StlTenny/RestService

요청을 비차단으로 실행하고 구현하기 쉬운 처리기로 결과를 반환합니다.구현 사례도 함께 제공됩니다.

예를 들어 버튼의 ItemClicked()에 있는 이벤트에서 서비스를 시작하려고 합니다.이 경우 다음과 같은 이유로 수신기 메커니즘이 작동하지 않습니다.
ItemClicked()에서 서비스(Intent extra에서와 같이)로 수신기를 전달했습니다.
활동이 백그라운드로 이동합니다.OnPause()에서 활동 누출을 방지하기 위해 ResultReceiver 내의 수신기 참조를 null로 설정합니다.
활동이 파괴됩니다.
활동이 다시 작성됩니다.그러나 이 시점에서 서비스는 해당 수신자 참조가 손실되므로 활동에 콜백할 수 없습니다.
제한된 브로드캐스트 또는 보류 중인 메커니즘이러한 시나리오에서는 의도가 더 유용한 것으로 보입니다. 서비스에서 활동 알림을 참조하십시오.

Robby Pond의 솔루션은 다소 부족합니다. IntentService는 한 번에 하나의 의도만 처리하므로 한 번에 하나의 API 호출만 허용합니다.병렬 API 호출을 수행하려는 경우가 많습니다.이 작업을 수행하려면 IntentService 대신 서비스를 확장하고 자신만의 스레드를 만들어야 합니다.

또한 게시물(Config.getURL("login"), 값)을 누르면 앱이 잠시 일시 중지되는 것 같습니다(이상하게 보입니다 - 서비스 뒤에 있는 아이디어는 다른 스레드에서 실행된다는 것이었습니다!)

이 경우 다른 스레드에서 실행되고 완료 시 결과를 UI 스레드로 반환하는 비동기 작업을 사용하는 것이 좋습니다.

Robby는 훌륭한 답변을 제공하지만, 여전히 더 많은 정보를 찾고 있는 것을 볼 수 있습니다.나는 REST API 호출을 쉽지만 잘못된 방법으로 구현했습니다.이 Google I/O 비디오를 보고 나서야 제가 어디서 잘못되었는지 이해했습니다.비동기 작업을 HttpUrlConnection get/put 호출과 결합하는 것만큼 간단하지 않습니다.

여기에는 기본적으로 요청의 전체 관리를 잊도록 도와주는 또 다른 접근 방식이 있습니다.비동기 대기열 방법 및 콜 가능/콜백 기반 응답을 기반으로 합니다.주요 장점은 이 방법을 사용하면 전체 프로세스(요청, 응답 가져오기 및 구문 분석, 안전한 DB)를 완전히 투명하게 만들 수 있다는 것입니다.응답 코드를 받으면 작업이 이미 완료됩니다.그런 다음 DB에 전화를 걸면 완료됩니다.활동이 활발하지 않을 때 발생하는 문제에도 도움이 됩니다.여기서 수행되는 작업은 모든 데이터를 로컬 데이터베이스에 저장하지만 작업에 의해 응답이 처리되지 않는 것입니다.

언급URL : https://stackoverflow.com/questions/3197335/restful-api-service

반응형