كيف يمكنني تحديث المعلومات في نشاط Android من خدمة خلفية
-
20-09-2019 - |
سؤال
أحاول إنشاء تطبيق Android بسيط يحتوي على قائمة نشاط للمعلومات ، عندما يبدأ التطبيق ، أخطط لبدء خدمة سيتم حساب البيانات باستمرار (ستتغير) وأريد أن تكون قائمة Activity متزامنة مع البيانات التي تحسبها الخدمة لحياة التطبيق.
كيف يمكنني إعداد نشاطي للاستماع إلى الخدمة؟ هل هذه هي أفضل طريقة للتعامل مع هذه المشكلة؟
على سبيل المثال ، إذا كنت تتخيل قائمة أسعار الأسهم - سيتم تغيير البيانات بانتظام وتحتاج إلى أن تكون متزامنة مع خدمة (في حالتي) التي تحسب/جلب البيانات باستمرار.
شكرا لك مقدما
المحلول
كيف يمكنني إعداد نشاطي للاستماع إلى الخدمة؟ هل هذه هي أفضل طريقة للتعامل مع هذه المشكلة؟
لديك ثلاثة خيارات رئيسية ، كما أراها:
الاقتراع. ال
Activity
يسأل بشكل دوريService
للحصول على أحدث البيانات. IMHO ، هذا الخيار يمتص ، لكنه بالتأكيد ممكن.عمليات الاسترجاعات. لكل إجابة جاكس ،
Activity
يسجل كائن رد الاتصال ("Observer") معService
. الService
يستدعي طريقة على رد الاتصال عندما تتغير البيانات ، والتي بدورها تقوم بتحديث واجهة المستخدم. يمكنك رؤية مثال على استخدام ذلك معService
هنا.إذاعة
Intents
. الService
يبثIntent
عبرsendBroadcast()
على تغيير البيانات. الActivity
سجلات أBroadcastReceiver
استخدامregisterReceiver()
, ، وذلكBroadcastReceiver
يتم إخطار البث الوارد. هذا يؤدي إلىActivity
لتحميل أحدث البيانات منService
, ، أو ربما فقط للحصول على أحدث البيانات من الإضافات في البثIntent
. يمكنك رؤية مثال على استخدام هذه التقنية مع أService
هنا.
نصائح أخرى
هذا يبدو وكأنه مرشح جيد لنمط المراقب. في الأساس ، سيقوم نشاطك (المراقب) بتسجيل نفسه في خدمة الخلفية (يمكن ملاحظته) ويمكنك دفع البيانات أو سحبها من نشاطك. سيكون مراقبك في هذه الحالة هو نشاطك وسيتم ملاحظته هو خدمتك.
إذا لم تكن تعرف شيئًا عن أنماط التصميم ، فقم بشراء "أنماط التصميم الأولى" ، فمن السهل القراءة ومليئة بالمعلومات الرائعة.
ملاحظة: أنا أقرأها الآن.
أنا حقًا أتساءل حقًا لماذا لم يذكر أحد مقاربة بسيطة باستخدام EventBus بواسطة أي مكتبة. هذا بالطبع إذا كنت لا تستخدم RX. المفضل لدي هو EventBus من GreenRobot.https://github.com/greenrobot/eventbus
مع بضعة أسطر من التعليمات البرمجية ، وليس واجهات. أطلق حدثًا ، واستمع إليه أينما تريد. إنه منفصل ، وهو مؤلم آمن ، ولن يعطل تطبيقك.
تحتاج إلى استخدام BindService () لربط النشاط بخدمة التشغيل والتواصل معها.
public class BindingActivity extends Activity {
YourService mService;
boolean mBound = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
@Override
protected void onStart() {
super.onStart();
// Bind to Your Service
Intent intent = new Intent(this, YourService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
@Override
protected void onStop() {
super.onStop();
// Unbind from the service
if (mBound) {
unbindService(mConnection);
mBound = false;
}
}
/** Called when a button is clicked (the button in the layout file attaches to
* this method with the android:onClick attribute) */
public void onButtonClick(View v) {
if (mBound) {
// Call a method from your Service.
// However, if this call were something that might hang, then this request should
// occur in a separate thread to avoid slowing down the activity performance.
int num = mService.getRandomNumber();
Toast.makeText(this, "number: " + num, Toast.LENGTH_SHORT).show();
}
}
/** Defines callbacks for service binding, passed to bindService() */
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName className,
IBinder service) {
// We've bound to the running Service, cast the IBinder and get instance
LocalBinder binder = (LocalBinder) service;
mService = binder.getService();
mBound = true;
}
@Override
public void onServiceDisconnected(ComponentName arg0) {
mBound = false;
}
};
}
وخدمتك مثل:
public class LocalService extends Service {
// Binder given to clients
private final IBinder mBinder = new LocalBinder();
// Random number generator
private final Random mGenerator = new Random();
/**
* Class used for the client Binder. Because we know this service always
* runs in the same process as its clients, we don't need to deal with IPC.
*/
public class LocalBinder extends Binder {
LocalService getService() {
// Return this instance of LocalService so clients can call public methods
return LocalService.this;
}
}
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
/** method for clients */
public int getRandomNumber() {
return mGenerator.nextInt(100);
}
}
سيكون لديك مؤشر ترابط خلفية يعمل على حساب التغييرات في القائمة. يحتاج هذا الموضوع الآن إلى إمكانية إخطار واجهة المستخدم الرسومية بأن القائمة تم تحديثها.
يمكنك استخدام نوع من ArrayAdapter للحصول على البيانات في ListView. يحتوي ArrayAdapter على طريقة تسمى adpater.notifyDataStchanged () في كل مرة تتصل فيها هذه الطريقة ، سيرى المحول أن البيانات المقابلة قد تغيرت ثم تخطر عرض القائمة بأنه يجب تحديثه في الاحتمال التالي.