This is the Fragment in which i am capturing Image using camera2basic(google sample).
And this method i am using to update the gallery with the latest captured image:
private void refreshGallery(File file)
{
Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
intent.setData(Uri.fromFile(file));
getActivity().sendBroadcast(intent);
}
And this is the Gallery Fragment where i am showing all the images stored in SD Card:
Here MainActivity is having a ViewPager, which is having 5 Fragments:
FragmentHome
FragmentGallery
FragmentCamera
FragmentStar
FragmentProfile
and inside FragmentGallery, there is an another ViewPager(GalleryViewPager) which is having 2 Fragments:
FragmentPhotos
FragmentVideos
Now as you can see, the CameraFragment is in a ViewPager of MainActivity, and the FragmentPhotos(which is showing all the photos of the gallery) is in another ViewPager inside FragmentGallery.
Now when i click the photo and navigate to FragmentPhotos(inside FragmentGallery), the gallery gets updated and recently clicked pic is shown(only for first time) but as i click more pics and return to FragmentPhotos(inside FragmentGallery) the gallery doesn't gets updated !!! Also when I move to a different tab(other than Tab1, Tab2 and Tab3 ie Tab4 or Tab5) ie when the ViewPager gets detroyed, then the gallery gets updated every time without any problem !!!
Please help me, how to update the fragment inside ViewPager.
Although I tried to update it with notifysetchanged but it had no effect.
To initiate the Gallery i am calling the initGallery() from MainActivity on Tab Selection(when the selected tab is the Gallery Fragment), as:
ViewPager viewPager = (ViewPager) findViewById(R.id.pagerGallery);
GalleryViewPagerAdapter adapter = (GalleryViewPagerAdapter) viewPager.getAdapter();
for (int i = 0; i < adapter.getCount(); i++) {
Fragment fragmentObject = (Fragment) viewPager.getAdapter().instantiateItem(viewPager, i);
if (fragmentObject instanceof FragmentPhotos) {
FragmentPhotos fragment = (FragmentPhotos) fragmentObject;
if (fragment != null) {
((FragmentPhotos) fragment).initGallery();
Log.e("", "Gallery called");
}
}
}
and the following is my PagerAdpater:
public class GalleryViewPagerAdapter extends FragmentStatePagerAdapter {
private final List<Fragment> mFragments = new ArrayList<>();
private final List<String> mFragmentTitles = new ArrayList<>();
int numOfTabs;
public GalleryViewPagerAdapter(FragmentManager fm) {
super(fm);
}
public void addFragment(Fragment fragment, String title)
{
mFragments.add(fragment);
mFragmentTitles.add(title);
}
#Override
public int getItemPosition(Object object) {
return POSITION_NONE;
}
#Override
public Fragment getItem(int position) {
return mFragments.get(position);
}
#Override
public int getCount() {
return mFragments.size();
}
#Override
public CharSequence getPageTitle(int position) {
return mFragmentTitles.get(position);
}
}
Following is initGallery():
public void initGallery()
{
{
new GetImagesFromCard().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
}
and GetImagesFromCard is as follows:
private class GetImagesFromCard extends AsyncTask<Void,LoadedImage,Void>
{
Bitmap bitmap;
ArrayList<LoadedImage> bitmapArrays=new ArrayList<LoadedImage>();
#Override
protected Void doInBackground(Void... params) {
Uri uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
String[] projection = {MediaStore.Images.Media.DATE_TAKEN,MediaStore.Images.Media._ID,MediaStore.Images.Thumbnails._ID,MediaStore.Images.Thumbnails.DATA,MediaStore.Images.Media.DATE_TAKEN};
String orderBy = MediaStore.Images.Media.DATE_TAKEN + " DESC";
Cursor cursor = getActivity().getContentResolver().query(uri, projection, null, null, orderBy);
int columnIndex = cursor.getColumnIndexOrThrow(MediaStore.Images.Media._ID);
int size = cursor.getCount();
if (size==0)
{
}
int imageId =0;
int i=0;
while (i<size && !isCancelled())
{
cursor.moveToPosition(i);
imageId = cursor.getInt(columnIndex);
uri = Uri.withAppendedPath(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "" + imageId);
publishProgress(new LoadedImage(uri.toString()));
if (i==0)
{
new ShowImagesEnlarged(i).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
i++;
}
cursor.close();
return null;
}
#Override
protected void onProgressUpdate(LoadedImage... values) {
super.onProgressUpdate(values);
for (LoadedImage photo: values)
{
imageAdapter.addPhoto(photo);
imageAdapter.notifyDataSetChanged();
bitmapArrays.add(photo);
}
}
#Override
protected void onCancelled() {
Log.e("","Task Cancelled");
super.onCancelled();
}
}
write this line where you extend FragmentPagerAdapter or FragmentStatPagerAdapter
#Override
public int getItemPosition(Object object) {
return POSITION_NONE;
}
it will automatically refresh fragment when you swipe one fragment to another in your viewPager or else you can attach and detach fragment like this
This will refresh current fragment:
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.detach(this).attach(this).commit();
note: You have to put this code in a one-time event like when data is refreshed otherwise your app will be hang too much.. just dont write in onCreat and onCreatView method
Okay what I would suggest is that you create an interface like this:
public interface IContentRefreshableFragment {
void refreshContent()
}
All of your Fragments should implement this interface e.g.:
public class FragmentPhoto implements IContentRefreshableFragment {
#Override
public void refreshContent() {
// You have to refresh your dataset here and push it into your
// adapter, don't forget to call adapter.notifiyDataSetChanged();
initGallery();
}
}
Then you start your Intent for taking a photo with an ResultCode:
public static final String PHOTO_TAKEN = "PHOTO_TAKEN";
startActivityForResult(PhotoActivity.class, PHOTO_TAKEN);
After that in your onActivityResult(...) in your Activity you check for the ResultCode and trigger content refresh:
#Override
public void onActivityResult(..., String requestCode) {
if(requestCode.equals(PHOTO_TAKEN) {
adapter.refreshContent();
}
}
And in your Adapter:
public class GalleryViewPagerAdapter extends FragmentStatePagerAdapter {
private List<IContentRefreshableFragment> mFragments;
public void refreshContent() {
for(IContentRefreshableFragment fragment : mFragments) {
fragment.refreshContent();
}
}
}
So you can handle a bunch of ViewPager Fragments content refreshs without recreating the Fragments every time from any point in your context.
Also you could add Tags to your fragments and refresh just single ones if you modify the methods a little.
Use getChildFragmentManager() in the constructor of your ViewPagerAdapter
ViewPager viewPager = (ViewPager) findViewById(R.id.pagerGallery);
GalleryViewPagerAdapter adapter = new GalleryViewPagerAdapter(getChildFragmentManager());
for (int i = 0; i < adapter.getCount(); i++) {
Fragment fragmentObject = (Fragment) viewPager.getAdapter().instantiateItem(viewPager, i);
if (fragmentObject instanceof FragmentPhotos) {
FragmentPhotos fragment = (FragmentPhotos) fragmentObject;
if (fragment != null) {
((FragmentPhotos) fragment).initGallery();
Log.e("", "Gallery called");
}
}
}
There a issue with some tips in https://code.google.com/p/android/issues/detail?id=55068
I am trying to fetch results from sqllite db in ViewPager using Adapater class
public class AppDetailPagerAdapter extends android.support.v4.app.FragmentStatePagerAdapter {
private List<AppPagingData> mData;
public AppDetailPagerAdapter(FragmentManager fm, List<AppPagingData> data) {
super(fm);
this.mData = data;
}
#Override
public Fragment getItem(int i) {
sCurrentPosition = i;
Fragment fragment = AppDetailFragment.newInstance(mData, i);
return fragment;
}
#Override
public int getCount() {
return mData.size();
}
#Override
public CharSequence getPageTitle(int position) {
return "OBJECT " + (position + 1);
}
}
And my fragment is
public class AppDetailFragment extends Fragment implements LoaderManager.LoaderCallbacks<Cursor> {
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private List<AppPagingData> mData;
private int mCurrentPosition;
private int mToken;
private static final String EXTRA_KEY_APP_DATA = "EXTRA_KEY_APP_DATA";
private static final String EXTRA_KEY_APP_CURR_POSITION = "EXTRA_KEY_APP_CURR_POSITION";
public static AppDetailFragment newInstance(ArrayList<AppPagingData> param1, int currentPosition) {
AppDetailFragment fragment = new AppDetailFragment();
Bundle args = new Bundle();
args.putParcelableArrayList(EXTRA_KEY_APP_DATA, param1);
args.putInt(EXTRA_KEY_APP_CURR_POSITION, currentPosition);
fragment.setArguments(args);
return fragment;
}
public AppDetailFragment() {
// Required empty public constructor
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
getLoaderManager().restartLoader(mToken, null, this);
}
#Override
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
if (loader.getId() == mToken) {
ViewGroup oocsGroup = (ViewGroup) getActivity().findViewById(R.id.oocsGroup);
// Remove all existing timings (except 1 ie header)
//I think this line remove childs for all fragment????
for (int i = oocsGroup.getChildCount() - 1; i >= 1; i--) {
oocsGroup.removeViewAt(i);
}
} else {
cursor.close();
}
}...
Now, the problem is my fragment linear layout items get deleted, as android call my fragment second instance. for e.g. if i select 1st item second will called automatically.
How to avoid layout of first instance to destry because of second.
As your adapter creates a new instance of fragment at getItem(), you are probably loosing the previous fragment to the garbage collector.
You could keep your fragments in an array (or ArrayList) and return fragment from the array at getItem().
like:
// keep created instances of AppDetailFragments
private AppDetailFragment[] frags;
public AppDetailPagerAdapter(FragmentManager fm, List<AppPagingData> data) {
super(fm);
this.data = data;
frags = new AppDetailFragment[data.size()];
// init all frags
for (int i=0;i<data.size();i++) {
frags[i] = AppDetailFragment.newInstance(data, i);
}
}
#Override
public Fragment getItem(int i) {
sCurrentPosition = i;
return frags[i]; // may want to check for arrayindexoutofboundsEx..
}
This way you will keep a reference to all created fragments.
note:
You no longer need to keep the data as for getCount you can return length of frags-array.
im working in one small project about handling feeds im looking to handle the feeds in listview and show details in viewpager and get the same feed when i click on the listview im lost about how i can pass the cursor position to the viewpaver
that it s the complet listfragment
public class EntryListFragmentt extends ListFragment
implements OnItemClickListener ,LoaderManager.LoaderCallbacks<Cursor>{
private static final String TAG = "EntryListFragmentt";
private OnItemSelectedListener mParentOnItemSelectedListener;
/**
* Cursor adapter for controlling ListView results.
*/
private SimpleCursorAdapter mAdapter;
public static ImageLoader imageLoader;
Uri detailUri;
static int pos;
private LoaderManager.LoaderCallbacks<Cursor> mCallbacks;
/**
* Handle to a SyncObserver. The ProgressBar element is visible until the SyncObserver reports
* that the sync is complete.
*
* <p>This allows us to delete our SyncObserver once the application is no longer in the
* foreground.
*/
ConnectionDetector cd;
private Object mSyncObserverHandle;
/**
* Options menu used to populate ActionBar.
*/
private Menu mOptionsMenu;
/**
* Projection for querying the content provider.
*/
private static final String[] PROJECTION = new String[]{
FeedContract.Entry._ID,
FeedContract.Entry.COLUMN_NAME_TITLE,
FeedContract.Entry.COLUMN_NAME_LINK,
FeedContract.Entry.COLUMN_IMAG_LINK,
FeedContract.Entry.COLUMN_TEXT_ENTRY,
FeedContract.Entry.COLUMN_NAME_PUBLISHED
};
// Column indexes. The index of a column in the Cursor is the same as its relative position in
// the projection.
/** Column index for _ID */
private static final int COLUMN_ID = 0;
/** Column index for title */
private static final int COLUMN_TITLE = 1;
/** Column index for link */
private static final int COLUMN_URL_STRING = 2;
/** Column index for published */
private static final int COLUMN_IMAG_LINK = 3;
private static final int COLUMN_TEXT_ENTRY = 4;
private static final int COLUMN_PUBLISHED = 5;
AlertDialogManager alert = new AlertDialogManager();
/**
* List of Cursor columns to read from when preparing an adapter to populate the ListView.
*/
private static final String[] FROM_COLUMNS = new String[]{
FeedContract.Entry.COLUMN_NAME_TITLE,
FeedContract.Entry.COLUMN_NAME_PUBLISHED,
FeedContract.Entry.COLUMN_NAME_LINK
// FeedContract.Entry.COLUMN_TEXT_ENTRY
};
/**
* List of Views which will be populated by Cursor data.
*/
private static final int[] TO_FIELDS = new int[]{
R.id.tx_title_actu,
R.id.tx_date_actu,
R.id.img_actu
// R.id.tx_text_actu
};
/**
* Mandatory empty constructor for the fragment manager to instantiate the
* fragment (e.g. upon screen orientation changes).
*/
public static EntryListFragmentt newInstance() {
return new EntryListFragmentt();
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
}
/**
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
//View view = inflater
// .inflate(R.layout.activity_entry_list, container, false);
return container;
}
**/
/**
* Create SyncAccount at launch, if needed.
*
* <p>This will create a new account with the system for our application, register our
* {#link SyncService} with it, and establish a sync schedule.
*/
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
// Create account, if needed
SyncUtils.CreateSyncAccount(activity);
}
// private void loaddata(){
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mAdapter = new SimpleCursorAdapter(
getActivity(), // Current context
R.layout.actu_listitem, // Layout for individual rows
null, // Cursor
FROM_COLUMNS, // Cursor columns to use
TO_FIELDS, // Layout fields to use
0 // No flags
);
mAdapter.setViewBinder(new SimpleCursorAdapter.ViewBinder() {
private String slink;
#Override
public boolean setViewValue(View view, Cursor cursor, int i) {
if (i == COLUMN_PUBLISHED ) {
// Convert timestamp to human-readable date
Time t = new Time();
t.set(cursor.getLong(i));
((TextView) view).setText(t.format("%Y-%m-%d %H:%M"));
// Drawable fimag = ResourceUtils.getDrawableByName( imaglink, getActivity());
//String faceName = "ic_launcher";
return true;
} else if (i == COLUMN_URL_STRING ){
slink = CursorUtils.getString(FeedContract.Entry.COLUMN_NAME_LINK, cursor).trim();
// int vlink = Integer.parseInt(CursorUtils.getString(FeedContract.Entry.COLUMN_NAME_LINK, cursor));
ImageView vimage =(ImageView) view.findViewById(R.id.img_actu);
//vimage.setImageResource(getActivity().getResources().getIdentifier("app.oc.gov.ma:drawable/"+slink,null,null));
vimage.setImageDrawable(ResourceUtils.getDrawableByName(slink, getActivity()));
// imageLoader=new ImageLoader(getActivity().getApplicationContext());
//imageLoader.DisplayImage(imaglink, vimage);
// vimage.setImageResource(R.drawable.a);
// Let SimpleCursorAdapter handle other fields automatically
return true;
} else {
return false;
}
}
});
mCallbacks = this;
setListAdapter(mAdapter);
setEmptyText(getText(R.string.loading));
getLoaderManager().initLoader(0, null, mCallbacks);
}
#Override
public void onResume() {
super.onResume();
mSyncStatusObserver.onStatusChanged(0);
// Watch for sync state changes
final int mask = ContentResolver.SYNC_OBSERVER_TYPE_PENDING |
ContentResolver.SYNC_OBSERVER_TYPE_ACTIVE;
mSyncObserverHandle = ContentResolver.addStatusChangeListener(mask, mSyncStatusObserver);
}
#Override
public void onPause() {
super.onPause();
if (mSyncObserverHandle != null) {
ContentResolver.removeStatusChangeListener(mSyncObserverHandle);
mSyncObserverHandle = null;
}
}
/**
* Query the content provider for data.
*
* <p>Loaders do queries in a background thread. They also provide a ContentObserver that is
* triggered when data in the content provider changes. When the sync adapter updates the
* content provider, the ContentObserver responds by resetting the loader and then reloading
* it.
*/
#Override
public Loader<Cursor> onCreateLoader(int i, Bundle bundle) {
// We only have one loader, so we can ignore the value of i.
// (It'll be '0', as set in onCreate().)
return new CursorLoader(getActivity(), // Context
FeedContract.Entry.CONTENT_URI, // URI
PROJECTION, // Projection
null, // Selection
null, // Selection args
// null); // Sort
FeedContract.Entry.COLUMN_NAME_PUBLISHED + " desc"); // Sort
}
/**
* Move the Cursor returned by the query into the ListView adapter. This refreshes the existing
* UI with the data in the Cursor.
*/
#Override
public void onLoadFinished(Loader<Cursor> cursorLoader, Cursor cursor) {
mAdapter.changeCursor(cursor);
}
/**
* Called when the ContentObserver defined for the content provider detects that data has
* changed. The ContentObserver resets the loader, and then re-runs the loader. In the adapter,
* set the Cursor value to null. This removes the reference to the Cursor, allowing it to be
* garbage-collected.
*/
#Override
public void onLoaderReset(Loader<Cursor> cursorLoader) {
mAdapter.changeCursor(null);
}
/**
* Create the ActionBar.
*/
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
mOptionsMenu = menu;
inflater.inflate(R.menu.main_actu, menu);
}
/**
* Respond to user gestures on the ActionBar.
*/
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
// If the user clicks the "Refresh" button.
case R.id.menu_refresh:
cd = new ConnectionDetector(getActivity().getApplicationContext());
// Check for internet connection
if (!cd.isConnectingToInternet()) {
// Internet Connection is not present
setEmptyText(getText(R.string.noconnect));
alert.showAlertDialog(getActivity(), "Internet Connection Error",
"Please connect to working Internet connection", false);
}else {
SyncUtils.TriggerRefresh();
return true;
}
return false;
}
return super.onOptionsItemSelected(item);
}
/**
* Load an article in the default browser when selected by the user.
*/
#Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
// TODO Auto-generated method stub
}
#Override
public void onListItemClick(ListView listView, View view, int position, long id) {
super.onListItemClick(listView, view, position, id);
// Get a URI for the selected item, then start an Activity that displays the URI. Any
// Activity that filters for ACTION_VIEW and a URI can accept this. In most cases, this will
// be a browser.
// Get the item at the selected position, in the form of a Cursor.
Cursor c = (Cursor) mAdapter.getItem(position);
// Get the link to the article represented by the item.
Uri detailUri = Uri.parse(FeedContract.Entry.CONTENT_URI + "/" + id);
WhatsOnFragment.newInstance(position, detailUri);
WhatsOnFragment WWhatsOnFragment = new WhatsOnFragment();
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction ft = fragmentManager.beginTransaction();
ft.replace(R.id.frame_container, WWhatsOnFragment);
//ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
//ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
ft.addToBackStack(null);
ft.commit();
}
public int getCount(int cmp) {
return cmp ;
}
public static WhatsOnFragment newInstance(int position,int cmp, Uri detailUri) {
WhatsOnFragment frag = new WhatsOnFragment();
Bundle args = new Bundle();
args.putParcelable(FeedContract.Entry.CONTENT_ITEM_TYPE, detailUri);
args.putInt(WhatsOnFragment.POSITION_KEY, position);
frag.setArguments(args);
return frag;
}
/**
* Set the state of the Refresh button. If a sync is active, turn on the ProgressBar widget.
* Otherwise, turn it off.
*
* #param refreshing True if an active sync is occuring, false otherwise
*/
public void setRefreshActionButtonState(boolean refreshing) {
if (mOptionsMenu == null) {
return;
}
final MenuItem refreshItem = mOptionsMenu.findItem(R.id.menu_refresh);
if (refreshItem != null) {
if (refreshing) {
refreshItem.setActionView(R.layout.actionbar_indeterminate_progress);
} else {
refreshItem.setActionView(null);
}
}
}
/**
* Crfate a new anonymous SyncStatusObserver. It's attached to the app's ContentResolver in
* onResume(), and removed in onPause(). If status changes, it sets the state of the Refresh
* button. If a sync is active or pending, the Refresh button is replaced by an indeterminate
* ProgressBar; otherwise, the button itself is displayed.
*/
private SyncStatusObserver mSyncStatusObserver = new SyncStatusObserver() {
/** Callback invoked with the sync adapter status changes. */
#Override
public void onStatusChanged(int which) {
getActivity().runOnUiThread(new Runnable() {
/**
* The SyncAdapter runs on a background thread. To update the UI, onStatusChanged()
* runs on the UI thread.
*/
#Override
public void run() {
// Create a handle to the account that was created by
// SyncService.CreateSyncAccount(). This will be used to query the system to
// see how the sync status has changed.
Account account = GenericAccountService.GetAccount();
if (account == null) {
// GetAccount() returned an invalid value. This shouldn't happen, but
// we'll set the status to "not refreshing".
setRefreshActionButtonState(false);
return;
}
// Test the ContentResolver to see if the sync adapter is active or pending.
// Set the state of the refresh button accordingly.
boolean syncActive = ContentResolver.isSyncActive(
account, FeedContract.CONTENT_AUTHORITY);
boolean syncPending = ContentResolver.isSyncPending(
account, FeedContract.CONTENT_AUTHORITY);
setRefreshActionButtonState(syncActive || syncPending);
}
});
}
};
}
that it s the fragment detail viewpager
public class WhatsOnFragment extends Fragment implements
LoaderCallbacks<Cursor> {
private static final String TAG="WhatsOnFragment";
private OnItemSelectedListener mParentOnImageSelectedListener;
private Handler mHandler = new Handler();
private TextView mCountdownTextView;
private ViewGroup mRootView;
private Cursor mAnnouncementsCursor;
private LayoutInflater mInflater;
private int mTitleCol = -1;
private int mDateCol = -1;
private int mUrlCol = -1;
//**********************************************''
/** Column index for _ID */
private static final int COLUMN_ID = 0;
/** Column index for title */
private static final int COLUMN_TITLE = 1;
/** Column index for link */
private static final int COLUMN_URL_STRING = 2;
/** Column index for published */
private static final int COLUMN_IMAG_LINK = 3;
private static final int COLUMN_TEXT_ENTRY = 4;
private static final int COLUMN_PUBLISHED = 5;
private static final String[] PROJECTION = new String[]{
FeedContract.Entry._ID,
FeedContract.Entry.COLUMN_NAME_TITLE,
FeedContract.Entry.COLUMN_NAME_LINK,
FeedContract.Entry.COLUMN_IMAG_LINK,
FeedContract.Entry.COLUMN_TEXT_ENTRY,
FeedContract.Entry.COLUMN_NAME_PUBLISHED
};
public static String POSITION_KEY = "position";
private static final int ANNOUNCEMENTS_LOADER_ID = 0;
private Uri detailUri;
public static int vpos;
public static WhatsOnFragment newInstance(int position, Uri detailUri) {
WhatsOnFragment frag = new WhatsOnFragment();
Bundle args = new Bundle();
args.putInt(POSITION_KEY, position);
//args.putParcelable(FeedContract.Entry.CONTENT_ITEM_TYPE, detailUri);
frag.setArguments(args);
return frag;
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
Log.v(TAG, "onAttach");
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//Bundle extras = getArguments();
//vpos = extras.getInt(POSITION_KEY,0);
//vpos = savedInstanceState.getInt(POSITION_KEY, 0);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
mInflater = inflater;
//
mRootView = (ViewGroup) inflater.inflate(R.layout.content_f,
container,false);
refresh();
return mRootView;
}
#Override
public void onDetach() {
super.onDetach();
// mHandler.removeCallbacks(mCountdownRunnable);
getActivity().getContentResolver().unregisterContentObserver(mObserver);
}
private void refresh() {
mHandler.removeCallbacks(mCountdownRunnable);
//mRootView.removeAllViews();
setupDuring();
//getLoaderManager().initLoader(0, null, this);
}
private void setupDuring() {
// Start background query to load announcements
getLoaderManager().initLoader(0, null, this);
getActivity().getContentResolver().registerContentObserver(
FeedContract.Entry.CONTENT_URI, true, mObserver);
}
/**
* Event that updates countdown timer. Posts itself again to
* {#link #mHandler} to continue updating time.
*/
private final Runnable mCountdownRunnable = new Runnable() {
public void run() {
mHandler.postDelayed(new Runnable() {
public void run() {
refresh();
}
}, 100);
return;
}
};
#Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
return new CursorLoader(getActivity(), // Context
FeedContract.Entry.CONTENT_URI, // URI
PROJECTION, // Projection
null, // Selection
null, // Selection args
// null);
FeedContract.Entry.COLUMN_NAME_PUBLISHED + " desc"); // Sort
}
#Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
if (getActivity() == null) {
return;
}
if (data != null && data.getCount() > 0) {
mTitleCol = data.getColumnIndex(FeedContract.Entry.COLUMN_NAME_TITLE);
mDateCol = data.getColumnIndex(FeedContract.Entry.COLUMN_TEXT_ENTRY);
showAnnouncements(data);
}
}
#Override
public void onLoaderReset(Loader<Cursor> loader) {
mAnnouncementsCursor = null;
}
/**
* Show the the announcements
*/
private void showAnnouncements(Cursor announcements) {
mAnnouncementsCursor = announcements;
ViewGroup announcementsRootView = (ViewGroup) mInflater.inflate(
R.layout.detail, mRootView, false);
final ViewPager pager = (ViewPager) announcementsRootView.findViewById(
R.id.pager);
final PagerAdapter adapter = new AnnouncementsAdapter();
pager.setAdapter(adapter);
//pager.setCurrentItem(0);
pager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
#Override
public void onPageSelected(int position) {
pager.setCurrentItem(pager.getCurrentItem());
}
#Override
public void onPageScrollStateChanged(int state) {
// TODO Auto-generated method stub
}
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
// TODO Auto-generated method stub
//Toast.makeText(getActivity().getApplicationContext(),"myposition " + position,Toast.LENGTH_LONG).show();
}
});
//mRootView.removeAllViews();
mRootView.addView(announcementsRootView);
}
public class AnnouncementsAdapter extends PagerAdapter {
#Override
public Object instantiateItem(ViewGroup pager, int position) {
mAnnouncementsCursor.moveToPosition(position);
View rootView = (View) mInflater.inflate(
R.layout.detail_fragment, pager, false);
TextView titleView = (TextView) rootView.findViewById(R.id.title);
TextView subtitleView = (TextView) rootView.findViewById(R.id.description);
//WebView desc = (WebView) rootView.findViewById(R.id.desc);
// Enable the vertical fading edge (by default it is disabled)
ScrollView sv = (ScrollView) rootView.findViewById(R.id.sv);
sv.setVerticalFadingEdgeEnabled(true);
// Set webview properties
//WebSettings ws = desc.getSettings();
//ws.setLayoutAlgorithm(LayoutAlgorithm.SINGLE_COLUMN);
//ws.setLightTouchEnabled(false);
//ws.setPluginState(PluginState.ON);
//ws.setJavaScriptEnabled(true);
titleView.setText(mAnnouncementsCursor.getString(mTitleCol));
subtitleView.setText(mAnnouncementsCursor.getString(mDateCol));
//desc.loadDataWithBaseURL("http://.../",mAnnouncementsCursor.getString(mDateCol), "text/html", "UTF-8", null);
pager.addView(rootView, 0);
return rootView;
}
#Override
public void destroyItem(ViewGroup pager, int position, Object view) {
pager.removeView((View) view);
}
#Override
public int getCount() {
return mAnnouncementsCursor.getCount();
}
#Override
public boolean isViewFromObject(View view, Object object) {
return view.equals(object);
}
#Override
public int getItemPosition(Object object) {
return POSITION_NONE;
}
public Object getItem(int position) {
WhatsOnFragment frag = new WhatsOnFragment();
Bundle args = new Bundle();
args.putInt(POSITION_KEY, position);
//args.putParcelable(FeedContract.Entry.CONTENT_ITEM_TYPE, detailUri);
frag.setArguments(args);
if (position > 0 && position < mAnnouncementsCursor.getCount() - 1) {
return position;
}
return position;
}
}
private final ContentObserver mObserver = new ContentObserver(new Handler()) {
#Override
public void onChange(boolean selfChange) {
if (getActivity() == null) {
return;
}
Loader<Cursor> loader = getLoaderManager().getLoader(ANNOUNCEMENTS_LOADER_ID);
if (loader != null) {
loader.forceLoad();
}
}
};
}
Here's how I am passing my Uri from one activity to another:
After you get the uri from your onListItemClick, add this line of code after that:
String uriString = uri.toString();
Now, you can either do it through shared preference or by passing extras from intent,
Method 1: By shared preference:
SharedPreferences prefs = getSharedPreferences("your_file_name", MODE_PRIVATE);
SharedPreferences.Editor editor = prefs.edit();
editor.putString("uri", uriString);
editor.commit();
Then, in your other activity or where your listview is defined, use this to retrieve the uri,
SharedPreferences mPreferences = mPreferences = getSharedPreferences(MyPREFERENCES, Context.MODE_PRIVATE);
String uri = mPreferences.getString("uri", uri);
//To parse the uri
Uri newUri = Uri.parse(uri);
Then you can use this uri to get the information you want to.
Method 2 : Getting uri from Intent:
First : In you activity where you are getting the Uri,
Intent myIntent = new Intent(SomeActivity1.this, SomeActivity2.class);
myIntent.putExtra("uri", uri);
myIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
myIntent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
setResult(RESULT_OK, myIntent);
startActivity(myIntent);
In your other activity or where your listview is defined, use this to retrieve the uri,
Intent data = getIntent();
Uri uri = data.getParcelableExtra("uri");
Now you can use this uri to get whatever information you are trying to retrieve.
Hope this answer helps .. :)
The code below defines a simple ListView with a listener that calls a simple ViewPager by passing selected item in parameters.
First the list:
public class SampleListFragment extends android.support.v4.app.ListFragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_list, null);
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
final ArrayList<String> list = new ArrayList<String>();
list.add("object1");
list.add("object2");
list.add("object3");
final ArrayAdapter<String> adapter = new ArrayAdapter<String>(getActivity(), android.R.layout.simple_list_item_1, android.R.id.text1, list);
getListView().setAdapter(adapter);
getListView().setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
final String item = (String) adapterView.getItemAtPosition(i);
// Quick and dirty way to call the ViewPager with the selected item
final SampleViewPagerFragment sampleViewPagerFragment = SampleViewPagerFragment.newIntance(item);
getActivity().getSupportFragmentManager().beginTransaction().replace(R.id.fragment_holder, sampleViewPagerFragment).commit();
}
});
}
}
Next the ViewPager:
public class SampleViewPagerFragment extends Fragment {
public static SampleViewPagerFragment newIntance(String text){
final SampleViewPagerFragment sampleViewPagerFragment = new SampleViewPagerFragment();
final Bundle arguments = new Bundle();
arguments.putString("object", text);
sampleViewPagerFragment.setArguments(arguments);
return sampleViewPagerFragment;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
final View view = inflater.inflate(R.layout.fragment_view_pager, null);
final ViewPager viewPager = (ViewPager) view.findViewById(R.id.view_pager);
final Bundle arguments = getArguments();
if(arguments != null){
// We create the adapter with arguments of the fragment
final SampleAdapter adapter = new SampleAdapter(getChildFragmentManager(), (String) arguments.get("object"));
viewPager.setAdapter(adapter);
}
return view;
}
private class SampleAdapter extends FragmentPagerAdapter {
private String object;
public SampleAdapter(FragmentManager fm, String object){
super(fm);
this.object = object;
}
#Override
public int getCount() {
return 2;
}
#Override
public Fragment getItem(int position) {
// We pass the selected item in arguments
return SampleFragment.newInstance(object + " " + position);
}
}
}
Finally the fragment that displays the content:
public class SampleFragment extends Fragment {
public static SampleFragment newInstance(String text){
final SampleFragment sampleFragment = new SampleFragment();
final Bundle arguments = new Bundle();
arguments.putString("text", text);
sampleFragment.setArguments(arguments);
return sampleFragment;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
final TextView textView = new TextView(getActivity());
final Bundle arguments = getArguments();
if(arguments != null){
textView.setText((String) arguments.get("text"));
}
return textView;
}
}
I hope it is what you are looking for..
I'm having a ViewPager with a FragmentStatePagerAdapter that shows items from a ContentProvider via a CursorAdapter. So there is a callback when data is changed in the content provider that automatically creates/removes pages.
When I create a new item via ContentResolver.insert() from another fragment I want to show the created page in the ViewPager.
To show a page I call ViewPager.setCurrentItem(). But it seems that directly after the insert call the ViewPager is not yet updated. When and where do I call that?
Edit:
Here is my MainActivity:
I'm having one fragment for creation of items (on position 0) and several items from the content provider. From the creation fragment I call insert on the content resolver.
public class MainActivity extends FragmentActivity implements
LoaderManager.LoaderCallbacks<Cursor> {
SectionsPagerAdapter mSectionsPagerAdapter;
SimpleCursorAdapter mCommitmentAdapter;
private static final byte LOADER_ID = 0;
private static final String TAG = MainActivity.class.getName();
ViewPager mViewPager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Adapter for commitment names and ids
mCommitmentAdapter = new SimpleCursorAdapter(this,
android.R.layout.simple_dropdown_item_1line, null,
new String[] { Commitment.Columns.NAME },
new int[] { android.R.id.text1 }, 0);
// Adapter for the saved commitments
mSectionsPagerAdapter = new SectionsPagerAdapter(
getSupportFragmentManager(), mCommitmentAdapter);
// Set up the ViewPager with the sections adapter.
mViewPager = (ViewPager) findViewById(R.id.pager);
mViewPager.setAdapter(mSectionsPagerAdapter);
getSupportLoaderManager().initLoader(LOADER_ID, null, this);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
#Override
public final Loader<Cursor> onCreateLoader(int id, final Bundle args) {
....
}
#Override
public final void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
mCommitmentAdapter.swapCursor(cursor);
}
#Override
public final void onLoaderReset(Loader<Cursor> loader) {
mCommitmentAdapter.swapCursor(null);
}
public final void showPageWithCommitmentId(long id) {
// this is called after contentresolver.insert
// but it does not work
mViewPager.setCurrentItem(mSectionsPagerAdapter.getItemPosition(id));
}
#Override
protected void onDestroy() {
if (mSectionsPagerAdapter != null) {
mSectionsPagerAdapter.destroy();
}
getLoaderManager().destroyLoader(LOADER_ID);
super.onDestroy();
}
public class SectionsPagerAdapter extends FragmentStatePagerAdapter {
final CursorAdapter wrappedAdapter;
final DataSetObserver subObserver;
public SectionsPagerAdapter(FragmentManager fm,
SimpleCursorAdapter adapter) {
super(fm);
this.wrappedAdapter = adapter;
subObserver = new DataSetObserver() {
#Override
public void onChanged() {
notifyDataSetChanged();
}
#Override
public void onInvalidated() {
// Probably destroying the loader
}
};
if (wrappedAdapter != null)
wrappedAdapter.registerDataSetObserver(subObserver);
}
public void destroy() {
if (wrappedAdapter != null) {
wrappedAdapter.unregisterDataSetObserver(subObserver);
}
}
#Override
public Fragment getItem(int position) {
if (position == 0) {
Fragment fragment = CreateCommitmentSectionFragment
.getInstance(position);
return fragment;
} else {
// create new ShowCommitSectionFragment
Fragment fragment = ShowCommitmentSectionFragment.getInstance(
getItemId(position), getPageTitle(position).toString());
return fragment;
}
}
public long getItemId(int position) {
long id = 0;
if (wrappedAdapter != null && position > 0) {
Cursor c = (Cursor) wrappedAdapter.getItem(position - 1);
if (c != null && !c.isAfterLast() && !c.isBeforeFirst()) {
id = c.getLong(0);
}
}
return id;
}
#Override
public int getCount() {
if (wrappedAdapter != null)
return 1 + wrappedAdapter.getCount();
else
return 1;
}
#Override
public CharSequence getPageTitle(int position) {
if (position >= getCount())
return null;
if (position == 0) {
return MainActivity.this.getString(R.string.main_create_create);
}
Cursor c = (Cursor) wrappedAdapter.getItem(position - 1);
if (c != null && !c.isAfterLast() && !c.isBeforeFirst()) {
return c.getString(1);
}
return null;
}
#Override
public int getItemPosition(Object object) {
Fragment f = (Fragment) object;
long listId = 0;
if (f instanceof ShowCommitmentSectionFragment) {
listId = f.getArguments().getLong(
ShowCommitmentSectionFragment.ARG_COMMITMENT_ID);
}
return getItemPosition(listId);
}
/**
* Get the position of the given commitment id.
*
* #param commitmentId
* #return
*/
public int getItemPosition(final long commitmentId) {
int length = getCount();
int result = POSITION_NONE;
int position;
for (position = 0; position < length; position++) {
if (commitmentId == getItemId(position)) {
result = position;
break;
}
}
return result;
}
}
}
I have a ViewPager hosted in a fragment that hosts two ListFragments that are populated by a Cursor returned from an SQLite query. I recently added a spinner to my Action Bar that will allow the user to sort the lists in the ViewPager. However, every time the spinner is selected, only the second list is sorted even when the first list is currently displayed. It seems like the ViewPager is not keeping track of the currently displayed ListFragment.
I have tried overriding getItemPosition in my adapter and using notifyDataSetChanged, but that doesn't help. I tried caching the position of the current active fragment in onAttach() also to no avail. I also tried using an OnSortChanged interface implemented by my adapter to try and recreate the ListFragments. I'm truly at a loss here. Here is my current code:
My main fragment:
public class BeerMenuFragment extends SherlockFragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.beer_menu_fragment, container,
false);
ViewPager pager = (ViewPager) view.findViewById(R.id.beer_pager);
pager.setAdapter(buildAdapter());
return view;
}
private PagerAdapter buildAdapter() {
return (new BeerMenuAdapter(getChildFragmentManager()));
}
}
My FragmentPagerAdapter:
public class BeerMenuAdapter extends FragmentPagerAdapter {
private final int NUM_ITEMS = 2;
public BeerMenuAdapter(FragmentManager fm) {
super(fm);
}
/*
* (non-Javadoc)
*
* #see android.support.v4.view.PagerAdapter#getPageTitle(int)
*/
#Override
public CharSequence getPageTitle(int position) {
return BeerListFragment.getTitle(position);
}
#Override
public int getCount() {
return NUM_ITEMS;
}
#Override
public Fragment getItem(int position) {
return BeerListFragment.newInstance(position);
}
}
And finally, the ListFragment:
public class BeerListFragment extends SherlockListFragment implements
OnNavigationListener {
private static final String KEY_POSITION = "position";
private static final String KEY_SPINNER = "ab_spinner";
private IconicAdapter adapter;
private static final String[] LABELS = { "Newest First", "Oldest First",
"Alphabetical" };
private Context ctxt;
private int mShowItems;
private Cursor data;
private boolean synthetic = true;
static BeerListFragment newInstance(int position) {
BeerListFragment frag = new BeerListFragment();
Bundle args = new Bundle();
args.putInt(KEY_POSITION, position);
frag.setArguments(args);
return (frag);
}
static String getTitle(int position) {
String header = "Draft";
switch (position) {
case 0:
header = "Draft";
break;
case 1:
header = "Bottle";
break;
}
return (header);
}
/*
* (non-Javadoc)
*
* #see
* android.support.v4.app.ListFragment#onCreateView(android.view.LayoutInflater
* , android.view.ViewGroup, android.os.Bundle)
*/
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View result = inflater.inflate(R.layout.menu_list_fragment, container,
false);
ctxt = getActivity().getApplicationContext();
SQLiteDatabase db = DatabaseHelper.getInstance(ctxt)
.getReadableDatabase();
SherlockFragmentActivity activity = getSherlockActivity();
ArrayAdapter<String> show = null;
ActionBar bar = activity.getSupportActionBar();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
show = new ArrayAdapter<String>(bar.getThemedContext(),
android.R.layout.simple_spinner_item, LABELS);
} else {
show = new ArrayAdapter<String>(activity,
android.R.layout.simple_spinner_item, LABELS);
}
show.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
bar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);
bar.setListNavigationCallbacks(show, this);
if (savedInstanceState != null) {
bar.setSelectedNavigationItem(savedInstanceState
.getInt(KEY_SPINNER));
}
data = getBeerMenuDbData(db, mShowItems);
// set up list adapter
adapter = new IconicAdapter(ctxt, data);
setListAdapter(adapter);
return (result);
}
private Cursor getBeerMenuDbData(SQLiteDatabase db, int showItems) {
String order;
String WHERE;
switch (showItems) {
case 1: // Oldest First
order = DbContract.BeerEntry.COLUMN_MODIFIED + " ASC";
break;
case 2: // Alphabetical
order = DbContract.BeerEntry.COLUMN_TITLE + " ASC";
break;
default: // Newest first
order = DbContract.BeerEntry.COLUMN_MODIFIED + " DESC";
break;
}
String[] COLUMNS = { DbContract.BeerEntry._ID,
DbContract.BeerEntry.COLUMN_TITLE,
DbContract.BeerEntry.COLUMN_MODIFIED };
WHERE = "serving='" + getTitle(getArguments().getInt(KEY_POSITION, -1))
+ "'";
return db.query(DbContract.BeerEntry.TABLE_NAME, COLUMNS, WHERE, null,
null, null, order);
}
class IconicAdapter extends CursorAdapter {
LayoutInflater inflater;
IconicAdapter(Context context, Cursor data) {
super(context, data, 0);
inflater = LayoutInflater.from(context);
}
#Override
public void bindView(View view, Context context, Cursor cursor) {
String dateString = cursor.getString(2);
String[] dateArray = new String[3];
TextView beerName = (TextView) view.findViewById(R.id.beerName);
TextView date = (TextView) view.findViewById(R.id.drinkDate);
RatingBar rb = (RatingBar) view.findViewById(R.id.ratingBar1);
beerName.setText(cursor.getString(1));
if (!dateString.isEmpty()) {
dateArray = dateString.split("-");
date.setText(dateArray[1] + "/" + dateArray[2] + "/"
+ dateArray[0]);
} else {
date.setText(dateString);
}
rb.setRating((float) Math.random() * 5.0f);
}
#Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
return inflater
.inflate(R.layout.beer_club_list_item, parent, false);
}
}
/*
* (non-Javadoc)
*
* #see android.support.v4.app.Fragment#onDestroy()
*/
#Override
public void onDestroy() {
super.onDestroy();
((CursorAdapter) getListAdapter()).getCursor().close();
}
#Override
public boolean onNavigationItemSelected(int itemPosition, long itemId) {
if (synthetic) {
synthetic = false;
return true;
}
mShowItems = itemPosition;
SQLiteDatabase db = DatabaseHelper.getInstance(ctxt)
.getReadableDatabase();
Cursor newData = getBeerMenuDbData(db, mShowItems);
adapter.changeCursor(newData);
return true;
}
#Override
public void onSaveInstanceState(Bundle outState) {
outState.putInt(KEY_SPINNER, getSherlockActivity()
.getSupportActionBar().getSelectedNavigationIndex());
}
}
Thanks in advance for any help!
So, your problem is that you are calling bar.setListNavigationCallbacks(show, this) inside of your BeerListFragments. When your 1st BeerListFragment is created in your ViewPager, it sets itself as the callback for the navigation selections. Then, when your 2nd BeerListFragment is created (ViewPagers resumes pages to the left and right of the currently visible page), it sets itself as the callback for the navigation selections, and overwrites the 1st BeerListFragment, which now will no longer get the onNavigationItemSelected callback.
This all results with the behavior you are seeing, the last BeerListFragment to call bar.setListNavigationCallbacks will be the only one to receive the onNavigationItemSelected callback. This is why only the 2nd BeerListFragment is being sorted.
To solve this, I would recommend you do a few things:
Manage setting the callback for the navigation selections in the BeerMenuFragment, and pass the results to the children Fragments that are in "alive" (in onResume). You will need to use one of the answers here in order to do so.
Store the the latest sort option applied, and check in onResume of each BeerListFragment to see if its sort matches, and if not, apply the sort.
This will guarantee that all of your sorts are applied to all of your pages in the ViewPager, whether they are displayed or not at the time of the sort being applied.