package org.qii.weiciyuan.ui.maintimeline; import org.qii.weiciyuan.R; import org.qii.weiciyuan.bean.AccountBean; import org.qii.weiciyuan.bean.GroupBean; import org.qii.weiciyuan.bean.MessageBean; import org.qii.weiciyuan.bean.MessageListBean; import org.qii.weiciyuan.bean.MessageReCmtCountBean; import org.qii.weiciyuan.bean.UserBean; import org.qii.weiciyuan.bean.android.AsyncTaskLoaderResult; import org.qii.weiciyuan.bean.android.MessageTimeLineData; import org.qii.weiciyuan.bean.android.TimeLinePosition; import org.qii.weiciyuan.dao.maintimeline.TimeLineReCmtCountDao; import org.qii.weiciyuan.othercomponent.WifiAutoDownloadPictureRunnable; import org.qii.weiciyuan.support.database.FriendsTimeLineDBTask; import org.qii.weiciyuan.support.debug.AppLogger; import org.qii.weiciyuan.support.error.WeiboException; import org.qii.weiciyuan.support.lib.HeaderListView; import org.qii.weiciyuan.support.lib.LogOnExceptionScheduledExecutor; import org.qii.weiciyuan.support.lib.MyAsyncTask; import org.qii.weiciyuan.support.lib.TopTipBar; import org.qii.weiciyuan.support.lib.VelocityListView; import org.qii.weiciyuan.support.settinghelper.SettingUtility; import org.qii.weiciyuan.support.utils.AppConfig; import org.qii.weiciyuan.support.utils.BundleArgsConstants; import org.qii.weiciyuan.support.utils.GlobalContext; import org.qii.weiciyuan.support.utils.Utility; import org.qii.weiciyuan.ui.adapter.AbstractAppListAdapter; import org.qii.weiciyuan.ui.adapter.StatusListAdapter; import org.qii.weiciyuan.ui.basefragment.AbstractMessageTimeLineFragment; import org.qii.weiciyuan.ui.browser.BrowserWeiboMsgActivity; import org.qii.weiciyuan.ui.loader.FriendsMsgLoader; import org.qii.weiciyuan.ui.main.LeftMenuFragment; import org.qii.weiciyuan.ui.main.MainTimeLineActivity; import org.qii.weiciyuan.ui.send.WriteWeiboActivity; import android.app.ActionBar; import android.content.Intent; import android.graphics.Bitmap; import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.support.v4.content.Loader; import android.util.Pair; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.ViewGroupOverlay; import android.view.ViewTreeObserver; import android.view.animation.DecelerateInterpolator; import android.widget.AdapterView; import android.widget.BaseAdapter; import android.widget.ImageView; import android.widget.ListView; import android.widget.Toast; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Set; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; /** * User: qii * Date: 12-7-29 * Weibo home/friend timeline */ public class FriendsTimeLineFragment extends AbstractMessageTimeLineFragment<MessageListBean> implements GlobalContext.MyProfileInfoChangeListener, MainTimeLineActivity.ScrollableListFragment { private static final String ARGUMENTS_ACCOUNT_EXTRA = FriendsTimeLineFragment.class.getName() + ":account_extra"; private static final String ARGUMENTS_USER_EXTRA = FriendsTimeLineFragment.class.getName() + ":userBean_extra"; private static final String ARGUMENTS_TOKEN_EXTRA = FriendsTimeLineFragment.class.getName() + ":token_extra"; private AccountBean accountBean; private UserBean userBean; private String token; private DBCacheTask dbTask; private Thread backgroundWifiDownloadPicThread = null; private ScheduledExecutorService autoRefreshExecutor = null; public final static String ALL_GROUP_ID = "0"; public final static String BILATERAL_GROUP_ID = "1"; private String currentGroupId = ALL_GROUP_ID; private HashMap<String, MessageListBean> groupDataCache = new HashMap<String, MessageListBean>(); private HashMap<String, TimeLinePosition> positionCache = new HashMap<String, TimeLinePosition>(); private MessageListBean bean = new MessageListBean(); private BaseAdapter navAdapter; private Handler handler = new Handler(Looper.getMainLooper()); @Override public MessageListBean getList() { return bean; } public FriendsTimeLineFragment() { } public static FriendsTimeLineFragment newInstance(AccountBean accountBean, UserBean userBean, String token) { FriendsTimeLineFragment fragment = new FriendsTimeLineFragment(); Bundle bundle = new Bundle(); bundle.putParcelable(ARGUMENTS_ACCOUNT_EXTRA, accountBean); bundle.putParcelable(ARGUMENTS_USER_EXTRA, userBean); bundle.putString(ARGUMENTS_TOKEN_EXTRA, token); fragment.setArguments(bundle); return fragment; } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setRetainInstance(true); setHasOptionsMenu(true); } @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { //use Up instead of Back to reach this fragment if (data == null) { return; } final MessageBean msg = (MessageBean) data.getParcelableExtra("msg"); if (msg != null) { for (int i = 0; i < getList().getSize(); i++) { if (msg.equals(getList().getItem(i))) { MessageBean ori = getList().getItem(i); if (ori.getComments_count() != msg.getComments_count() || ori.getReposts_count() != msg.getReposts_count()) { ori.setReposts_count(msg.getReposts_count()); ori.setComments_count(msg.getComments_count()); FriendsTimeLineDBTask.asyncUpdateCount(msg.getId(), msg.getComments_count(), msg.getReposts_count()); getAdapter().notifyDataSetChanged(); } break; } } } } @Override protected void onListViewScrollStop() { savePositionToPositionsCache(); startDownloadingOtherPicturesOnWifiNetworkEnvironment(); } private void startDownloadingOtherPicturesOnWifiNetworkEnvironment() { if (backgroundWifiDownloadPicThread == null && Utility.isWifi(getActivity()) && SettingUtility.getEnableBigPic() && SettingUtility.isWifiAutoDownloadPic()) { final int position = getListView().getFirstVisiblePosition(); int listVewOrientation = ((VelocityListView) getListView()).getTowardsOrientation(); WifiAutoDownloadPictureRunnable runnable = new WifiAutoDownloadPictureRunnable( getList(), position, listVewOrientation); backgroundWifiDownloadPicThread = new Thread(runnable); backgroundWifiDownloadPicThread.start(); AppLogger .i("WifiAutoDownloadPictureRunnable startDownloadingOtherPicturesOnWifiNetworkEnvironment"); } } @Override protected void onListViewScrollStateTouchScroll() { super.onListViewScrollStateTouchScroll(); stopDownloadingOtherPicturesOnWifiNetworkEnvironment(); } @Override protected void onListViewScrollStateFling() { super.onListViewScrollStateFling(); stopDownloadingOtherPicturesOnWifiNetworkEnvironment(); } private void stopDownloadingOtherPicturesOnWifiNetworkEnvironment() { if (backgroundWifiDownloadPicThread != null) { backgroundWifiDownloadPicThread.interrupt(); backgroundWifiDownloadPicThread = null; AppLogger .i("WifiAutoDownloadPictureRunnable stopDownloadingOtherPicturesOnWifiNetworkEnvironment"); } } private void savePositionToPositionsCache() { TimeLinePosition current = Utility.getCurrentPositionFromListView(getListView()); if (!current.isEmpty()) { positionCache.put(currentGroupId, current); AppLogger.i("Current ListView position first visible item id " + current.firstItemId + " , save to memory cache"); } else { AppLogger .i("Cant get correct current ListView position, so use previous database data"); } } private void saveNewMsgCountToPositionsCache() { final TimeLinePosition position = positionCache.get(currentGroupId); position.newMsgIds = newMsgTipBar.getValues(); } private void setListViewPositionFromPositionsCache() { final TimeLinePosition timeLinePosition = positionCache.get(currentGroupId); AppLogger.i("Memory cached position first visible item id " + (timeLinePosition != null ? timeLinePosition.firstItemId : 0)); int position = timeLinePosition != null ? timeLinePosition.getPosition(bean) : 0; int top = timeLinePosition != null ? timeLinePosition.top : 0; AppLogger.i("Set ListView position from memory cached position position " + position + " top " + top); Utility.setListViewAdapterPosition(getListView(), position, top, new Runnable() { @Override public void run() { setListViewUnreadTipBar(timeLinePosition); } }); } private void setListViewUnreadTipBar(TimeLinePosition p) { if (p != null && p.newMsgIds != null) { if (SettingUtility.getEnableAutoRefresh()) { newMsgTipBar.setType(TopTipBar.Type.ALWAYS); } newMsgTipBar.setValue(p.newMsgIds); } } //must create new position every time onpause, pulltorefresh wont call onListViewScrollStop private void savePositionToDB() { savePositionToPositionsCache(); TimeLinePosition position = positionCache.get(currentGroupId); if (position != null) { position.newMsgIds = newMsgTipBar.getValues(); final String groupId = currentGroupId; FriendsTimeLineDBTask .asyncUpdatePosition(position, GlobalContext.getInstance().getCurrentAccountId(), groupId); AppLogger .i("Save FriendsTimeLineFragment position to database current first visible item id " + position.firstItemId); } } private void saveGroupIdToDB() { FriendsTimeLineDBTask .asyncUpdateRecentGroupId(GlobalContext.getInstance().getCurrentAccountId(), currentGroupId); } @Override public void onPause() { super.onPause(); if (!getActivity().isChangingConfigurations()) { savePositionToDB(); saveGroupIdToDB(); } removeRefresh(); stopDownloadingOtherPicturesOnWifiNetworkEnvironment(); } @Override public void onResume() { super.onResume(); addRefresh(); GlobalContext.getInstance().registerForAccountChangeListener(this); if (SettingUtility.getEnableAutoRefresh()) { this.newMsgTipBar.setType(TopTipBar.Type.ALWAYS); } else { this.newMsgTipBar.setType(TopTipBar.Type.AUTO); } } @Override public void onDestroy() { super.onDestroy(); Utility.cancelTasks(dbTask); GlobalContext.getInstance().unRegisterForAccountChangeListener(this); } @Override public void onActivityCreated(Bundle savedInstanceState) { userBean = getArguments().getParcelable(ARGUMENTS_USER_EXTRA); accountBean = getArguments().getParcelable(ARGUMENTS_ACCOUNT_EXTRA); token = getArguments().getString(ARGUMENTS_TOKEN_EXTRA); switch (getCurrentState(savedInstanceState)) { case FIRST_TIME_START: if (Utility.isTaskStopped(dbTask) && getList().getSize() == 0) { dbTask = new DBCacheTask(this, accountBean.getUid()); dbTask.executeOnIO(); GroupInfoTask groupInfoTask = new GroupInfoTask( GlobalContext.getInstance().getSpecialToken(), GlobalContext.getInstance().getCurrentAccountId()); groupInfoTask.executeOnExecutor(MyAsyncTask.THREAD_POOL_EXECUTOR); } else { getAdapter().notifyDataSetChanged(); refreshLayout(getList()); } groupDataCache.put(ALL_GROUP_ID, new MessageListBean()); groupDataCache.put(BILATERAL_GROUP_ID, new MessageListBean()); if (getList().getSize() > 0) { groupDataCache.put(ALL_GROUP_ID, getList().copy()); } buildActionBarNav(); break; case SCREEN_ROTATE: //nothing refreshLayout(getList()); buildActionBarNav(); setListViewPositionFromPositionsCache(); break; case ACTIVITY_DESTROY_AND_CREATE: if (Utility.isTaskStopped(dbTask) && getList().getSize() == 0) { dbTask = new DBCacheTask(this, accountBean.getUid()); dbTask.executeOnIO(); GroupInfoTask groupInfoTask = new GroupInfoTask( GlobalContext.getInstance().getSpecialToken(), GlobalContext.getInstance().getCurrentAccountId()); groupInfoTask.executeOnExecutor(MyAsyncTask.THREAD_POOL_EXECUTOR); } else { getAdapter().notifyDataSetChanged(); refreshLayout(getList()); } groupDataCache.put(ALL_GROUP_ID, new MessageListBean()); groupDataCache.put(BILATERAL_GROUP_ID, new MessageListBean()); if (getList().getSize() > 0) { groupDataCache.put(ALL_GROUP_ID, getList().copy()); } buildActionBarNav(); break; } super.onActivityCreated(savedInstanceState); } @Override public void onHiddenChanged(boolean hidden) { super.onHiddenChanged(hidden); if (!hidden) { buildActionBarNav(); // ((MainTimeLineActivity) getActivity()).setCurrentFragment(this); } } @Override protected void buildListAdapter() { StatusListAdapter adapter = new StatusListAdapter(this, getList().getItemList(), getListView(), true, false); adapter.setTopTipBar(newMsgTipBar); timeLineAdapter = adapter; getListView().setAdapter(timeLineAdapter); } private int getIndexFromGroupId(String id, List<GroupBean> list) { if (list == null || list.size() == 0) { return 0; } int index = 0; if (id.equals("0")) { index = 0; } else if (id.equals("1")) { index = 1; } for (int i = 0; i < list.size(); i++) { if (list.get(i).getIdstr().equals(id)) { index = i + 2; break; } } return index; } private String getGroupIdFromIndex(int index, List<GroupBean> list) { String selectedItemId; if (index == 0) { selectedItemId = "0"; } else if (index == 1) { selectedItemId = "1"; } else { selectedItemId = list.get(index - 2).getIdstr(); } return selectedItemId; } private String[] buildListNavData(List<GroupBean> list) { List<String> name = new ArrayList<String>(); name.add(getString(R.string.all_people)); name.add(getString(R.string.bilateral)); for (GroupBean b : list) { name.add(b.getName()); } String[] valueArray = name.toArray(new String[0]); return valueArray; } public void buildActionBarNav() { if ((((MainTimeLineActivity) getActivity()).getMenuFragment()).getCurrentIndex() != LeftMenuFragment.HOME_INDEX) { return; } ((MainTimeLineActivity) getActivity()).setCurrentFragment(this); getActivity().getActionBar().setDisplayShowTitleEnabled(false); getActivity().getActionBar().setDisplayHomeAsUpEnabled(Utility.isDevicePort()); getActivity().getActionBar().setNavigationMode(ActionBar.NAVIGATION_MODE_LIST); List<GroupBean> list = new ArrayList<GroupBean>(); if (GlobalContext.getInstance().getGroup() != null) { list = GlobalContext.getInstance().getGroup().getLists(); } else { list = new ArrayList<GroupBean>(); } navAdapter = new FriendsTimeLineListNavAdapter(getActivity(), buildListNavData(list)); final List<GroupBean> finalList = list; getActivity().getActionBar() .setListNavigationCallbacks(navAdapter, new ActionBar.OnNavigationListener() { @Override public boolean onNavigationItemSelected(int which, long itemId) { if (!Utility.isTaskStopped(dbTask)) { return true; } String groupId = getGroupIdFromIndex(which, finalList); if (!groupId.equals(currentGroupId)) { switchFriendsGroup(groupId); } return true; } }); currentGroupId = FriendsTimeLineDBTask .getRecentGroupId(GlobalContext.getInstance().getCurrentAccountId()); if (Utility.isDevicePort()) { ((MainTimeLineActivity) getActivity()).setTitle(""); getActivity().getActionBar().setIcon(R.drawable.ic_menu_home); } else { ((MainTimeLineActivity) getActivity()).setTitle(""); getActivity().getActionBar().setIcon(R.drawable.ic_launcher); } if (getActivity().getActionBar().getNavigationMode() == ActionBar.NAVIGATION_MODE_LIST && isVisible()) { getActivity().getActionBar().setSelectedNavigationItem(getRecentNavIndex()); } } @Override public void onChange(UserBean newUserBean) { if (navAdapter != null) { navAdapter.notifyDataSetChanged(); } } @Override public void scrollToTop() { Utility.stopListViewScrollingAndScrollToTop(getListView()); } private void handleDBCacheOnProgressUpdateData(MessageTimeLineData[] result) { if (result != null && result.length > 0) { MessageTimeLineData recentData = result[0]; getList().replaceData(recentData.msgList); putToGroupDataMemoryCache(recentData.groupId, recentData.msgList); positionCache.put(recentData.groupId, recentData.position); currentGroupId = recentData.groupId; } getPullToRefreshListView().setVisibility(View.VISIBLE); getAdapter().notifyDataSetChanged(); setListViewPositionFromPositionsCache(); if (getActivity().getActionBar().getNavigationMode() == ActionBar.NAVIGATION_MODE_LIST) { getActivity().getActionBar().setSelectedNavigationItem(getRecentNavIndex()); } refreshLayout(getList()); /** * when this account first open app,if he don't have any data in database,fetch data from server automally */ if (getList().getSize() == 0) { getPullToRefreshListView().setRefreshing(); loadNewMsg(); } else { new RefreshReCmtCountTask(FriendsTimeLineFragment.this, getList()) .executeOnExecutor( MyAsyncTask.THREAD_POOL_EXECUTOR); } } private void handleDBCacheResultData(List<MessageTimeLineData> result) { for (MessageTimeLineData single : result) { putToGroupDataMemoryCache(single.groupId, single.msgList); positionCache.put(single.groupId, single.position); } } @Override public void loadNewMsg() { super.loadNewMsg(); new RefreshReCmtCountTask(FriendsTimeLineFragment.this, getList()) .executeOnExecutor( MyAsyncTask.THREAD_POOL_EXECUTOR); } private static class DBCacheTask extends MyAsyncTask<Void, MessageTimeLineData, List<MessageTimeLineData>> { private WeakReference<FriendsTimeLineFragment> fragmentWeakReference; private String accountId; private DBCacheTask(FriendsTimeLineFragment friendsTimeLineFragment, String accountId) { fragmentWeakReference = new WeakReference<FriendsTimeLineFragment>( friendsTimeLineFragment); this.accountId = accountId; } @Override protected void onPreExecute() { super.onPreExecute(); FriendsTimeLineFragment fragment = fragmentWeakReference.get(); if (fragment != null) { fragment.getPullToRefreshListView().setVisibility(View.INVISIBLE); } } @Override protected List<MessageTimeLineData> doInBackground(Void... params) { MessageTimeLineData recentGroupData = FriendsTimeLineDBTask .getRecentGroupData(accountId); publishProgress(recentGroupData); return FriendsTimeLineDBTask .getOtherGroupData(accountId, recentGroupData.groupId); } @Override protected void onPostExecute(List<MessageTimeLineData> result) { super.onPostExecute(result); FriendsTimeLineFragment fragment = fragmentWeakReference.get(); if (fragment == null) { return; } if (fragment.getActivity() == null) { return; } if (result != null && result.size() > 0) { fragment.handleDBCacheResultData(result); } } @Override protected void onProgressUpdate(MessageTimeLineData... result) { super.onProgressUpdate(result); FriendsTimeLineFragment fragment = fragmentWeakReference.get(); if (fragment == null) { return; } if (fragment.getActivity() == null) { return; } fragment.handleDBCacheOnProgressUpdateData(result); } } private int getRecentNavIndex() { List<GroupBean> list = new ArrayList<GroupBean>(); if (GlobalContext.getInstance().getGroup() != null) { list = GlobalContext.getInstance().getGroup().getLists(); } else { list = new ArrayList<GroupBean>(); } return getIndexFromGroupId(currentGroupId, list); } @Override protected void listViewItemClick(AdapterView parent, View view, int position, long id) { startActivityForResult( BrowserWeiboMsgActivity.newIntent(getList().getItem(position), GlobalContext.getInstance().getSpecialToken()), MainTimeLineActivity.REQUEST_CODE_UPDATE_FRIENDS_TIMELINE_COMMENT_REPOST_COUNT); } @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { super.onCreateOptionsMenu(menu, inflater); inflater.inflate(R.menu.actionbar_menu_friendstimelinefragment, menu); } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.write_weibo: Intent intent = new Intent(getActivity(), WriteWeiboActivity.class); intent.putExtra("token", token); intent.putExtra("account", accountBean); startActivity(intent); break; case R.id.refresh: if (allowRefresh()) { getPullToRefreshListView().setRefreshing(); loadNewMsg(); } break; case R.id.switch_theme: //make sure activity has saved current left menu position ((MainTimeLineActivity) getActivity()).saveNavigationPositionToDB(); SettingUtility.switchToAnotherTheme(); ((MainTimeLineActivity) getActivity()).reload(); break; } return super.onOptionsItemSelected(item); } public void setSelected(String selectedItemId) { currentGroupId = selectedItemId; } @Override protected void newMsgLoaderSuccessCallback(MessageListBean newValue, Bundle loaderArgs) { if (Utility.isAllNotNull(getActivity(), newValue) && newValue.getSize() > 0) { if (loaderArgs != null && loaderArgs .getBoolean(BundleArgsConstants.AUTO_REFRESH, false)) { addNewDataAndRememberPositionAutoRefresh(newValue); } else { boolean scrollToTop = SettingUtility.isReadStyleEqualWeibo(); if (scrollToTop) { addNewDataWithoutRememberPosition(newValue); } else { addNewDataAndRememberPosition(newValue); } } putToGroupDataMemoryCache(currentGroupId, getList()); FriendsTimeLineDBTask.asyncReplace(getList(), accountBean.getUid(), currentGroupId); } } private void addNewDataAndRememberPositionAutoRefresh(final MessageListBean newValue) { int initSize = getList().getSize(); if (getActivity() != null && newValue.getSize() > 0) { if (hasActionMode()) { AppLogger.v("ListView have ActionMode, skip notifyDataSetChanged"); return; } final HeaderListView headerListView = (HeaderListView) getListView(); View firstChildView = getListView().getChildAt(0); boolean isFirstViewHeader = headerListView.isThisViewHeader(firstChildView); if (isFirstViewHeader && !headerListView.isInTouchByUser()) { // //Overlay is Android 4.3 method if (!Utility.isJB2()) { getList().addNewData(newValue); getAdapter().notifyDataSetChanged(); Utility.setListViewItemPosition(getListView(), 0, 0, null); return; } //animate add item final ListView listView = getListView(); final ArrayList<Pair<Long, Bitmap>> previousViewsBitmap = new ArrayList<Pair<Long, Bitmap>>(); final HashMap<Long, Integer> previousViewsTop = new HashMap<Long, Integer>(); final HashMap<Long, View> previousViews = new HashMap<Long, View>(); int childCount = listView.getChildCount(); for (int i = 0; i < childCount; i++) { View childView = listView.getChildAt(i); if (headerListView.isThisViewHeader(childView)) { continue; } int firstAdapterItemPosition = listView.getFirstVisiblePosition(); int currentAdapterItemPosition = firstAdapterItemPosition + i - listView .getHeaderViewsCount(); long currentAdapterItemId = getAdapter().getItemId(currentAdapterItemPosition); int childViewTop = childView.getTop(); Bitmap bitmap = Utility.getBitmapFromView(childView); Pair<Long, Bitmap> pair = new Pair<Long, Bitmap>(currentAdapterItemId, bitmap); previousViewsBitmap.add(pair); previousViewsTop.put(currentAdapterItemId, childViewTop); childView.setHasTransientState(true); previousViews.put(currentAdapterItemId, childView); } getList().addNewData(newValue); getAdapter().notifyDataSetChanged(); getListView().getViewTreeObserver() .addOnPreDrawListener( new ViewTreeObserver.OnPreDrawListener() { @Override public boolean onPreDraw() { listView.getViewTreeObserver() .removeOnPreDrawListener(this); DecelerateInterpolator decelerateInterpolator = new DecelerateInterpolator(); final ViewGroupOverlay overlay = listView .getOverlay(); Set<Long> previousViewsId = previousViews.keySet(); boolean somePreviousViewsAreStillInScreen = false; ArrayList<View> newAddedItemViews = new ArrayList<View>(); int deltaY = 0; int childCount = listView.getChildCount(); for (int i = 0; i < childCount; i++) { View childView = listView.getChildAt(i); if (headerListView.isThisViewHeader(childView)) { continue; } int firstAdapterItemPosition = listView .getFirstVisiblePosition(); int currentAdapterItemPosition = firstAdapterItemPosition + i - listView .getHeaderViewsCount(); long currentAdapterItemId = getAdapter() .getItemId(currentAdapterItemPosition); if (previousViewsId.contains(currentAdapterItemId)) { somePreviousViewsAreStillInScreen = true; deltaY = childView.getTop() - previousViewsTop .get(currentAdapterItemId); } else { newAddedItemViews.add(childView); } } if (!somePreviousViewsAreStillInScreen) { deltaY = listView.getHeight(); } for (View view : newAddedItemViews) { view.setTranslationY(-deltaY); view.animate().translationY(0) .setInterpolator(decelerateInterpolator); } for (Pair<Long, Bitmap> pair : previousViewsBitmap) { long id = pair.first; int top = previousViewsTop.get(id); final View view = previousViews.get(id); final Bitmap bitmap = pair.second; final ImageView imageView = new ImageView( getActivity()); imageView.setImageBitmap(bitmap); imageView.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED), View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)); imageView.layout(0, 0, imageView.getMeasuredWidth(), imageView.getMeasuredHeight()); overlay.add(imageView); imageView.setTranslationY(top); view.setAlpha(0); imageView.animate() .translationY(top + deltaY) .setInterpolator(decelerateInterpolator) .withEndAction( new Runnable() { @Override public void run() { overlay.remove( imageView); bitmap.recycle(); view.setAlpha( 1.0f); view.setHasTransientState( false); } }); } return true; } }); return; } getList().addNewData(newValue); Runnable endAction = new Runnable() { @Override public void run() { newMsgTipBar.setValue(newValue, false); newMsgTipBar.setType(TopTipBar.Type.ALWAYS); } }; //keep current read position when user touch listview if (isFirstViewHeader && headerListView.isInTouchByUser()) { int index = getListView().getFirstVisiblePosition(); getAdapter().notifyDataSetChanged(); int finalSize = getList().getSize(); final int positionAfterRefresh = index + finalSize - initSize + getListView() .getHeaderViewsCount(); //use 1 px to show newMsgTipBar Utility.setListViewItemPosition(getListView(), positionAfterRefresh, 1, endAction); return; } //need to calc the first child view's top distance int index = getListView().getFirstVisiblePosition(); View firstAdapterItemView = Utility.getListViewFirstAdapterItemView(getListView()); final int top = (firstAdapterItemView == null) ? 0 : firstAdapterItemView.getTop(); getAdapter().notifyDataSetChanged(); int finalSize = getList().getSize(); final int positionAfterRefresh = index + finalSize - initSize; Utility.setListViewItemPosition(getListView(), positionAfterRefresh, top, endAction); } } private void addNewDataAndRememberPosition(final MessageListBean newValue) { int initSize = getList().getSize(); if (getActivity() != null && newValue.getSize() > 0) { MessageBean previousFirstItem = getList().getSize() > 0 ? getList().getItem(0) : null; int index = getListView().getFirstVisiblePosition(); getList().addNewData(newValue); getAdapter().notifyDataSetChanged(); int finalSize = getList().getSize(); int positionAfterRefresh = index + finalSize - initSize + getListView() .getHeaderViewsCount(); //make sure isMiddleUnreadItem item is visible at first ListView visible position if (previousFirstItem != null) { int itemPositionAfterRefresh = getList().getItemList().indexOf(previousFirstItem); if (getList().getItem(itemPositionAfterRefresh - 1).isMiddleUnreadItem()) { positionAfterRefresh -= 1; } } //use 1 px to show newMsgTipBar Utility.setListViewItemPosition(getListView(), positionAfterRefresh, 1, new Runnable() { @Override public void run() { newMsgTipBar.setValue(newValue, false); newMsgTipBar.setType(TopTipBar.Type.AUTO); } }); } } protected void middleMsgLoaderSuccessCallback(int position, MessageListBean newValue, boolean towardsBottom) { if (getActivity() != null && newValue != null && newValue.getSize() > 0) { getList().addMiddleData(position, newValue, towardsBottom); getAdapter().notifyDataSetChanged(); FriendsTimeLineDBTask.asyncReplace(getList(), accountBean.getUid(), currentGroupId); } } private void addNewDataWithoutRememberPosition(MessageListBean newValue) { newMsgTipBar.setValue(newValue, true); getList().addNewData(newValue); getAdapter().notifyDataSetChanged(); getListView().setSelectionAfterHeaderView(); } @Override protected void oldMsgLoaderSuccessCallback(MessageListBean oldValue) { if (Utility.isAllNotNull(getActivity(), oldValue) && oldValue.getSize() > 1) { getList().addOldData(oldValue); putToGroupDataMemoryCache(currentGroupId, getList()); FriendsTimeLineDBTask.asyncReplace(getList(), accountBean.getUid(), currentGroupId); } else if (Utility.isAllNotNull(getActivity())) { Toast.makeText(getActivity(), getString(R.string.older_message_empty), Toast.LENGTH_SHORT).show(); } } public void switchFriendsGroup(String groupId) { getLoaderManager().destroyLoader(NEW_MSG_LOADER_ID); getLoaderManager().destroyLoader(MIDDLE_MSG_LOADER_ID); getLoaderManager().destroyLoader(OLD_MSG_LOADER_ID); getPullToRefreshListView().onRefreshComplete(); dismissFooterView(); savedCurrentLoadingMsgViewPositon = -1; if (timeLineAdapter instanceof AbstractAppListAdapter) { ((AbstractAppListAdapter) timeLineAdapter) .setSavedMiddleLoadingViewPosition(savedCurrentLoadingMsgViewPositon); } positionCache.put(currentGroupId, Utility.getCurrentPositionFromListView(getListView())); saveNewMsgCountToPositionsCache(); setSelected(groupId); newMsgTipBar.clearAndReset(); if (groupDataCache.get(currentGroupId) == null || groupDataCache.get(currentGroupId).getSize() == 0) { getList().getItemList().clear(); getAdapter().notifyDataSetChanged(); getPullToRefreshListView().setRefreshing(); loadNewMsg(); } else { getList().replaceData(groupDataCache.get(currentGroupId)); getAdapter().notifyDataSetChanged(); setListViewPositionFromPositionsCache(); saveGroupIdToDB(); new RefreshReCmtCountTask(this, getList()) .executeOnExecutor(MyAsyncTask.THREAD_POOL_EXECUTOR); } } private void putToGroupDataMemoryCache(String groupId, MessageListBean value) { MessageListBean copy = new MessageListBean(); copy.addNewData(value); groupDataCache.put(groupId, copy); } private void removeRefresh() { if (autoRefreshExecutor != null && !autoRefreshExecutor.isShutdown()) { autoRefreshExecutor.shutdownNow(); } } protected void addRefresh() { autoRefreshExecutor = new LogOnExceptionScheduledExecutor(1); autoRefreshExecutor .scheduleAtFixedRate(new AutoTask(), AppConfig.AUTO_REFRESH_INITIALDELAY, AppConfig.AUTO_REFRESH_PERIOD, TimeUnit.SECONDS); } private class AutoTask implements Runnable { @Override public void run() { handler.post(new Runnable() { @Override public void run() { if (getActivity() == null) { return; } if (hasActionMode()) { return; } if (!SettingUtility.getEnableAutoRefresh()) { return; } if (!Utility.isTaskStopped(dbTask)) { return; } if (!allowRefresh()) { return; } if (!Utility.isWifi(getActivity())) { return; } if (isListViewFling() || !isVisible() || ((MainTimeLineActivity) getActivity()) .getSlidingMenu().isMenuShowing()) { return; } Bundle bundle = new Bundle(); bundle.putBoolean(BundleArgsConstants.SCROLL_TO_TOP, false); bundle.putBoolean(BundleArgsConstants.AUTO_REFRESH, true); getLoaderManager() .restartLoader(NEW_MSG_LOADER_ID, bundle, msgAsyncTaskLoaderCallback); } }); } } /** * refresh timline messages' repost and comment count */ private static class RefreshReCmtCountTask extends MyAsyncTask<Void, List<MessageReCmtCountBean>, List<MessageReCmtCountBean>> { private List<String> msgIds; private WeakReference<FriendsTimeLineFragment> fragmentWeakReference; private RefreshReCmtCountTask(FriendsTimeLineFragment friendsTimeLineFragment, MessageListBean data) { fragmentWeakReference = new WeakReference<FriendsTimeLineFragment>( friendsTimeLineFragment); msgIds = new ArrayList<String>(); List<MessageBean> msgList = data.getItemList(); for (MessageBean msg : msgList) { if (msg != null) { msgIds.add(msg.getId()); } } } @Override protected List<MessageReCmtCountBean> doInBackground(Void... params) { if (msgIds.size() == 0) { return null; } try { return new TimeLineReCmtCountDao(GlobalContext.getInstance().getSpecialToken(), msgIds).get(); } catch (WeiboException e) { cancel(true); } return null; } @Override protected void onPostExecute(List<MessageReCmtCountBean> value) { super.onPostExecute(value); FriendsTimeLineFragment fragment = fragmentWeakReference.get(); if (fragment == null || value == null || value.size() == 0) { return; } fragment.updateTimeLineMessageCommentAndRepostData(value); } } private void updateTimeLineMessageCommentAndRepostData(List<MessageReCmtCountBean> value) { if (value == null) { return; } HashMap<String, MessageReCmtCountBean> messageReCmtCountBeanHashMap = new HashMap<String, MessageReCmtCountBean>(); for (MessageReCmtCountBean count : value) { messageReCmtCountBeanHashMap.put(count.getId(), count); } for (int i = 0; i < getList().getSize(); i++) { MessageBean msg = getList().getItem(i); if (msg == null) { continue; } MessageReCmtCountBean count = messageReCmtCountBeanHashMap.get(msg.getId()); if (count != null) { msg.setReposts_count(count.getReposts()); msg.setComments_count(count.getComments()); } } getAdapter().notifyDataSetChanged(); FriendsTimeLineDBTask.asyncReplace(getList(), accountBean.getUid(), currentGroupId); } protected Loader<AsyncTaskLoaderResult<MessageListBean>> onCreateNewMsgLoader(int id, Bundle args) { String accountId = accountBean.getUid(); String token = accountBean.getAccess_token(); String sinceId = null; if (getList().getItemList().size() > 0) { sinceId = getList().getItemList().get(0).getId(); } return new FriendsMsgLoader(getActivity(), accountId, token, currentGroupId, sinceId, null); } protected Loader<AsyncTaskLoaderResult<MessageListBean>> onCreateMiddleMsgLoader(int id, Bundle args, String middleBeginId, String middleEndId, String middleEndTag, int middlePosition) { String accountId = accountBean.getUid(); String token = accountBean.getAccess_token(); return new FriendsMsgLoader(getActivity(), accountId, token, currentGroupId, middleBeginId, middleEndId); } protected Loader<AsyncTaskLoaderResult<MessageListBean>> onCreateOldMsgLoader(int id, Bundle args) { String accountId = accountBean.getUid(); String token = accountBean.getAccess_token(); String maxId = null; if (getList().getItemList().size() > 0) { maxId = getList().getItemList().get(getList().getItemList().size() - 1).getId(); } return new FriendsMsgLoader(getActivity(), accountId, token, currentGroupId, null, maxId); } }