편안한 API 서비스
웹 기반 REST API를 호출하는 데 사용할 수있는 서비스를 만들고 싶습니다.
기본적으로 앱 init에서 서비스를 시작하고 싶을 때 해당 서비스에 URL을 요청하고 결과를 반환하도록 요청하고 싶습니다. 그 동안 진행률 창이나 비슷한 것을 표시하고 싶습니다.
나는 현재 IDL을 사용하는 서비스를 만들었습니다. 앱 간 통신을 위해 실제로 필요한 부분을 읽었 으므로이 부분을 제거해야하지만 콜백을 수행하는 방법이 확실하지 않다고 생각하십시오. 또한 post(Config.getURL("login"), values)
응용 프로그램을 칠 때 응용 프로그램이 잠시 일시 중지 된 것처럼 보입니다 (이상한 것으로 보입니다-서비스의 아이디어는 다른 스레드에서 실행된다는 생각이었습니다!)
현재 내부에 post 및 get 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);
}
}
};
서비스가 응용 프로그램의 일부가 될 경우 필요 이상으로 복잡해집니다. RESTful 웹 서비스에서 일부 데이터를 가져 오는 간단한 유스 케이스가 있으므로 ResultReceiver 및 IntentService 를 조사 해야합니다 .
이 Service + ResultReceiver 패턴은 조치를 수행하려고 할 때 startService () 를 사용하여 서비스를 시작하거나 바인딩하여 작동합니다. 인 텐트의 추가 항목을 통해 ResultReceiver (활동)를 수행하고 전달할 조작을 지정할 수 있습니다.
서비스에서 onHandleIntent 를 구현 하여 Intent에 지정된 작업을 수행합니다. 작업이 완료되면 전달 된 ResultReceiver를 사용하여 onReceiveResult 가 호출 될 활동에 메시지를 다시 보냅니다 .
예를 들어, 웹 서비스에서 일부 데이터를 가져 오려고합니다.
- 인 텐트를 작성하고 startService를 호출하십시오.
- 서비스의 작업이 시작되고 시작되었다는 메시지를 활동에 보냅니다.
- 활동은 메시지를 처리하고 진행 상황을 보여줍니다.
- 서비스가 작업을 마치고 일부 데이터를 활동으로 다시 보냅니다.
- 활동이 데이터를 처리하고 목록보기에 넣습니다.
- 서비스는 완료되었다는 메시지를 보내며 자체적으로 종료됩니다.
- 활동은 완료 메시지를 받고 진행 대화 상자를 숨 깁니다.
코드 기반을 원하지 않는다고 언급했지만 오픈 소스 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.Receiver를 구현하기 위해 편집 됨
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 클라이언트 애플리케이션 개발
작성자 : Virgil Dobjanschi
설명 :
이 세션에서는 Android 플랫폼에서 RESTful 애플리케이션을 개발하기위한 아키텍처 고려 사항을 제시합니다. Android 플랫폼과 관련된 디자인 패턴, 플랫폼 통합 및 성능 문제에 중점을 둡니다.
그리고 제 API의 첫 번째 버전에서 실제로 고려하지 않은 많은 고려 사항이 있습니다.
또한 post (Config.getURL ( "login"), values)를 눌렀을 때 앱이 잠시 일시 중지 된 것 같습니다.
스레드를 직접 만들 필요는 없습니다 . 로컬 서비스는 기본적으로 UI 스레드에서 실행됩니다.
@Martyn은 전체 코드를 원하지 않지만이 주석은이 질문에 적합하다고 생각합니다.
모든 안드로이드 개발자가 고려해야 할 10 가지 오픈 소스 안드로이드 앱
Android 용 Foursquared는 공개 소스 이며 foursquare REST API와 상호 작용하는 흥미로운 코드 패턴을 가지고 있습니다.
REST 클라이언트 Retrofit을 적극 권장합니다 .
이 잘 작성된 블로그 게시물이 매우 유용하다는 것을 알았습니다. 간단한 예제 코드도 포함되어 있습니다. 저자는 Retrofit 을 사용하여 네트워크 호출을하고 Otto 는 데이터 버스 패턴을 구현합니다.
http://www.mdswanson.com/blog/2014/04/07/durable-android-rest-clients.html
모든 기능을 통합 한 독립형 클래스의 방향으로 모든 것을 지시하고 싶었습니다.
http://github.com/StlTenny/RestService
요청을 비 블로킹으로 실행하고 구현하기 쉬운 처리기로 결과를 반환합니다. 예제 구현도 제공됩니다.
버튼의 이벤트-onItemClicked ()에서 서비스를 시작한다고 가정 해 봅시다. 이 경우 수신자 메커니즘은 작동하지 않습니다.
a) 나는 onItemClicked ()에서 수신자를 서비스에 전달했습니다.
b) 활동이 배경으로 이동합니다. onPause ()에서 ResultReceiver 내의 수신자 참조를 활동 누출을 피하기 위해 null로 설정했습니다.
c) 활동이 파괴된다.
d) 활동이 다시 작성됩니다. 그러나이 시점에서 서비스는 수신자 참조가 유실되어 활동에 콜백 할 수 없습니다.
제한된 방송 또는 PendingIntent의 메커니즘은 이러한 시나리오에서 더 유용 합니다. 서비스에서 활동 알림을 참조하십시오.
Robby Pond의 솔루션에는 다소 부족한 점이 있습니다. IntentService는 한 번에 하나의 의도 만 처리하므로 한 번에 하나의 API 호출 만 허용합니다. 종종 병렬 API 호출을 수행하려고합니다. 이 작업을 수행하려면 IntentService 대신 Service를 확장하고 자체 스레드를 만들어야합니다.
또한 post (Config.getURL ( "login"), values)를 눌렀을 때 앱이 잠시 일시 중지 된 것 같습니다.
이 경우 다른 스레드에서 실행되고 완료되면 ui 스레드로 결과를 반환하는 asynctask를 사용하는 것이 좋습니다.
여기에는 기본적으로 요청의 전체 관리를 잊어 버리는 데 도움이되는 또 다른 접근법이 있습니다. 비동기 대기열 방법과 콜 러블 / 콜백 기반 응답을 기반으로합니다. 주요 장점은이 방법을 사용하면 전체 프로세스 (요청, 가져 오기 및 구문 분석, save와 db)를 완전히 투명하게 만들 수 있다는 것입니다. 응답 코드를 받으면 작업이 이미 완료된 것입니다. 그 후 당신은 당신의 DB를 호출해야하고 완료되었습니다. 활동이 활성화되지 않은 경우 발생하는 문제에 대한 도움을줍니다. 여기서 일어날 모든 데이터는 로컬 데이터베이스에 저장되지만 응답은 활동에 의해 처리되지 않으므로 이상적인 방법입니다.
나는 여기에 일반적인 접근법에 대해 썼습니다 : http://ugiagonzalez.com/2012/07/02/theres-life-after-asynctasks-in-android/
다음 게시물에 특정 샘플 코드를 넣을 것입니다. 그것이 도움이되기를 바랍니다. 접근법을 공유하고 잠재적 인 의심이나 문제를 해결하기 위해 저에게 연락하십시오.
Robby는 훌륭한 답변을 제공하지만 여전히 자세한 정보를 찾고 있음을 알 수 있습니다. REST API 호출을 쉽지만 쉬운 방법으로 구현했습니다. 내가 잘못한 부분을 이해 한이 Google I / O 비디오 를 볼 때까지는 아니 었 습니다. AsyncTask를 HttpUrlConnection get / put 호출과 결합하는 것만 큼 간단하지 않습니다.
참고 URL : https://stackoverflow.com/questions/3197335/restful-api-service
'IT story' 카테고리의 다른 글
상대적 가져 오기에서 최상위 패키지 오류를 넘어서 (0) | 2020.04.24 |
---|---|
JavaScript 문자열은 변경할 수 없습니까? (0) | 2020.04.24 |
새 탭 / 새 창이 열리면 Chrome 개발자 도구를 자동으로 엽니 다 (0) | 2020.04.24 |
nohup과 앰퍼샌드의 차이점은 무엇입니까 (0) | 2020.04.24 |
HttpModule과 HttpClientModule의 차이점 (0) | 2020.04.24 |