I am working on an application that I expect to migrate to multiple platforms. To facilitate the porting, I'm using Fragments to streamline the process. So what I have right now is a single Activity and several fragments. In one case I have several instances of the same fragment, with different data. Obviously each of these instances of the same fragment will use the same interface functions.
I've added the parameter "tag" to the interface function to identify each instance of fragment (using the tag used in creating the fragment). I guess one could also use the resource ID.
My question: Is this a good way to do this? Is there a better or more accepted method?
Activity code snippet:
public class SailboatRaceActivity extends FragmentActivity
implements SR_CommandsFragment.OnSR_CommandsSelectedListener,
SR_SubCommands_Fragment.OnSR_SubCommandsSelectedListener,
FleetListFragment.FleetList_WidthChange,
FleetListFragment.FleetListChange,
FleetScoringFragment.OnFS_SelectedListener,
FleetSpinnerFragment.FleetSpinner_Selection {
// State Variables
private int mSubCommandPositon;
private int mCommandPosition;
private int mFleetSelection;
private int mFleetListColumnWidth = 0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState != null) {
mSubCommandPositon = savedInstanceState.getInt("mSubCommandPositon");
mCommandPosition = savedInstanceState.getInt("mCommandPosition");
mFleetSelection = savedInstanceState.getInt("mFleetSelection");
mFleetListColumnWidth = savedInstanceState.getInt("mFleetListColumnWidth");
}
setContentView(R.layout.sailboat_race_layout);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
}
public void onSR_CommandSelected(int position) {
SR_SubCommands_Fragment SR_SubCFrag = (SR_SubCommands_Fragment) getFragmentManager().findFragmentById(R.id.subcommands);
mCommandPosition = position;
if (SR_SubCFrag != null) {
SR_SubCFrag.update_SR_subcommands(position);
SR_SubCFrag.ChangeListViewWidth(mFleetListColumnWidth);
}
}
public void onSR_SubCommandSelected(int position) {
mSubCommandPositon = position;
FleetScoringFragment FSFrag = (FleetScoringFragment) getFragmentManager().findFragmentById(R.id.fleet_scoring);
if (FSFrag != null) {
FSFrag.update_commands(mCommandPosition, mSubCommandPositon);
}
}
#Override
public void onSaveInstanceState(Bundle outState) {
outState.putInt("mSubCommandPositon", mSubCommandPositon);
outState.putInt("mCommandPosition", mCommandPosition);
outState.putInt("mFleetSelection", mFleetSelection);
outState.putInt("mFleetListColumnWidth", mFleetListColumnWidth);
super.onSaveInstanceState(outState);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
#Override
public void FleetList_WidthChange(int width) {
mFleetListColumnWidth = width;
// can we set width of other two lists
SR_SubCommands_Fragment SR_SubCFrag = (SR_SubCommands_Fragment) getFragmentManager().findFragmentById(R.id.subcommands);
if (SR_SubCFrag != null) {
SR_SubCFrag.ChangeListViewWidth(width);
}
SR_CommandsFragment SR_CFrag = (SR_CommandsFragment) getFragmentManager().findFragmentById(R.id.commands);
if (SR_CFrag != null) {
SR_CFrag.ChangeListViewWidth(width);
}
}
#Override
public void FleetListChange(int position) {
FleetScoringFragment FSFrag = (FleetScoringFragment) getFragmentManager().findFragmentById(R.id.fleet_scoring);
if (FSFrag != null) {
mFleetSelection = position;
FSFrag.update_FleetScoringList(position);
}
FleetScoringHeaderFragment FSHFrag = (FleetScoringHeaderFragment) getFragmentManager().findFragmentById(R.id.scoring_header);
if (FSHFrag != null) {
mFleetSelection = position;
FSHFrag.update_FleetScoringHeader(position);
}
}
#Override
public void onFS_Selected(int position) {
}
#Override
public void FSpinner_selection(int selection, String tag) {
int fs = selection;
String thistag =tag;
// do something
}
The FSpinner_selection interface is the one I'm working on. I set this implementation just to check if the data was valid.
FleetSpinner snippet:
public class FleetSpinnerFragment extends Fragment {
private int nPresentFleetPosition;
public ArrayList<FleetItem> mListArray = new ArrayList<FleetItem>();
FleetSpinnerAdapter adapter;
FleetSpinner_Selection mCallback;
Spinner spinner;
String tag;
public interface FleetSpinner_Selection {
public void FSpinner_selection(int selection, String tag);
}
public FleetSpinnerFragment() {
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
mCallback = (FleetSpinner_Selection) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ " must implement FSpinner_Selection");
}
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState == null) {
nPresentFleetPosition = 0;
for (int i = 0; i<Fleet.fleetbit.length;i++) {
mListArray.add(Fleet.fleetbit[i]);
}
} else {
nPresentFleetPosition = savedInstanceState.getInt("nPresentFleetPosition");
ArrayList temp = savedInstanceState.getParcelableArrayList("thisFleetList");
mListArray.addAll(temp);
}
}
#Override
public void onSaveInstanceState(Bundle savedInstanceState) {
savedInstanceState.putInt("nPresentFleetPosition", nPresentFleetPosition);
ArrayList<FleetItem> temp = new ArrayList<FleetItem>();
for (int i =0 ; i< adapter.getCount();i++){
temp.add(adapter.getItem(i));
}
savedInstanceState.putParcelableArrayList("thisFleetList", temp);
super.onSaveInstanceState(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = new View(getActivity());
adapter = new FleetSpinnerAdapter(getActivity(), R.layout.fleet_list_item);
spinner = new Spinner(getActivity());
spinner.setAdapter(adapter);
adapter.addAll(Fleet.fleetbit);
spinner.setOnItemSelectedListener(new CustomOnItemSelectedListener());
tag = getTag();
spinner.setSelection(nPresentFleetPosition);
return spinner;
}
public void update_FleetScoringHeader(int position) {
nPresentFleetPosition = position;
FrameLayout FLScoringHeader = (FrameLayout) getActivity().findViewById(R.id.scoring_header);
TextView v1 = (TextView) FLScoringHeader.findViewById(R.id.fleet_list_item_textview);
v1.setText(Fleet.fleetbit[nPresentFleetPosition].name);
ImageView v0 = (ImageView) FLScoringHeader.findViewById(R.id.fleet_list_item_icon);
v0.setImageResource(Fleet.fleetbit[nPresentFleetPosition].id);
}
static class FleetHolder {
ImageView imgIcon;
TextView txtTitle;
}
public class CustomOnItemSelectedListener extends Activity implements AdapterView.OnItemSelectedListener {
#Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
FleetItem temp = (FleetItem) parent.getItemAtPosition(position);
nPresentFleetPosition = position;
mCallback.FSpinner_selection(position, tag);
}
#Override
public void onNothingSelected(AdapterView<?> parent) {
}
}
I'm just starting to learn android programming, so this may be a really noob question.
Related
I'm writing a memo keeper app. It has a ViewPager that allows you to swipe between categories of memos. When I add a memo in a page, the memo is listed in the ListView of the fragment.
But if i swipe to another page and swipe back, then add another memo, that memo is not listed in the ListView. I tried notifyDatasetChanged() of the adapter and invalidateViews() of the ListView but nothing seem to work.
I don't know, where I made a mistake. I hope if you can find what I did wrong, it will very helpful for me.
Here is my Fragment code:
public class MemoListFragment extends Fragment
{
private MemoAdapter memoAdapter = null;
private ListView memoListView;
private Memo memoToEdit = null;
private List<Memo> userSelected = new ArrayList<>();
private onDeleteActionSelectedListener
deleteActionSelectedListener;
private String category;
private List<Memo> memoList;
public String getCategory()
{
return category;
}
public void setCategory(String category)
{
this.category = category;
}
private final int EDIT_MEMO_REQUEST_CODE = 2;
public void updateMemoList(List<Memo> memoList)
{
memoAdapter.clear();
memoAdapter.addAll(memoList);
}
public void setInitData(List<Memo> memoList)
{
this.memoList = memoList;
}
public void addMemo(Memo m)
{
memoAdapter.add(m);
memoListView.invalidateViews();
}
public MemoListFragment()
{
// Required empty public constructor
}
#Override
public void onAttach(Context context)
{
super.onAttach(context);
deleteActionSelectedListener = ((MainActivity)
context).getMainPresenter();
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup
container,
Bundle savedInstanceState)
{
View rootLayout = inflater.inflate(R.layout.memo_list_fragment,
container, false);
memoListView = rootLayout.findViewById(R.id.memo_list_view);
memoListView.setOnItemClickListener((parent, view, position,
id) ->
{
{
Memo selectedMemo = memoAdapter.getItem(position);
Intent editMemo = new Intent(getActivity(),
MemoViewActivity.class);
editMemo.putExtra("memo_to_edit", selectedMemo);
memoToEdit = selectedMemo;
startActivityForResult(editMemo,
EDIT_MEMO_REQUEST_CODE);
}
});
memoAdapter = new MemoAdapter(getActivity(), 0, memoList);
memoListView.setAdapter(memoAdapter);
memoListView.setChoiceMode(AbsListView.CHOICE_MODE_MULTIPLE_MODAL);
memoListView.setMultiChoiceModeListener(modeListener);
return rootLayout;
}
#Override
public void onActivityResult(int requestCode, int resultCode,
Intent data)
{
if (requestCode == EDIT_MEMO_REQUEST_CODE)
{
if (resultCode == Activity.RESULT_OK)
{
String title = data.getStringExtra("title").toString();
String detail =
data.getStringExtra("detail").toString();
if (memoToEdit != null)
{
memoToEdit.setDetail(detail);
memoToEdit.setTitle(title);
memoToEdit.setLastModified(LocalDate.now());
memoToEdit = null;
}
}
}
}
AbsListView.MultiChoiceModeListener modeListener = new
AbsListView.MultiChoiceModeListener()
{
#Override
public void onItemCheckedStateChanged(ActionMode mode, int
position, long id, boolean checked)
{
Memo m = memoAdapter.getItem(position);
if (userSelected.contains(m))
{
userSelected.remove(m);
memoAdapter.getSelectedPos().remove(new
Integer(position));
}
else
{
userSelected.add(m);
memoAdapter.getSelectedPos().add(position);
}
memoListView.invalidateViews();
mode.setTitle(userSelected.size() + " items selected.");
}
#Override
public boolean onCreateActionMode(ActionMode mode, Menu menu)
{
mode.getMenuInflater().inflate(R.menu.context_menu, menu);
memoAdapter.setShowCheckboxes(true);
return true;
}
#Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu)
{
return false;
}
#Override
public boolean onActionItemClicked(ActionMode mode, MenuItem
item)
{
switch (item.getItemId())
{
case R.id.action_delete:
for (Memo m : userSelected)
memoAdapter.remove(m);
deleteActionSelectedListener.onDeleteActionSelected(userSelected);
mode.finish();
return true;
default:
return false;
}
}
#Override
public void onDestroyActionMode(ActionMode mode)
{
userSelected.clear();
memoAdapter.getSelectedPos().clear();
memoAdapter.setShowCheckboxes(false);
}
};
public interface onDeleteActionSelectedListener
{
void onDeleteActionSelected(List<Memo> userSelected);
}
}
Here is the code to add a memo:
public void addMemo(Memo memo)
{
int currentPage = mainView.getCurrentPagePosition();
if (currentPage == 0)//on page All category
memo.setCategory("Not categorized");
else
memo.setCategory(memoManager.getCategoriesList().get(currentPage));
MemoListFragment currentFrag = fragmentList.get(currentPage);
currentFrag.addMemo(memo);
}
Here is my PagerAdapter code:
public class MemooPagerAdapter extends FragmentStatePagerAdapter
{
private FragmentSetupManager fragmentSetupManager;
private List<String> categoriesList;
public MemooPagerAdapter(FragmentManager fm, FragmentSetupManager fragmentSetupManager)
{
super(fm);
this.fragmentSetupManager = fragmentSetupManager;
this.categoriesList = fragmentSetupManager.getCategoriesList();
}
#Override
public Fragment getItem(int position)
{
MemoListFragment fragment = new MemoListFragment();
String cate = categoriesList.get(position);
fragment.setCategory(cate);
fragment.setInitData(fragmentSetupManager.getFragmentData(cate));
fragmentSetupManager.addToFragmentList(fragment);
return fragment;
}
#Override
public int getCount()
{
return categoriesList.size();
}
#Nullable
#Override
public CharSequence getPageTitle(int position)
{
return categoriesList.get(position);
}
public interface FragmentSetupManager
{
List<Memo> getFragmentData(String category);
void addToFragmentList(MemoListFragment fragment);
List<String> getCategoriesList();
}
}
ViewPager stetup:
public MainPresenter(MainView mainView)
{
this.mainView = mainView;
memoManager = new MemoManager(((Activity) mainView).getApplicationContext());
pagerAdapter = new MemooPagerAdapter(
((FragmentActivity) mainView).getSupportFragmentManager(), this);
mainView.setMainVPagerAdapter(pagerAdapter);
}
Ideally, you want to communicate an event from one fragment to another. The easiest of ways is to use RXJava. This approach is the best way of doing that and easy to implement. In my opinion, this is the best approach for communicating two or maore fragments in Android.
Set up your project with the dependencies:
// RxJava2 Dependencies
implementation 'io.reactivex.rxjava2:rxjava:2.2.8'
implementation 'io.reactivex.rxjava2:rxandroid:2.1.1'
So if you are in FragmentA and move to FragmentB, and made a change in FragmentB, FragmentA will get this change.
See how this was implemented easily here. Do let me know if it is sufficient.
I am using a recyclerView to show a grid of movie posters. The posters are contained in a List<> along with their respective title and so on.
I implemented a searchView widget and I can successuflly get a List of matching results. But I can't hide the other ones.
As you understand I don't want to delete the irrelevant movies from the adapter or the user would not be able to see them again.
This is the code:
public class SearchUtils {
public static List<String> search(List<Show> list, String keyword){
List<String> results = new ArrayList<>();
for (Show curVal : list){
String curTitle = curVal.getTitle().toLowerCase().trim();
if (curTitle.contains(keyword)){
results.add(curTitle);
}else{
results = new ArrayList<>();
}
}
return results;
}
}
ListFragment.java
public class ListFragment extends Fragment implements LoaderManager.LoaderCallbacks<List<Show>> {
private static final String LOG_TAG = "ListFragment";
private static final String ARG_SCOPE = "com.dcs.shows.activity_to_launch";
private static final String BASE_URL = "http://api.themoviedb.org/3";
private TextView tv;
private ProgressBar pb;
private int scope;
private RecyclerView mRecyclerView;
private ShowAdapter mShowAdapter;
private SearchView mSearchView;
public static ListFragment newInstance(int target) {
Bundle args = new Bundle();
args.putInt(ARG_SCOPE, target);
ListFragment fragment = new ListFragment();
fragment.setArguments(args);
return fragment;
}
public ListFragment() {
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
scope = getArguments().getInt(ARG_SCOPE);
setHasOptionsMenu(true);
Log.i(LOG_TAG, "onCreate#Scope is: " + scope);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_list, container, false);
mShowAdapter = new ShowAdapter(new ArrayList<Show>());
mRecyclerView = (RecyclerView) rootView.findViewById(R.id.recyclerView);
GridLayoutManager glm = new GridLayoutManager(getActivity(), 4);
mRecyclerView.setLayoutManager(glm);
mRecyclerView.addItemDecoration(new SpacesItemDecoration(8, getActivity()));
mRecyclerView.setAdapter(mShowAdapter);
mRecyclerView.addOnScrollListener(new EndlessRecyclerViewScrollListener(glm) {
#Override
public void onLoadMore(int page, int totalItemsCount) {
// Triggered only when new data needs to be appended to the list
// Add whatever code is needed to append new items to the bottom of the list
}
});
pb = (ProgressBar)rootView.findViewById(R.id.progress_view);
ConnectivityManager connMgr = (ConnectivityManager) getActivity().getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = connMgr.getActiveNetworkInfo();
if (networkInfo != null && networkInfo.isConnected()) {
// fetch data
getLoaderManager().initLoader(1, null, this);
} else {
// display error
pb.setVisibility(View.GONE);
}
return rootView;
}
List<Show> searchList;
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
getActivity().getMenuInflater().inflate(R.menu.main, menu);
final MenuItem myActionMenuItem = menu.findItem( R.id.action_search);
mSearchView = (SearchView) myActionMenuItem.getActionView();
mSearchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
#Override
public boolean onQueryTextSubmit(String s) {
if(!mSearchView.isIconified()) {
mSearchView.setIconified(true);
}
myActionMenuItem.collapseActionView();
return false;
}
#Override
public boolean onQueryTextChange(String s) {
if(s != null || !s.isEmpty()) {
for(Show movie : mShowAdapter.getList()) {
if(movie.getTitle().toLowerCase().contains(s.toLowerCase())){
mShowAdapter.add(movie);
}
mShowAdapter.notifyDataSetChanged();
}
} else {
mShowAdapter.addItemsToList(searchList, false);
}
return false;
}
});
mSearchView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
#Override
public void onViewDetachedFromWindow(View arg0) {
// search was detached/closed
Log.v(LOG_TAG, "Restoring list: " + searchList + " size: " + searchList.size());
mShowAdapter.addItemsToList(searchList, false);
}
#Override
public void onViewAttachedToWindow(View arg0) {
// search was opened
searchList = mShowAdapter.getList();
}
});
}
private class ShowHolder extends RecyclerView.ViewHolder {
public ImageView mImageView;
public TextView mTextView;
public ShowHolder(View itemView) {
super(itemView);
mImageView = (ImageView) itemView.findViewById(R.id.grid_item_image);
mTextView = (TextView) itemView.findViewById(R.id.grid_item_title);
}
}
private class ShowAdapter extends RecyclerView.Adapter<ShowHolder> {
private List<Show> mShows;
public ShowAdapter(List<Show> shows) {
mShows = shows;
}
public void add(Show show){
mShows.add(show);
notifyDataSetChanged();
}
public void addItemsToList(List<Show> newShows, boolean append){
if(append){
mShows.addAll(newShows);
}else {
mShows = newShows;
}
notifyDataSetChanged();
}
public void removeItemsFromList(int index){
mShows.remove(index);
notifyItemRemoved(index);
}
public List<Show> getList(){
return mShows;
}
#Override
public ShowHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(getActivity());
View rootView = inflater.inflate(R.layout.list_item_row, parent, false);
return new ShowHolder(rootView);
}
#Override
public void onBindViewHolder(ShowHolder holder, int position) {
Show currentShow = mShows.get(position);
holder.mTextView.setText(currentShow.getTitle());
Glide.with(getActivity()).load(currentShow.getImage()).into(holder.mImageView);
}
#Override
public int getItemCount() {
return mShows.size();
}
}
#Override
public Loader<List<Show>> onCreateLoader(int i, Bundle bundle) {
//start the loader with the appropriate uri
//for now it only supports movies+popular
//it will support movies+top, tv+popular, tv+top.
Uri baseUri = Uri.parse(BASE_URL);
Uri.Builder uriBuilder = baseUri.buildUpon();
uriBuilder.appendPath("movie");
uriBuilder.appendPath("popular");
uriBuilder.appendQueryParameter("api_key", QueryUtils.API_KEY);
uriBuilder.appendQueryParameter("page", Integer.valueOf(1).toString());
Log.v(LOG_TAG, "onCreateLoader#URL built: " + uriBuilder.toString());
return new ShowLoader(getActivity(), uriBuilder.toString());
}
#Override
public void onLoadFinished(Loader<List<Show>> loader, List<Show> shows) {
// Clear the adapter of previous earthquake data
clearAdapter();
// If there is a valid list of Shows, then add them to the adapter's
// data set. This will trigger the ListView to update.
if (shows != null && !shows.isEmpty()) {
mShowAdapter.addItemsToList(shows, false);
mShowAdapter.notifyDataSetChanged();
}
pb.setVisibility(View.GONE);
}
#Override
public void onLoaderReset(Loader<List<Show>> loader) {
// Loader reset, so we can clear out our existing data.
clearAdapter();
}
private void clearAdapter(){
List<Show> empty = new ArrayList<>();
mShowAdapter.addItemsToList(empty, false);
mShowAdapter.notifyDataSetChanged();
}
Thanks
You can use two lists, one with all the elements (original), and one with just queried elements (this one should use recyclerview adapter). When querying, just select from original list and add them to adapter list, then notify changes. Don't forget to clear adapter list before adding new entries.
Edit: you can try something like this on onQueryTextChange method. Adapt for your own wish.
if(s != null && !s.isEmpty()) {
for(String movie : originalList) {
if(movie.toLowerCase().contains(s.toLowerCase()){
adapter.add(movie);
}
notifyChanges();
}
}
} else { adapter.addAll(originalList); }
I am working on a RecyclerView which must be Draggable & swipeable. Everything works perfect.
The Data is getting Fetched in one class called ExerciseDataProvider & the RV code is another Fragment RecyclerListViewFragment.
The problem is that i can't notify Data changed from the FetchExercise on postExecute method. So the Data's are not getting populated in the RV.
Please Guide me in a Right Direction.
ACTIVITY
public class DraggableSwipeableExampleActivity extends AppCompatActivity {
private static final String FRAGMENT_TAG_DATA_PROVIDER = "data provider";
private static final String FRAGMENT_LIST_VIEW = "list view";
private static final String FRAGMENT_TAG_ITEM_PINNED_DIALOG = "item pinned dialog";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_demo);
if (savedInstanceState == null) {
getSupportFragmentManager().beginTransaction()
.add(new ExampleDataProviderFragment(), FRAGMENT_TAG_DATA_PROVIDER)
.commit();
getSupportFragmentManager().beginTransaction()
.add(R.id.container, new RecyclerListViewFragment(), FRAGMENT_LIST_VIEW)
.commit();
}
}
public AbstractDataProvider getDataProvider() {
final Fragment fragment = getSupportFragmentManager().findFragmentByTag(FRAGMENT_TAG_DATA_PROVIDER);
return ((ExampleDataProviderFragment) fragment).getDataProvider();
}
DATA PROVIDER
public class ExerciseDataProvider extends AbstractDataProvider {
private List<ConcreteData> mData;
private ConcreteData mLastRemovedData;
private int mLastRemovedPosition = -1;
public ExerciseDataProvider() {
new FetchExercise().execute();
mData = new LinkedList<>();
}
class FetchExercise extends AsyncTask<Void,Void,Void> {
#Override
protected Void doInBackground(Void... params) {
final int viewType = 0;
final int swipeReaction = RecyclerViewSwipeManager.REACTION_CAN_SWIPE_UP | RecyclerViewSwipeManager.REACTION_CAN_SWIPE_DOWN;
String url = "https://gist.githubusercontent.com/fake/cb9aa5494e7ee36ac3ca/raw/a4abfd19368063/exercise.JSON";
Log.d("Path", url);
try {
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder().url(url).build();
Response response = client.newCall(request).execute();
String jsonData = response.body().string();
try {
JSONArray jsonArray = new JSONArray(jsonData);
for (int i = 0; i < jsonArray.length(); i++) {
final long id = i;
JSONObject jsonObject = jsonArray.getJSONObject(i);
String exercise_name = jsonObject.getString("name");
int exercise_duration = jsonObject.getInt("duration");
mData.add(new ConcreteData(id, viewType, exercise_name, exercise_duration, swipeReaction));
Log.d("exercise_name", exercise_name);
}
} catch (JSONException e) {
e.printStackTrace();
}
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
}
}
#Override
public int getCount() {
return mData.size();
}
#Override
public Data getItem(int index) {
if (index < 0 || index >= getCount()) {
throw new IndexOutOfBoundsException("index = " + index);
}
return mData.get(index);
}
#Override
public int undoLastRemoval() {
if (mLastRemovedData != null) {
int insertedPosition;
if (mLastRemovedPosition >= 0 && mLastRemovedPosition < mData.size()) {
insertedPosition = mLastRemovedPosition;
} else {
insertedPosition = mData.size();
}
mData.add(insertedPosition, mLastRemovedData);
mLastRemovedData = null;
mLastRemovedPosition = -1;
return insertedPosition;
} else {
return -1;
}
}
#Override
public void moveItem(int fromPosition, int toPosition) {
if (fromPosition == toPosition) {
return;
}
final ConcreteData item = mData.remove(fromPosition);
mData.add(toPosition, item);
mLastRemovedPosition = -1;
}
#Override
public void removeItem(int position) {
//noinspection UnnecessaryLocalVariable
final ConcreteData removedItem = mData.remove(position);
mLastRemovedData = removedItem;
mLastRemovedPosition = position;
}
public static final class ConcreteData extends Data {
private final long mId;
private final String mText;
private final int mViewType;
private final int mDuration;
private boolean mPinned;
ConcreteData(long id, int viewType, String text, int duration, int swipeReaction) {
mId = id;
mViewType = viewType;
mText = text;
mDuration = duration;
}
#Override
public int getViewType() {
return mViewType;
}
#Override
public int getDuration() {
return mDuration;
}
#Override
public long getId() {
return mId;
}
#Override
public String toString() {
return mText;
}
#Override
public String getText() {
return mText;
}
#Override
public boolean isPinned() {
return mPinned;
}
#Override
public void setPinned(boolean pinned) {
mPinned = pinned;
}
}
}
RecyclerListViewFragment
public class RecyclerListViewFragment extends Fragment {
private RecyclerView mRecyclerView;
private RecyclerView.LayoutManager mLayoutManager;
private RecyclerView.Adapter mAdapter;
private RecyclerView.Adapter mWrappedAdapter;
private RecyclerViewDragDropManager mRecyclerViewDragDropManager;
private RecyclerViewSwipeManager mRecyclerViewSwipeManager;
private RecyclerViewTouchActionGuardManager mRecyclerViewTouchActionGuardManager;
public RecyclerListViewFragment() {
super();
}
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_recycler_list_view, container, false);
}
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
//noinspection ConstantConditions
mRecyclerView = (RecyclerView) getView().findViewById(R.id.recycler_view);
mLayoutManager = new LinearLayoutManager(getContext());
// touch guard manager (this class is required to suppress scrolling while swipe-dismiss animation is running)
mRecyclerViewTouchActionGuardManager = new RecyclerViewTouchActionGuardManager();
mRecyclerViewTouchActionGuardManager.setInterceptVerticalScrollingWhileAnimationRunning(true);
mRecyclerViewTouchActionGuardManager.setEnabled(true);
// drag & drop manager
mRecyclerViewDragDropManager = new RecyclerViewDragDropManager();
mRecyclerViewDragDropManager.setDraggingItemShadowDrawable(
(NinePatchDrawable) ContextCompat.getDrawable(getContext(), R.drawable.material_shadow_z3));
// swipe manager
mRecyclerViewSwipeManager = new RecyclerViewSwipeManager();
//adapter
final MyDraggableSwipeableItemAdapter myItemAdapter = new MyDraggableSwipeableItemAdapter(getDataProvider());
myItemAdapter.setEventListener(new MyDraggableSwipeableItemAdapter.EventListener() {
#Override
public void onItemRemoved(int position) {
((DraggableSwipeableExampleActivity) getActivity()).onItemRemoved(position);
}
#Override
public void onItemViewClicked(View v, boolean pinned) {
onItemViewClick(v, pinned);
}
});
mAdapter = myItemAdapter;
mWrappedAdapter = mRecyclerViewDragDropManager.createWrappedAdapter(myItemAdapter); // wrap for dragging
mWrappedAdapter = mRecyclerViewSwipeManager.createWrappedAdapter(mWrappedAdapter); // wrap for swiping
final GeneralItemAnimator animator = new SwipeDismissItemAnimator();
animator.setSupportsChangeAnimations(false);
mRecyclerView.setLayoutManager(mLayoutManager);
mRecyclerView.setAdapter(mWrappedAdapter); // requires *wrapped* adapter
mRecyclerView.setItemAnimator(animator);
// additional decorations
//noinspection StatementWithEmptyBody
if (supportsViewElevation()) {
// Lollipop or later has native drop shadow feature. ItemShadowDecorator is not required.
} else {
mRecyclerView.addItemDecoration(new ItemShadowDecorator((NinePatchDrawable) ContextCompat.getDrawable(getContext(), R.drawable.material_shadow_z1)));
}
mRecyclerView.addItemDecoration(new SimpleListDividerDecorator(ContextCompat.getDrawable(getContext(), R.drawable.list_divider_h), true));
mRecyclerViewTouchActionGuardManager.attachRecyclerView(mRecyclerView);
mRecyclerViewSwipeManager.attachRecyclerView(mRecyclerView);
mRecyclerViewDragDropManager.attachRecyclerView(mRecyclerView);
}
#Override
public void onPause() {
mRecyclerViewDragDropManager.cancelDrag();
super.onPause();
}
#Override
public void onDestroyView() {
if (mRecyclerViewDragDropManager != null) {
mRecyclerViewDragDropManager.release();
mRecyclerViewDragDropManager = null;
}
if (mRecyclerViewSwipeManager != null) {
mRecyclerViewSwipeManager.release();
mRecyclerViewSwipeManager = null;
}
if (mRecyclerViewTouchActionGuardManager != null) {
mRecyclerViewTouchActionGuardManager.release();
mRecyclerViewTouchActionGuardManager = null;
}
if (mRecyclerView != null) {
mRecyclerView.setItemAnimator(null);
mRecyclerView.setAdapter(null);
mRecyclerView = null;
}
if (mWrappedAdapter != null) {
WrapperAdapterUtils.releaseAll(mWrappedAdapter);
mWrappedAdapter = null;
}
mAdapter = null;
mLayoutManager = null;
super.onDestroyView();
}
private void onItemViewClick(View v, boolean pinned) {
int position = mRecyclerView.getChildAdapterPosition(v);
if (position != RecyclerView.NO_POSITION) {
((DraggableSwipeableExampleActivity) getActivity()).onItemClicked(position);
}
}
public AbstractDataProvider getDataProvider() {
return ((DraggableSwipeableExampleActivity) getActivity()).getDataProvider();
}
public void notifyItemChanged(int position) {
mAdapter.notifyItemChanged(position);
}
public void notifyItemInserted(int position) {
mAdapter.notifyItemInserted(position);
mRecyclerView.scrollToPosition(position);
}
}
To update recyclerView from onPostExecute in a data provider class, your onPostExecute should have access to context where your recyclerView is defined.
Since your FetchExercise async task is defined inside ExerciseDataProvider class, try passing activity context to ExerciseDataProvider's constructor and then pass it on to FetchExercise async task as described here: getting context in AsyncTask
public class MyCustomTask extends AsyncTask<Void, Void, Long> {
private Context mContext;
public MyCustomTask (Context context){
mContext = context;
}
protected void onPostExecute(Long result) {
//use mContext to update recycler view
}
}
}
Use the context to update the recyclerView.
UPDATE
Step 1
Define an interface that will notify your activity of data set change inside a class that initialises your data provider class and pass activity context to constructor of data provider class.
public class ExampleDataProviderFragment extends Fragment {
private AbstractDataProvider mDataProvider;
//Define an interface that will notify your activity of data set change
public interface EventListener {
void onNotifyDataSetChanged();
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
//Pass activity context to ExerciseDataProvider
mDataProvider = new ExerciseDataProvider(getActivity());
}
public AbstractDataProvider getDataProvider() {
return mDataProvider;
}
}
Step 2
Add context parameter to ExerciseDataProvider's constructor and use it to notify activity that implements your interface to notify dataset change.
public class ExerciseDataProvider extends AbstractDataProvider {
private List<ConcreteData> mData;
private ConcreteData mLastRemovedData;
private int mLastRemovedPosition = -1;
//Add context parameter to constructor
public ExerciseDataProvider(Context context) {
//Pass context to async task
new FetchExercise(context).execute();
mData = new LinkedList<>();
}
class FetchExercise extends AsyncTask<Void,Void,Integer> {
Context mContext;
public FetchExercise(Context context) {
mContext = context;
}
#Override
protected Integer doInBackground(Void... params) {
...
return 1;
}
#Override
protected void onPostExecute(Integer result) {
super.onPostExecute(result);
//Typecast context to interface defined above
//and notify dataset changes by calling its method
ExampleDataProviderFragment.EventListener eventListener = (ExampleDataProviderFragment.EventListener)mContext;
eventListener.onNotifyDataSetChanged();
}
}
}
Step 3
Implement above defined interface in your activity class and notify recyclerview adapter inside it
public class DraggableSwipeableExampleActivity extends AppCompatActivity
implements ExampleDataProviderFragment.EventListener {
#Override
protected void onCreate(Bundle savedInstanceState) {
...
}
//implement interface method and notify recyclerview of changes
#Override
public void onNotifyDataSetChanged() {
Fragment fragment = getSupportFragmentManager().findFragmentByTag(FRAGMENT_LIST_VIEW);
// you might need to change visibility of `mWrappedAdapter` in the fragment that defines it or create a getter for it so that you can access it here
((RecyclerListViewFragment) fragment).mWrappedAdapter.notifyDataSetChanged();
}
...
}
I think #random is correct you should be notifying your Recycle view on post execute.
#Override
protected void onPostExecute(Void aVoid) {
mRecyclerViewAdapter.notifyDataSetChanged();
super.onPostExecute(aVoid);
}
or if you have done something in your async task to add/delete something in the data set you would do:
#Override
protected void onPostExecute(Void aVoid) {
mRecyclerViewAdapter.notifyItemRemoved(itemposition); // or item added
mRecyclerViewAdapter.notifyDataSetChanged();
super.onPostExecute(aVoid);
}
Hope it helps !
How can I refresh the view of a fragment, when the back button is pressed?
I have tried this in the onResume method of the fragment but it doesn't work.
OK, here is the code
#SuppressWarnings("unused")
public class RestaurantMenuFragment extends Fragment {
private static final String TAG = "MenuItemsFragment";
private static final String CATEGORIES_KEY = "categories";
private static final String SELECTED_CATEGORY_ID_KEY = "category";
private static final String RESTAURANT_KEY = "restaurant123";
private static final String RESTAURANT_KCITY = "city";
private Spinner mCategoriesSpinner;
private ArrayAdapter<CategoriesResponse.Category> mCategoriesAdapter;
private ListView mListView;
private List<MenuItem> mItems;
private MenuItemsAdapter mItemsAdapter;
private EmptyLayout mEmptyLayout;
private Restaurant mRestaurant;
private int mCategoryId;
private List<CategoriesResponse.Category> mCategories;
private RestaurantActivity mActivity;
private MainApplication mApplication;
private CategoriesResponse mCategoriesResponse;
private ActionBar mActionBar;
private Gson mGson;
int categ;
private ObjectGetter mObjectGetter;
public static RestaurantMenuFragment newInstance(Restaurant restaurant) {
RestaurantMenuFragment fragment = new RestaurantMenuFragment();
Bundle args = new Bundle();
args.putString(RESTAURANT_KEY, new Gson().toJson(restaurant));
String dd=restaurant.city;
Log.i("dd12", dd);
fragment.setArguments(args);
return fragment;
}
public RestaurantMenuFragment() {
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mActivity = (RestaurantActivity) getActivity();
mApplication = (MainApplication) mActivity.getApplication();
mActionBar = mActivity.getSupportActionBar();
mGson = new Gson();
mObjectGetter = new ObjectGetter();
mCategories = new ArrayList<CategoriesResponse.Category>();
Log.i("mCategories",""+mCategories);
mItems = new ArrayList<MenuItem>();
Log.i("12345",""+mItems);
mItemsAdapter = new MenuItemsAdapter(getActivity(), mItems);
Bundle args = getArguments();
if (args != null) {
mRestaurant = mGson.fromJson(args.getString(RESTAURANT_KEY),
Restaurant.class);
}
if (savedInstanceState != null) {
mRestaurant = mGson.fromJson(
savedInstanceState.getString(RESTAURANT_KEY),
Restaurant.class);
mCategoryId = savedInstanceState.getInt(SELECTED_CATEGORY_ID_KEY);
mCategoriesResponse = mGson.fromJson(
savedInstanceState.getString(CATEGORIES_KEY),
CategoriesResponse.class);
}
assert mRestaurant != null;
updateCart();
}
public void updateCart() {
View view = mActionBar.getCustomView();
Button cartButton = (Button) view.findViewById(R.id.cartButton);
int nOfItems = 0;
if (mApplication.isCartCreated()) {
nOfItems = mApplication.getCart().getNOfAllItems();
}
cartButton.setText(String.format("%d", nOfItems));
if (nOfItems > 0) {
cartButton.setEnabled(true);
} else {
cartButton.setEnabled(false);
}
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
Gson gson = new Gson();
outState.putString(RESTAURANT_KEY, gson.toJson(mRestaurant));
outState.putInt(SELECTED_CATEGORY_ID_KEY, mCategoryId);
outState.putString(CATEGORIES_KEY, gson.toJson(mCategoriesResponse));
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onViewCreated(view, savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.spinner_list, container, false);
RestaurantActivity activity = (RestaurantActivity) getActivity();
String myDataFromActivity = activity.getMyData();
String myDataFromActivity1 = activity.getMyData1();
Log.i("myDataFromActivity",myDataFromActivity);
Log.i("myDataFromActivity1",myDataFromActivity1);
categ=Integer.parseInt(myDataFromActivity1);
mListView = (ListView) view.findViewById(R.id.list122334);
mListView.setAdapter(mItemsAdapter);
Log.d(TAG,"Querying items url "
+ Urls.menuItemsQuery(mRestaurant.id,categ));
mEmptyLayout = EmptyLayout.with(getActivity()).to(mListView)
.setEmptyMessage(R.string.categories_empty_message)
.showLoading();
loadItems();
return view;
}
private void loadItems() {
mEmptyLayout.showLoading();
mItems.clear();
mObjectGetter.getJsonObjectOrDialog(mActivity,
Urls.menuItemsQuery(mRestaurant.id, categ),
ItemsResponse.class,
new ObjectGetter.OnFinishedListener<ItemsResponse>() {
#Override
public void onFinishedLoadingObject(
ItemsResponse itemsResponse) {
mEmptyLayout.showEmpty();
if (itemsResponse != null
&& itemsResponse.items != null) {
mItems.addAll(itemsResponse.items);
}
mItemsAdapter.notifyDataSetChanged();
}
});
}
private class MenuItemsAdapter extends ArrayAdapter<MenuItem> {
private static final String TAG = "MenuItemsAdapter";
public MenuItemsAdapter(Context context, List<MenuItem> menuItems) {
super(context, 0, menuItems);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
final MenuItem menuItem = getItem(position);
View view = convertView;
final ViewHolder viewHolder;
LayoutInflater inflater;
if (convertView == null) {
inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = inflater.inflate(R.layout.menu_item, parent, false);
viewHolder = new ViewHolder();
viewHolder.name = (TextView) view.findViewById(R.id.name);
viewHolder.description = (TextView) view.findViewById(R.id.description);
viewHolder.price = (TextView) view.findViewById(R.id.price);
viewHolder.add = (Button) view.findViewById(R.id.add);
viewHolder.selectedView = view.findViewById(R.id.selectedView);
viewHolder.remove = (Button) view.findViewById(R.id.remove);
viewHolder.total = (TextView) view.findViewById(R.id.itemTotal);
viewHolder.quantity = (TextView) view.findViewById(R.id.quantity);
view.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
try
{
viewHolder.name.setText(menuItem.name);
viewHolder.description.setText(menuItem.description);
viewHolder.price.setText(String.valueOf(menuItem.price));
}catch(NullPointerException e){
e.printStackTrace();
}
viewHolder.add.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mApplication.createNewCartIfPossibleAndAskIfNot(
getActivity(), mRestaurant,
new MainApplication.OnCreateCartListener() {
#Override
public void onCreateCart(Cart cart) {
cart.addOne(menuItem);
updateItemFromCart(menuItem, viewHolder);
updateCart();
}
});
}
});
viewHolder.remove.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (!mApplication.isCartCreated()) {
return;
}
mApplication.getCart().removeOne(menuItem);
updateItemFromCart(menuItem, viewHolder);
updateCart();
}
});
return view;
}
private void updateItemFromCart(MenuItem menuItem, ViewHolder viewHolder) {
if (!mApplication.isCartCreated()) {
return;
}
int quantity = mApplication.getCart().getNOfItemsOfType(menuItem);
if (quantity > 0) {
viewHolder.selectedView.setVisibility(View.VISIBLE);
} else {
viewHolder.selectedView.setVisibility(View.GONE);
}
viewHolder.quantity.setText(String.valueOf(quantity));
viewHolder.total.setText(String.valueOf(quantity
* menuItem.price));
}
class ViewHolder {
TextView name;
TextView description;
TextView price;
Button add;
View selectedView;
Button remove;
TextView total;
TextView quantity;
}
}
#Override
public void onResume() {
super.onResume();
updateCart();
mItems.clear();
if (mItemsAdapter != null) {
mItemsAdapter.notifyDataSetChanged();
}
}
#Override
public void onDestroy() {
if (mObjectGetter != null) {
mObjectGetter.stopRequests();
}
super.onDestroy();
}
}
Now, i want to update the listvieww data when the user pressed the back button. I set the new loadItems() method in the onResume() Method of the Fragment. This Method is called but the old listview data appears and new data also appears...
Back button should be handled from Activity.
You can override onBackPressed in Activity and call a function on corresponding fragment to reloadItems().
Here are your 3 options I could think of.
Get reference to Fragment and call function to reLoadItems and its better to define an interface for this communication which fragment implements.
Better solution than first one. Add a LocalBroadcast which Activity broadcasts and your fragment listens and updates data on receiving broadcast.
Example for this :
http://luboganev.github.io/blog/messaging-with-localbroadcastmanager/
Otto event bus where both activity and fragment classes are connected to the event bus and they activity publishes event and fragment subscribes to it. This is what I am using for something similar in my application. (But I have pretty frequent asynchronous events that come along. SO I am using this. 2nd option might be sufficient in your case).
Example for this :
http://www.vogella.com/tutorials/JavaLibrary-EventBusOtto/article.html
As ramesh already mentioned, back button handling happens in your activity class that holds the fragments. Here is a simple example, how you can handle these back button events for your fragment.
Activity Code:
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
boolean returnSuperKeyDown = true;
if(keyCode == KeyEvent.KEYCODE_BACK){
Fragment fragment = getYourCurrentFragment();
if (fragment instanceof YourFragment) {
returnSuperKeyDown = ((YourFragment) fragment).onFragmentKeyDown();
}
}
if (returnSuperKeyDown) {
return super.onKeyDown(keyCode, event);
} else {
return true;
}
}
YourFragment Method:
public boolean onFragmentKeyDown() {
updateYourFragment();
return false;
}
#Rithe, #sunder sharma
As per me there is simple to refresh the fragment when come back from other fragment,
We just have to override the onActivityCreated Method for refresh fragment.
Like as
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
//your code which you want to refresh
loadItems();
}
You can also update/refresh the fragment using onStart() method.
public void onStart(){
super.onStart();
//update your fragment
}
This worked fine for me.
call your loadItem() method onHiddenChanged(boolean hidden)method.onHiddenChanged is overrided method
I'm trying to implement a loader which should load some data from a restful api using retrofit. However the content isn't loaded... unless I place a call to workspaceAdapter.notifyDataSetChanged() in my onOptionsItemSelected method. I say place a call because I don't actually have to make the call. Which I find very odd.
The second odd thing about this is that if I change some data on the server and tries to update by click the refresh menu item which should call the same workspaceAdapter.notifyDataSetChanged() nothing happens.
Below is my Activity.
public class WorkspacesActivity extends Activity implements LoaderCallbacks<List<ListviewEntry>> {
private static final String TAG = WorkspacesActivity.class.getSimpleName();
private static final int LOADER_ID = 1;
private RestClient client;
private ProgressBar progressBar;
private WorkspaceAdapter workspaceAdapter;
private ListView listView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_workspaces);
workspaceAdapter = new WorkspaceAdapter(this);
listView = (ListView)findViewById(R.id.listView);
listView.setAdapter(workspaceAdapter);
progressBar = (ProgressBar)findViewById(R.id.workspacesProgressBar);
progressBar.setVisibility(View.VISIBLE);
Bundle extras = getIntent().getExtras();
if(extras == null) {
return;
}
String accessToken = extras.getString(MainActivity.INTENT_ACCESS_TOKEN);
if(accessToken != null) {
client = new RestClient(accessToken);
getLoaderManager().initLoader(LOADER_ID, null, this);
}
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
switch (item.getItemId())
{
case R.id.action_refresh:
workspaceAdapter.notifyDataSetChanged();
// getLoaderManager().getLoader(LOADER_ID).forceLoad();
return true;
case R.id.action_create_organization:
return true;
case R.id.action_settings:
return true;
}
return super.onOptionsItemSelected(item);
}
#Override
public Loader<List<ListviewEntry>> onCreateLoader(int i, Bundle bundle) {
Log.d(TAG, "onCreateLoader");
progressBar.setVisibility(View.VISIBLE);
return new WorkspaceLoader(this, client);
}
#Override
public void onLoadFinished(Loader<List<ListviewEntry>> listLoader, List<ListviewEntry> listviewEntries) {
Log.d(TAG, "onLoadFinished");
progressBar.setVisibility(View.GONE);
workspaceAdapter.setData(listviewEntries);
}
#Override
public void onLoaderReset(Loader<List<ListviewEntry>> listLoader) {
Log.d(TAG, "onLoaderReset");
progressBar.setVisibility(View.VISIBLE);
workspaceAdapter.setData(null);
}
}
My loader.
public class WorkspaceLoader extends AsyncTaskLoader<List<ListviewEntry>> {
private static final String TAG = WorkspaceLoader.class.getSimpleName();
private RestClient client;
public WorkspaceLoader(Context context, RestClient client) {
super(context);
this.client = client;
}
#Override
public void onStartLoading() {
Log.d(TAG, "onStartLoading");
forceLoad();
super.onStartLoading();
}
/**
* Since Organization has (1:m) Workspaces. We need to flatten this structure. A
* List<ListviewEntry> is used as internal data source. So this method request all the
* oganizations associated with a user, extracts organization or workspace id, organization or
* workspace name and stores those with a type indicating weather it's one or the other. This
* list structure can then be passed on to the adapter.
*
* #return listviewEntries
*/
#Override
public List<ListviewEntry> loadInBackground() {
Log.d(TAG, "loadInBackground");
List<Organization> organizations = client.requestOrganizations();
List<ListviewEntry> listviewEntries = new ArrayList<ListviewEntry>();
// Flatten Organizations and Workspaces
for (Organization organization : organizations) {
listviewEntries.add(new ListviewEntry(organization.getOrg_id(), organization.getName(),
ListviewEntry.Type.ORGANIZATION));
for (Workspace workspace : organization.getSpaces()) {
listviewEntries.add(new ListviewEntry(workspace.getSpace_id(), workspace.getName(),
ListviewEntry.Type.WORKSPACE));
}
}
return listviewEntries;
}
#Override
public void deliverResult(List<ListviewEntry> data) {
Log.d(TAG, "deliverResult");
if(isReset())
{
if(data != null) {
releaseResources(data);
return;
}
}
super.deliverResult(data);
}
private void releaseResources(List<ListviewEntry> data) {
Log.d(TAG, "releaseResources");
// For a simple List, there is nothing to do. For something like a Cursor,
// we would close it in this method. All resources associated with the
// Loader should be released here.
}
}
My adapter.
public class WorkspaceAdapter extends BaseAdapter {
private static final String TAG = WorkspaceAdapter.class.getSimpleName();
private List<ListviewEntry> data;
private LayoutInflater layoutInflater;
public WorkspaceAdapter(Context context) {
data = new ArrayList<ListviewEntry>();
layoutInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
public void setData(List<ListviewEntry> data) {
this.data = data;
}
#Override
public int getCount() {
return data.size();
}
#Override
public ListviewEntry getItem(int position) {
return data.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
holder = new ViewHolder();
switch (getItem(position).getType()) {
case WORKSPACE:
convertView = layoutInflater.inflate(R.layout.listview_workspace, null);
holder.textView = (TextView) convertView.findViewById(R.id.listViewRow);
break;
case ORGANIZATION:
convertView = layoutInflater.inflate(R.layout.listview_organization, null);
holder.textView = (TextView) convertView.findViewById(R.id.listViewHeader);
break;
}
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.textView.setText(data.get(position).getName());
return convertView;
}
public static class ViewHolder {
public TextView textView;
}
}
Anyone got a clue about where I'm going wrong?
I've updated my setData method on my adapter si calls notifyDataSetChanged. Eg.
public void setData(List<ListviewEntry> data)
{
this.data = data;
notifyDataSetChanged();
}
That seems to do the trick. But is that how it should be done?