我需要从互联网上下载元素并将它们添加到后台的arraylist中。 (下载可能需要几分钟。)
有一个循环,其中每次迭代都会下载整个元素的一部分并添加到列表中。我需要不同的活动,无论下载(循环)是在进行还是完成,都可以在需要时访问该arraylist。
似乎服务可以做到这一点,但我对如何做不了解。考虑下面的代码,我该如何实现这个目标?
class A extends Service {
void foo(){
//uses a loop to get elements from internet
//then adds the elements to myArraylist in each loop
}
}
class B extends Activity {
//needs to have access to myArraylist asynchronously
}
class C extends Activity {
//needs to have access to myArraylist asynchronously
}
请注意,当用户在活动之间切换时,我需要下载过程保持活动状态。
答案 0 :(得分:0)
您可以通过广播接收器来完成。要发送您可以使用的其他活动的数据:
intent = new Intent(ApplicationSetting.NEW_MESSAGE_ACTION);
intent.putExtra(IMMessage.IMMESSAGE_KEY, msg);
sendBroadcast(intent);
要接收此消息以获取其他任何活动,您可以使用此代码:
private BroadcastReceiver receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
/*
* For before commit
*/
if (ApplicationSetting.NEW_MESSAGE_ACTION.equals(action)) {
IMMessage message = intent
.getParcelableExtra(IMMessage.IMMESSAGE_KEY);
Log.w("message", "are" + message);
}
}
};
答案 1 :(得分:0)
因此,您遇到的问题是您的下载循环可能正在添加或更改列表,而活动活动也可能正在访问同一列表。这可能会导致ConcurrentModificationException
。要避免这种情况,您需要做的是将所有活动与列表同步。为了使其可用于所有活动并使其可供您的服务访问,我建议将列表本身存储在您的应用程序中(扩展Application
的类
public class MyApplication extends Application {
private List<MyElement> mElems;
@Override
public void onCreate() {
super.onCreate();
mElems = Collections.synchronizedList(new ArrayList<MyElement>());
//this line will start your download service, available accross the whole app
startService(new Intent(getApplicationContext(), A.class));
}
//You can use accessor methods and keep the list private to ensure
//synchronisation doesn't get missed anywhere
public void synchronisedAddElement(MyElement elem) {
mElems.add(elem); //already synchronous in this case
}
//I havent tested this method, you method below may be safer
public Iterator getElementsIteratorSynchronised() {
synchronized(mElems) {
return list.iterator();
}
}
public Iterator iterateElementsSynchronised(OnElementListener lis) {
synchronized(mElems) {
Iterator<MyElement> i = list.iterator();
if (lis != null) {
while (l.hasNext()) {
lis.onElement(l.next());
}
}
}
}
public static class OnElementListener {
public void onElement(MyElement el);
}
}
您可以按如下方式写信给
class A extends Service {
void foo(){
MyApplication app = (MyApplication) getApplication();
... //do your network call loop here, adding to local list
app.synchronisedAddElement( myNewElement );
}
}
并阅读
class B extends Activity {
//the async task just because your comment said async access
new AsynTask<MyApplication, Void, Void>() {
public Void doInBackground(MyApplication app) {
app.iterateElementsSynchronised(new OnElementListener() {
public void onElement(MyElement el) {
Log.d(TAG, "Did somethign appropriate with " + el);
}
})
}
}.execute( (MyApplication) getApplication() );
}
请将此视为伪代码,我已将其写入火车之家,因此方法签名可能会有所不同,但这应该可以帮到您需要的地方
答案 2 :(得分:-1)
使用Nick Cardoso推荐的结构,但经过多次更改以满足我的情况,我设法解决了这个问题。这是:
class A extends Service {
ArrayList arrayList = new ArrayList();
MyApplication app;
void foo(){
new Thread (new Runnable (){
@Override
public void run() {
app = (MyApplication)getApplication();
While(true){
//get elements from network and put them in arrayList
app.synchronisedAddCollection(arrayList);
LocalBroadcastManager.getInstance(this).sendBroadcast(mediaIntent);
}
}
}).start();
}
}
这是我的Application类:
public class MyApplication extends Application {
List<HashMap<String, String>> myArrayList = new ArrayList<HashMap<String, String>>();
@Override
public void onCreate() {
super.onCreate();
}
public void synchronisedAddCollection(ArrayList<HashMap<String, String>> arrayList) {
myArrayList.addAll(arrayList);
}
public ArrayList<HashMap<String, String>> getArrayList(){
return (ArrayList<HashMap<String, String>>) myArrayList;
}
}
以下是需要访问共享arraylist的活动
class B extends Activity {
MyApplication app;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
startService(new Intent(getApplicationContext(), MyService.class);
LocalBroadcastManager.getInstance(this).registerReceiver(lbr,
new IntentFilter("mediaIntent"));
}
private BroadcastReceiver lbr = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
app = (MyApplication)getApplication();
//now i have access to the app arrayList
System.out.println(app.myArrayList.size());
}
}
};
}
不要忘记在清单中注册MyApplication和MyService。