在后台下载互联网数据,并在所有活动中同时共享。怎么样?

时间:2015-12-30 17:14:53

标签: android service

我需要从互联网上下载元素并将它们添加到后台的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
}  

请注意,当用户在活动之间切换时,我需要下载过程保持活动状态。

3 个答案:

答案 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。