Saya ingin membuat layanan yang dapat saya gunakan untuk membuat panggilan ke REST API berbasis web.
Pada dasarnya saya ingin memulai layanan pada aplikasi init maka saya ingin dapat meminta layanan itu untuk meminta url dan mengembalikan hasilnya. Sementara itu saya ingin dapat menampilkan jendela progres atau yang serupa.
Saya telah membuat layanan saat ini yang menggunakan IDL, saya telah membaca di suatu tempat bahwa Anda hanya benar-benar membutuhkan ini untuk komunikasi lintas aplikasi, jadi anggap ini perlu dihapus tetapi tidak yakin bagaimana melakukan panggilan balik tanpa itu. Juga ketika saya menekan post(Config.getURL("login"), values)
aplikasi tampaknya berhenti untuk sementara waktu (tampak aneh - mengira ide di balik layanan adalah bahwa ia berjalan di utas yang berbeda!)
Saat ini saya memiliki layanan dengan posting dan mendapatkan metode http di dalamnya, beberapa file AIDL (untuk komunikasi dua arah), ServiceManager yang berhubungan dengan memulai, menghentikan, mengikat dll untuk layanan dan saya secara dinamis membuat Handler dengan kode tertentu untuk panggilan balik sesuai kebutuhan.
Saya tidak ingin ada yang memberi saya basis kode yang lengkap untuk dikerjakan, tetapi beberapa petunjuk akan sangat dihargai.
Kode dalam (kebanyakan) lengkap:
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) {...}
};
Beberapa file AIDL:
package com.something.android
oneway interface IRemoteServiceCallback {
void userLogIn(String result);
}
dan
package com.something.android
import com.something.android.IRemoteServiceCallback;
interface IRestfulService {
void doLogin(in String username, in String password);
void registerCallback(IRemoteServiceCallback cb);
}
dan manajer layanan:
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;
}
}
Layanan init dan ikat:
// this I'm calling on app onCreate
servicemanager = new ServiceManager(this);
servicemanager.startService();
servicemanager.bindService();
application = (ApplicationState)this.getApplication();
application.setServiceManager(servicemanager);
panggilan fungsi layanan:
// 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);
}
}
};
sumber
Jawaban:
Jika layanan Anda akan menjadi bagian dari aplikasi Anda, maka Anda membuatnya menjadi jauh lebih kompleks daripada yang seharusnya. Karena Anda memiliki kasus penggunaan sederhana untuk mendapatkan beberapa data dari Layanan Web RESTful , Anda harus melihat dalam ResultReceiver dan IntentService .
Pola Service + ResultReceiver ini berfungsi dengan memulai atau mengikat ke layanan dengan startService () ketika Anda ingin melakukan beberapa tindakan. Anda dapat menentukan operasi yang akan dilakukan dan lulus dalam ResultReceiver Anda (aktivitas) melalui ekstra di Intent.
Di layanan Anda menerapkan onHandleIntent untuk melakukan operasi yang ditentukan dalam Intent. Ketika operasi selesai, Anda menggunakan yang diteruskan dalam ResultReceiver untuk mengirim pesan kembali ke Aktivitas di mana titik onReceiveResult akan dipanggil.
Jadi misalnya, Anda ingin menarik beberapa data dari Layanan Web Anda.
Saya tahu Anda menyebutkan bahwa Anda tidak menginginkan basis kode tetapi aplikasi Google I / O 2010 open source menggunakan layanan dengan cara yang saya uraikan ini.
Diperbarui untuk menambahkan kode sampel:
Kegiatannya.
Layanan:
Ekstensi ResultReceiver - diedit untuk mengimplementasikan MyResultReceiver.Receiver
sumber
stopSelf
jika Anda subkelasIntentService
karena jika Anda melakukannya, Anda akan kehilangan permintaan yang tertunda karena hal yang samaIntentService
.IntentService
akan membunuh dirinya sendiri ketika tugas selesai, jadithis.stopSelf()
tidak perlu.Mengembangkan aplikasi klien Android REST telah menjadi sumber yang luar biasa bagi saya. Pembicara tidak menunjukkan kode apa pun, ia hanya membahas pertimbangan desain dan teknik dalam mengumpulkan batu padat Rest Api di android. Jika podcast Anda agak orang atau tidak, saya sarankan memberikan yang ini setidaknya satu dengarkan tetapi, secara pribadi saya sudah mendengarkannya 4 atau lima kali sejauh ini dan saya mungkin akan mendengarkannya lagi.
Mengembangkan aplikasi klien Android REST
Penulis: Virgil Dobjanschi
Deskripsi:
Sesi ini akan menyajikan pertimbangan arsitektur untuk mengembangkan aplikasi RESTful di platform Android. Ini berfokus pada pola desain, integrasi platform, dan masalah kinerja khusus untuk platform Android.
Dan ada begitu banyak pertimbangan yang saya benar-benar tidak membuat versi pertama dari api saya bahwa saya harus refactor
sumber
Tidak, Anda harus membuat utas sendiri, layanan Lokal berjalan pada utas UI secara default.
sumber
Saya tahu @ Martyn tidak ingin kode lengkap, tapi saya pikir penjelasan ini bagus untuk pertanyaan ini:
10 Aplikasi Android Sumber Terbuka yang harus dilihat oleh setiap pengembang Android
Foursquared untuk Android adalah open-source , dan memiliki pola kode yang menarik berinteraksi dengan foursquare REST API.
sumber
Saya akan sangat menyarankan REST klien Retrofit .
Saya telah menemukan posting blog yang ditulis dengan baik ini sangat membantu, juga berisi kode contoh sederhana. Penulis menggunakan Retrofit untuk melakukan panggilan jaringan dan Otto untuk menerapkan pola bus data:
http://www.mdswanson.com/blog/2014/04/07/durable-android-rest-clients.html
sumber
Hanya ingin mengarahkan Anda semua ke arah kelas mandiri yang saya putar yang menggabungkan semua fungsi.
http://github.com/StlTenny/RestService
Itu mengeksekusi permintaan sebagai non-blocking, dan mengembalikan hasil dalam handler yang mudah diimplementasikan. Bahkan hadir dengan contoh implementasi.
sumber
Katakanlah saya ingin memulai layanan pada acara - onItemClicked () dari sebuah tombol. Mekanisme Receiver tidak akan berfungsi dalam kasus itu karena: -
a) Saya meneruskan Receiver ke layanan (seperti pada Intent extra) dari onItemClicked ()
b) Aktivitas bergerak ke latar belakang. Di onPause () saya mengatur referensi penerima di dalam ResultReceiver ke nol untuk menghindari bocornya Aktivitas.
c) Aktivitas dihancurkan.
d) Aktivitas akan dibuat lagi. Namun pada titik ini Layanan tidak akan dapat membuat panggilan balik ke Aktivitas karena referensi penerima hilang.
Mekanisme siaran terbatas atau PendingIntent tampaknya lebih berguna dalam skenario seperti itu - lihat aktivitas Beritahu dari layanan
sumber
Perhatikan bahwa solusi dari Robby Pond entah bagaimana kurang: dengan cara ini Anda hanya mengizinkan untuk melakukan satu panggilan api sekaligus karena IntentService hanya menangani satu maksud pada satu waktu. Seringkali Anda ingin melakukan panggilan api paralel. Jika Anda ingin melakukan ini, Anda harus memperluas Layanan alih-alih IntentService dan membuat utas sendiri.
sumber
Dalam hal ini lebih baik menggunakan asynctask, yang berjalan pada utas yang berbeda dan mengembalikan hasilnya ke utas setelah selesai.
sumber
Ada pendekatan lain di sini yang pada dasarnya membantu Anda melupakan seluruh pengelolaan permintaan. Ini didasarkan pada metode antrian async dan respons berbasis callable / callback. Keuntungan utama adalah bahwa dengan menggunakan metode ini Anda akan dapat membuat seluruh proses (permintaan, dapatkan dan tanggapan parse, sabe ke db) sepenuhnya transparan untuk Anda. Setelah Anda mendapatkan kode respons, pekerjaan sudah dilakukan. Setelah itu Anda hanya perlu melakukan panggilan ke db Anda dan Anda selesai. Ini membantu juga dengan masalah apa yang terjadi ketika aktivitas Anda tidak aktif. Apa yang akan terjadi di sini adalah bahwa Anda akan menyimpan semua data Anda di basis data lokal Anda tetapi responsnya tidak akan diproses oleh aktivitas Anda, itu cara yang ideal.
Saya menulis tentang pendekatan umum di sini http://ugiagonzalez.com/2012/07/02/theres-life-after-asynctasks-in-android/
Saya akan meletakkan kode sampel tertentu di posting mendatang. Semoga ini bisa membantu, jangan ragu untuk menghubungi saya untuk berbagi pendekatan dan menyelesaikan potensi keraguan atau masalah.
sumber
Robby memberikan jawaban yang bagus, meskipun saya dapat melihat Anda masih mencari informasi lebih lanjut. Saya menerapkan REST api memanggil cara TAPI mudah salah. Tidak sampai menonton video Google I / O ini saya mengerti di mana saya salah. Ini tidak sesederhana mengumpulkan AsyncTask dengan panggilan panggilan / panggilan HttpUrlConnection.
sumber