如何定期从Web服务更新recyclerView而不泄漏内存

时间:2017-03-30 20:17:37

标签: android memory-management memory-leaks android-recyclerview

我的应用程序使用volley进行webservice调用,以便每10秒更新一次recyclerView。除了内存使用量持续增加10秒,直到它达到最大堆大小。然后GC开始完成它的工作,但内存使用率并没有像开始那样回落。 使用Eclipse MAT或Android Studio分析器任务,我无法在代码中找到单个泄漏。

我想知道如果我的代码中有泄漏的嫌疑人。任何帮助将不胜感激。

下面我有3个班级:

  • EventService每10秒钟使用MainActivitysendBroadcast()发送一条消息。

  • MainActiviy将使用EventServiceBroadcastReceiver收到消息,并在其update

  • 内调用Fragment次操作
  • EventListFragment位于MainActivity内,包含RecyclerView,需要更新。

这是我的EventService

public class EventService extends Service {
    private volatile boolean isCanceled = false;
    public static final String KEY_MESSAGE = "connection";
    public EventService() {}

       @Override
public int onStartCommand(final Intent intent, int flags, int startId) {
    Runnable r = new Runnable() {
        @Override
        public void run() {
            while (!isCanceled) {
                try {
                    Intent i = new Intent("android.intent.action.MAIN");
                    AppController.getInstance().cancelPendingRequests("json_obj_req");
                    i.putExtra(KEY_MESSAGE, MESSAGE);
                    sendBroadcast(i);
                    Thread.sleep(10000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    };
    Thread eventThread = new Thread(r);
    eventThread.start();
    return Service.START_STICKY;
}

    @Override
    public void onDestroy() {
        isCanceled = true;
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

}

这是我的MainActivity

public class MainActivity extends AppCompatActivity {
    private Intent intent;
    private BroadcastReceiver mReceiver;
    private EventListFragment eventListFragment;
    private IntentFilter intentFilter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

    private void setView() {
        eventListFragment = (EventListFragment) getSupportFragmentManager().findFragmentById(R.id.frgEventList);
    }

    @Override
    protected void onResume() {
        intent = new Intent(this, EventService.class);
        mReceiver = new MyReceiver(eventListFragment);
        this.registerReceiver(mReceiver, intentFilter);
        intent = new Intent(this, EventService.class);
        startService(intent);
    }

    @Override
    protected void onPause() {
        super.onPause();
        stopService(intent);
        unregisterReceiver(mReceiver);
    }

    private static class MyReceiver extends BroadcastReceiver {
        private WeakReference<EventListFragment> eventListFragment = null;
        public MyReceiver(EventListFragment eventFragment) {
            this.eventListFragment = new WeakReference<>(eventFragment);
        }

        @Override
        public void onReceive(Context context, Intent intent) {
            String mssg = intent.getStringExtra(KEY_MESSAGE);
            EventListFragment eventFragment = eventListFragment.get();
            if (mssg.equals(MESSAGE) && eventFragment != null) {
               //Update recyclerView
                eventFragment.eventToList();
            }
        }
    }
}

这是我的EventListFragment

public class EventListFragment extends Fragment {

    private View view;
    private RecyclerView recyclerView;
    private LinearLayoutManager mLayoutManager;
    private EventAdapter eventAdapter;
    private RequestData requestData;
    private ArrayList<EventModel> eventList;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        view = inflater.inflate(R.layout.fragment_event_list, container, false);
        return view;
    }

    @Override
    public void onResume() {
        super.onResume();
        setView();
        setControl();
    }

    private void setView() {
        recyclerView = (RecyclerView) view.findViewById(R.id.frg_recycler_view);
    }

    private void setControl() {
        if (eventAdapter == null && mLayoutManager == null) {
            eventList = new ArrayList<>();
            eventAdapter = new EventAdapter(getActivity().getApplicationContext(), eventList);
            mLayoutManager = new LinearLayoutManager(getActivity().getApplicationContext());
            recyclerView.setLayoutManager(mLayoutManager);
            recyclerView.setHasFixedSize(true);
            recyclerView.addItemDecoration(new DividerItemDecoration(getActivity(), LinearLayoutManager.VERTICAL));
            recyclerView.setAdapter(eventAdapter);
        }

        recyclerView.addOnItemTouchListener(new RecyclerItemListener(getActivity().getApplicationContext(), recyclerView, new RecyclerItemListener.RecyclerTouchListener() {
            @Override
            public void onClickItem(View v, int position) {
              EventModel model = eventList.get(position);
                SQLiteHandler db = SQLiteHandler.getInstance(getActivity().getApplicationContext());
                //some instances
            }

            @Override
            public void onLongClickItem(View v, int position) {

            }
        }));
    }
//make service call
    public void eventToList() {
        if (requestData == null) {
            requestData = new RequestData(getActivity());
        }
        final ArrayList<EventModel> newList = new ArrayList<>(); //are you leaking?
        requestData.getEventToday(new RequestData.VolleyCallback() {
            @Override
            public void onSuccess(JSONObject result) {
                for (int i = 0; i < result.length(); i++) {
                    try {

                        JSONObject item = result.getJSONObject(Integer.toString(i));
                        EventModel eventModel = new EventModel();                
                        String title = item.getString("title");
                        String start = item.getString("start");
                        String end = item.getString("end");
                        String date = item.getString("date");
                        eventModel.setDate(date);
                        eventModel.setStartTime(start);
                        eventModel.setEndTime(end);
                        eventModel.setTitle(title);                    
                        newList.add(eventModel);
                    } catch (JSONException e) {         
                        e.printStackTrace();
                    }
                }
                eventAdapter.update(newList);

            }
        });

    }
}

非常感谢!

1 个答案:

答案 0 :(得分:1)

首先,一个设计考虑因素:是否有必要每10秒调用一次Web服务?您知道服务器数据何时/多久更改一次?

每次从Web服务器读取数据时,应用程序都需要做很多工作:创建多个对象,更新适配器等。此外,考虑网络流量,每隔10秒就使用一次网络。

你可以做些事情:

  1. 增加等待时间:通过这种方式,您可以减少每秒创建对象的数量。
  2. 减少临时对象的本地引用(请参阅下面的代码)
  3. 在添加新值之前,检查Recycler视图的适配器是否正确延迟了旧的。
  4. 评估是否可以使用技术推送数据,以避免数据轮询。您可以看到GCM
  5. 考虑到#2,我尝试重写eventToList方法:

    public void eventToList() {
      if (requestData == null) {
        requestData = new RequestData(getActivity());
      }      
      requestData.getEventToday(new RequestData.VolleyCallback() {
        @Override
        public void onSuccess(JSONObject result) {
          ArrayList<EventModel> newList = new ArrayList<>();
          JSONObject item;
          EventModel eventModel;
          String title;
          String start;
          String end;
          String date;
          for (int i = 0; i < result.length(); i++) {
            try {
              item = result.getJSONObject(Integer.toString(i));
              eventModel = new EventModel();                
              title = item.getString("title");
              start = item.getString("start");
              end = item.getString("end");
              date = item.getString("date");
              eventModel.setDate(date);
              eventModel.setStartTime(start);
              eventModel.setEndTime(end);
              eventModel.setTitle(title);                    
              newList.add(eventModel);
            } catch (JSONException e) {         
              e.printStackTrace();
            }
          }
          eventAdapter.update(newList);
        }
     });
    

    }