I have a GridView that is implemented within an Activity and a Fragment, and contain its own Adapter. It works great, until scrolling, when I try to scroll it appears to leave a background of the first items loaded.
Here's the code I am implementing:
Activity Class
public class FavoriteActivity extends ActionBarActivity {
private final String LOG_TAG = FavoriteActivity.class.getSimpleName();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_favorite);
if (savedInstanceState == null) {
getSupportFragmentManager().beginTransaction()
.add(R.id.container, new FavoriteListFragment())
.commit();
}
}
#Override
protected void onResume() {
super.onResume();
FavoriteListFragment fragment = (FavoriteListFragment)getSupportFragmentManager().findFragmentById(R.id.container);
if ( null != fragment ) {
fragment.onRestartLoader();
}
}
}
Fragment Class
public class FavoriteListFragment extends Fragment implements LoaderManager.LoaderCallbacks<Cursor> {
public static final String LOG_TAG = FavoriteListFragment.class.getSimpleName();
private static final int LOADER = 0;
private static final String SELECTED_KEY = "selected_position";
private ResultListAdapter mAdapter;
private GridView mGridView;
private int mPosition = ListView.INVALID_POSITION;
public static final String[] SMCONTENT_COLUMNS = {
SMDBContract.SMContentEntry.COLUMN_TITLE,
};
static final int COL_TITLE = 0;
#Override
public void onActivityCreated(Bundle savedInstanceState) {
getLoaderManager().initLoader(LOADER, null, this);
super.onActivityCreated(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater,
ViewGroup container,
Bundle savedInstanceState) {
mAdapter = new ResultListAdapter(getActivity(), null, 0);
mAdapter.setIsFavoriteView(true);
View rootView = inflater.inflate(R.layout.fragment_favorite, container, false);
mGridView = (GridView) rootView.findViewById(R.id.listview_sm_content_favorite);
mGridView.setAdapter(mAdapter);
if (savedInstanceState != null && savedInstanceState.containsKey(SELECTED_KEY)) {
mPosition = savedInstanceState.getInt(SELECTED_KEY);
}
return rootView;
}
void onRestartLoader() {
getLoaderManager().restartLoader(LOADER, null, this);
}
#Override
public void onSaveInstanceState(Bundle outState) {
// When tablets rotate, the currently selected list item needs to be saved.
// When no item is selected, mPosition will be set to Listview.INVALID_POSITION,
if (mPosition != ListView.INVALID_POSITION) {
outState.putInt(SELECTED_KEY, mPosition);
}
super.onSaveInstanceState(outState);
}
#Override
public Loader<Cursor> onCreateLoader(int i, Bundle bundle) {
String favs = Utility.getFavoritesIds(getActivity());
Uri resultSearchURI = SMDBContract.SMContentEntry
.buildSMContentMultiple(SMDBContract.CATEGORY_SERIE, favs);
Log.d(LOG_TAG,"PREFS URI: "+resultSearchURI);
return new CursorLoader(getActivity(),
resultSearchURI,
SMCONTENT_COLUMNS,
null,
null,
null);
}
#Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
mAdapter.swapCursor(data);
mAdapter.setCursor(data);
if (mPosition != ListView.INVALID_POSITION) {
mGridView.smoothScrollToPosition(mPosition);
}
}
#Override
public void onLoaderReset(Loader<Cursor> loader) {
mAdapter.swapCursor(null);
}
}
Adapter
public class ResultListAdapter extends CursorAdapter {
private Context mContext;
private Cursor mCursor;
public ResultListAdapter(Context context, Cursor c, int flags) {
super(context, c, flags);
mContext = context;
mCursor = c;
}
public Cursor getCursor() {
return mCursor;
}
public void setCursor(Cursor mCursor) {
this.mCursor = mCursor;
}
public static class ViewHolder {
public final ImageView iconView;
public final TextView titleView;
public ViewHolder(View view) {
iconView = (ImageView) view.findViewById(R.id.list_item_icon);
titleView = (TextView) view.findViewById(R.id.list_item_title_textView);
}
}
#Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
View view = LayoutInflater.from(context).inflate(R.layout.grid_item, parent, false);
ViewHolder viewHolder = new ViewHolder(view);
view.setTag(viewHolder);
return view;
}
#Override
public void bindView(View view, Context context, Cursor cursor) {
ViewHolder viewHolder = (ViewHolder) view.getTag();
if (viewHolder.iconView != null) {
Picasso.with(context)
.load(cursor.getString(ResultListFragment.COL_POSTER))
.fit()
.centerInside()
.into(viewHolder.iconView);
}
if (viewHolder.titleView != null)
viewHolder.titleView.setText(cursor.getString(ResultListFragment.COL_TITLE));
}
}
Activity Layout
<fragment
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:name=".FavoriteListFragment"
tools:context=".FavoriteListFragment"
tools:layout="#android:layout/list_content" />
Fragment Layout
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="![enter image description here][1].FavoriteListFragment">
<GridView
android:id="#+id/listview_sm_content_favorite"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:columnWidth="100dp"
android:numColumns="auto_fit"
android:verticalSpacing="5dp"
android:horizontalSpacing="5dp"
android:stretchMode="columnWidth"
android:gravity="center"
/>
</FrameLayout>
Grid Item Layout
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<FrameLayout
android:layout_width="100dp"
android:layout_height="150dp"
android:layout_gravity="center"
>
<ImageView
android:id="#+id/list_item_icon"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="#mipmap/ic_launcher"/>
</FrameLayout>
<TextView
android:id="#+id/list_item_title_textView"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:fontFamily="sans-serif-light"
android:layout_gravity="center"
android:textAppearance="?android:textAppearanceMedium"
android:text="My Item Title"/>
</LinearLayout>
UPDATE:
I just found out that by removing this code from the FavoriteActivity.onCreate the error stops... but why!? can somebody tell me
if (savedInstanceState == null) {
getSupportFragmentManager().beginTransaction()
.add(R.id.container, new FavoriteListFragment())
.commit();
}
Remove following lines from your Grid Item Layout:
from ImageView remove:
android:src="#mipmap/ic_launcher"
from TextView remove:
android:text="My Item Title"
Related
I am trying to scroll to the selected position after screen rotation but nothing is happening.
I have tried many suggestions, but none is working (setSelection, own smooth scroll...)
public class MovieFragment extends Fragment {
// The customised movie adapter
private MovieAdapter mMovieAdapter;
private GridView mGridView;
private static final String SELECTED_POSTER = "stored_position";
private int mPosition = GridView.INVALID_POSITION;
public interface Callback {
/**
* DetailFragmentCallback for when an item has been selected.
*/
void onItemSelectedNormal (Movie movie);
}
public MovieFragment() {
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
/**
* Function that makes an Async call for the fetch function while passing the sort criteria from the shared preferences.
*/
public void updateMovies (String sortCriteria) {
FetchMoviesTask fmt = new FetchMoviesTask(getActivity(), mMovieAdapter);
fmt.execute(sortCriteria);
}
#Override
public void onStart() {
super.onStart();
}
public void onSortChange () {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getActivity());
String sortCriteria = prefs.getString(getString(R.string.pref_criteria_key), getString(R.string.pref_criteria_default));
updateMovies(sortCriteria);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
mMovieAdapter = new MovieAdapter(getActivity(), new ArrayList<Movie>());
View rootView = inflater.inflate(R.layout.fragment_movie, container, false);
mGridView = (GridView) rootView.findViewById(R.id.gridview_movie);
mGridView.setAdapter(mMovieAdapter);
// Handle a click on a poster.
mGridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
Movie movie = mMovieAdapter.getItem(i); // Get the movie object at the appropriate position.
((Callback) getActivity()).onItemSelectedNormal(movie);
mPosition = i;
}
});
if (savedInstanceState != null && savedInstanceState.containsKey(SELECTED_POSTER)) {
mPosition = savedInstanceState.getInt(SELECTED_POSTER);
}
//onSortChange();
return rootView;
}
#Override
public void onSaveInstanceState(Bundle outState) {
if (mPosition != GridView.INVALID_POSITION){
outState.putInt(SELECTED_POSTER, mPosition);
}
super.onSaveInstanceState(outState);
}
#Override
public void onViewStateRestored(#Nullable Bundle savedInstanceState) {
super.onViewStateRestored(savedInstanceState);
if (mPosition != GridView.INVALID_POSITION) {
mGridView.smoothScrollToPosition(mPosition);
}
}
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
onSortChange();
}
}
Here is my adapter:
public class MovieAdapter extends ArrayAdapter<Movie> {
private static final String LOG_TAG = MovieAdapter.class.getSimpleName();
public MovieAdapter(Activity context, ArrayList<Movie> movies) {
super(context, 0, movies);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// Gets the Movie object from the ArrayAdapter at the appropriate position
Movie movie = getItem(position);
if (convertView == null) {
convertView = LayoutInflater.from(getContext()).inflate(
R.layout.movie_poster, parent, false);
}
ImageView imageView = (ImageView) convertView.findViewById(R.id.poster_view);
Picasso.with(convertView.getContext()).load(movie.getImageURL()).into(imageView);
return convertView;
}
}
My fragment layout:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- TODO: Update blank fragment layout -->
<GridView
android:id="#+id/gridview_movie"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:verticalSpacing="0dp"
android:horizontalSpacing="0dp"
android:numColumns="auto_fit"
style="#style/MovieGridStyle"
android:stretchMode="columnWidth" />
<TextView
android:id="#+id/no_data_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="#string/empty_fav_list"
android:visibility="invisible"
android:gravity="center"
android:textColor="#bfafaf"
android:textSize="25sp" />
</RelativeLayout>
My images layout, named movie_poster:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="10sp"
android:background="#drawable/touch_selector">
<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:scaleType="fitXY"
android:id="#+id/poster_view"
android:adjustViewBounds="true"/>
</FrameLayout>
In my app,I get some data from my server. They are displayed fine,but when I pass them in my Detailed Fragment,then all views are null:(.
So here is my code.
public class MainActivityFragment extends Fragment {
public static final String TAG = "AelApp";
public static ArrayList<MyModel> listItemsList;
RecyclerView myList;
public static MatchReportsAdapter adapter;
public MainActivityFragment() {
// Required empty public constructor
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
updateMatchReport();
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
getActivity().setTitle("Match Report");
View rootView = inflater.inflate(R.layout.fragment_main_activity, container, false);
listItemsList = new ArrayList<>();
myList = (RecyclerView)rootView.findViewById(R.id.listview_match_reports);
final LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getActivity());
myList.setHasFixedSize(true);
myList.setLayoutManager(linearLayoutManager);
adapter = new MatchReportsAdapter(getActivity(), listItemsList);
myList.setAdapter(adapter);
return rootView;
}
public void updateMatchReport(){
Intent i = new Intent(getActivity(), MatchReport.class);
getActivity().startService(i);
}
}
Adapter
public class MatchReportsAdapter extends
RecyclerView.Adapter<MatchReportsAdapter.RowHolder>{
private List<MyModel> reportsList;
private Context mContext;
private ImageLoader mImageLoader;
private int focused = 0;
public MatchReportsAdapter(Activity activity, List<MyModel> reportsLists){
this.reportsList = reportsLists;
this.mContext=activity;
}
#Override
public RowHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.row_items,null);
final RowHolder holder = new RowHolder(v);
return holder;
}
#Override
public void onBindViewHolder(RowHolder holder, int position) {
final MyModel listItems = reportsList.get(position);
holder.itemView.setSelected(focused==position);
holder.getLayoutPosition();
mImageLoader = AppController.getInstance().getImageLoader();
holder.thumbnail.setImageUrl(listItems.getImage(),mImageLoader);
holder.thumbnail.setDefaultImageResId(R.drawable.reddit_placeholder);
holder.name.setText(Html.fromHtml(listItems.getTitle()));
holder.relativeLayout.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
String article = listItems.getArticle();
String image = listItems.getImage();
Intent i = new Intent(mContext, DetailedActivity.class);
i.putExtra("articleKey",article);
i.putExtra("imageKey",image);
mContext.startActivity(i);
}
});
}
#Override
public int getItemCount() {
return reportsList.size();
}
public class RowHolder extends RecyclerView.ViewHolder{
protected NetworkImageView thumbnail;
protected TextView name;
protected RelativeLayout relativeLayout;
public RowHolder(View itemView) {
super(itemView);
this.relativeLayout = (RelativeLayout)
itemView.findViewById(R.id.recLayout);
this.thumbnail =
(NetworkImageView)itemView.findViewById(R.id.thumbnail);
this.name = (TextView)itemView.findViewById(R.id.title);
}
}
}
DetailedActivity
public class DetailedActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_detailed);
if(savedInstanceState == null){
getSupportFragmentManager()
.beginTransaction()
.add(R.id.detailed_match_reports,new DetailedActivityFragment())
.commit();
}
}
}
DetailedActivityFragment
public class DetailedActivityFragment extends Fragment {
TextView articleTextView;
String image;
String article;
ImageView imageView;
public DetailedActivityFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View v = inflater.inflate(R.layout.fragment_detailed_activity, container, false);
articleTextView = (TextView)getActivity().findViewById(R.id.articleTextView);
imageView = (ImageView)getActivity().findViewById(R.id.imageNews);
Intent i = getActivity().getIntent();
article = i.getStringExtra("articleKey");
image = i.getStringExtra("imageKey");
Picasso.with(getActivity()).load(image).into(imageView);
articleTextView.setText(article);
return v;
}
}
All of my data are passed after clicking a row good. I know this as I debug the following lines.
article = i.getStringExtra("articleKey");
image = i.getStringExtra("imageKey");
and see that both String variables are not null. However,the both views(TextView,ImageView) of my detailed fragment are null.
Maybe I am doing something wrong with my xml file,and I don't see it.
activity_main.xml
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/match_reports"
tools:context="theo.testing.androidservices.fragments.MainActivityFragment">
</FrameLayout>
fragment_main_activity
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/recLayout"
tools:context=".activities.MainActivity"
android:background="#fff">
<android.support.v7.widget.RecyclerView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="#+id/listview_match_reports"
android:layout_alignParentStart="true"
android:layout_alignParentLeft="true"
/>
</RelativeLayout>
activity_detailed.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/detailed_match_reports"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="theo.testing.androidservices.activities.DetailedActivity"
tools:ignore="MergeRootFrame">
</FrameLayout>
and finally
fragment_detailed_activity
<?xml version="1.0" encoding="utf-8"?>
<ScrollView android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/imageNews"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
xmlns:android="http://schemas.android.com/apk/res/android">
<TextView
android:layout_gravity="center_horizontal"
android:padding="10dp"
android:text="xcvxcvxcv"
android:textColor="#000"
android:layout_marginTop="5dp"
android:textAppearance="?android:attr/textAppearanceMedium"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/articleTextView"/>
</ScrollView>
What am I missing?
Thanks
Theo.
Change these
articleTextView = (TextView)getActivity().findViewById(R.id.articleTextView);
imageView = (ImageView)getActivity().findViewById(R.id.imageNews);
to
articleTextView = (TextView)v.findViewById(R.id.articleTextView);
imageView = (ImageView)v.findViewById(R.id.imageNews);
You'r passing data to DetailActivity. So first retrieve in DetailActivity and then pass to DetailFragment.
Also you need to pass data to DetailFragment using Bundle with setArguments(bundle)
Your Textview articleTextView is in the fragment but you are finding it in the activitys xml:
articleTextView = (TextView)getActivity().findViewById(R.id.articleTextView);
insetad you should do:
articleTextView = (TextView)(v.findViewById(R.id.articleTextView));
Do the same for Imageviewl.
I wish to display albums in grid with Album art, album name and number of songs.
These are my xml layouts:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:id="#+id/content_frame"
android:layout_height="match_parent"
android:background="#color/metalList">
<GridView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/grid"
android:layout_width="fill_parent"
android:numColumns="auto_fit"
android:layout_height="wrap_content"
android:verticalSpacing="10dp"
android:horizontalSpacing="10dp"
android:stretchMode="columnWidth"
android:layout_gravity="right|top"/>
</FrameLayout>
and for individual items:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
android:layout_width="160dp"
android:layout_height="200dp"
android:orientation="vertical"
android:background="#color/metalList"
android:layout_marginLeft="10dp"
android:layout_marginTop="10dp"
android:layout_marginRight="5dp"
android:elevation="4dp"
xmlns:android="http://schemas.android.com/apk/res/android">
<ImageView
android:id="#+id/albumart"
android:layout_width="160dp"
android:layout_height="160dp"
android:layout_gravity="top"
android:layout_margin="0dp"
android:src="#drawable/musicicon"
/>
<TextView
android:id="#+id/album_name"
android:layout_height="25dp"
android:layout_width="match_parent"
android:textColor="#color/metalTextB"
android:layout_below="#id/albumart"
android:layout_marginLeft="5dp"
android:textSize="16sp"
android:typeface="sans"
android:text="Album"
android:scrollHorizontally="true"
android:ellipsize="end"
android:maxLines="1"/>
<TextView
android:id="#+id/songs_num"
android:layout_width="match_parent"
android:layout_height="15dp"
android:layout_below="#id/album_name"
android:layout_marginLeft="5dp"
android:textColor="#color/metalTextS"
android:textSize="10sp"
android:text="artist"
android:typeface="sans"
android:scrollHorizontally="true"
android:ellipsize="end"
android:maxLines="1"/>
</LinearLayout>
Here are the codes for the Fragment and Activity
Albums.java
public class Albums extends Fragment implements LoaderManager.LoaderCallbacks {
AlbumsAdapter mAdapter;
private static final String ARG_POSITION = "position";
private int position;
public static Albums newInstance(int position) {
Albums f = new Albums();
Bundle b = new Bundle();
b.putInt(ARG_POSITION, position);
f.setArguments(b);
return f;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View myFragmentView = inflater.inflate(R.layout.albums, container, false);
GridView grid = (GridView) this.getActivity().findViewById(R.id.grid);
mAdapter = new AlbumsAdapter(getActivity(), null);
grid.setAdapter(mAdapter);
return myFragmentView;
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
getLoaderManager().initLoader(0, null, this);
}
static final String[] ALBUM_SUMMARY_PROJECTION = { MediaStore.Audio.Albums._ID,MediaStore.Audio.Albums.ALBUM_ART, MediaStore.Audio.Albums.ALBUM, MediaStore.Audio.Albums.ARTIST};
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
String select = null;
return new CursorLoader(getActivity(), MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI,ALBUM_SUMMARY_PROJECTION, select, null, null);
}
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
mAdapter.swapCursor(data);
}
public void onLoaderReset(Loader<Cursor> loader) {
mAdapter.swapCursor(null);
}
}
public class AlbumsAdapter extends CursorAdapter {
private final LayoutInflater mInflater;
public AlbumsAdapter(Context context, Cursor c) {
super(context, c);
mInflater = LayoutInflater.from(context);
}
#Override
public void bindView(View view, Context context, Cursor cursor) {
ImageView albumArt = (ImageView) view.findViewById(R.id.albumart);
albumArt.setScaleType(ImageView.ScaleType.FIT_XY);
String path = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Albums.ALBUM_ART));
Bitmap img = BitmapFactory.decodeFile(path);
if(img !=null)
albumArt.setImageBitmap(img);
else{
Bitmap bit = getDefaultAlbumArt(context);
albumArt.setImageBitmap(bit);
}
TextView albumTitle = (TextView) view.findViewById(R.id.album_name);
albumTitle.setText(cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Albums.ALBUM)));
TextView artistName = (TextView) view.findViewById(R.id.songs_num);
artistName.setText(cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Albums.ARTIST)));
}
#Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
final View view = mInflater.inflate(R.layout.grid_item, parent, false);
return view;
}
public Bitmap getDefaultAlbumArt(Context context) {
Bitmap bm = null;
BitmapFactory.Options options = new BitmapFactory.Options();
try {
bm = BitmapFactory.decodeResource(context.getResources(),
R.drawable.musicicon, options);
} catch (Error ee) {
} catch (Exception e) {
}
return bm;
}
}
AlbumsAdapter.java
public class AlbumsAdapter extends CursorAdapter {
private final LayoutInflater mInflater;
public AlbumsAdapter(Context context, Cursor c) {
super(context, c);
mInflater = LayoutInflater.from(context);
}
#Override
public void bindView(View view, Context context, Cursor cursor) {
ImageView albumArt = (ImageView) view.findViewById(R.id.albumart);
albumArt.setScaleType(ImageView.ScaleType.FIT_XY);
String path = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Albums.ALBUM_ART));
Bitmap img = BitmapFactory.decodeFile(path);
if(img !=null)
albumArt.setImageBitmap(img);
else{
Bitmap bit = getDefaultAlbumArt(context);
albumArt.setImageBitmap(bit);
}
TextView albumTitle = (TextView) view.findViewById(R.id.album_name);
albumTitle.setText(cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Albums.ALBUM)));
TextView artistName = (TextView) view.findViewById(R.id.songs_num);
artistName.setText(cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Albums.ARTIST)));
}
#Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
final View view = mInflater.inflate(R.layout.grid_item, parent, false);
return view;
}
public Bitmap getDefaultAlbumArt(Context context) {
Bitmap bm = null;
BitmapFactory.Options options = new BitmapFactory.Options();
try {
bm = BitmapFactory.decodeResource(context.getResources(),
R.drawable.musicicon, options);
} catch (Error ee) {
} catch (Exception e) {
}
return bm;
}
}
I am getting a "java.lang.NullPointerException" with these codes.
Can you please change same as below ?
View myFragmentView = inflater.inflate(R.layout.albums, container, false);
GridView grid = (GridView) this.getActivity().findViewById(R.id.grid);
to
View myFragmentView = inflater.inflate(R.layout.albums, container, false);
GridView grid = (GridView) myFragmentView.findViewById(R.id.grid);
Reason:
In fragment you have to bind child view to fragment view.
Done
Am trying to make a ui with flipview as in this tutorial. IThe tutorial deals with activities, but i want it in fragments case. That ie, the flip effect as well as its parent is a fragment. When i use activity it works, but on using fragment,only the empty textview shows up. Can anyone help me with this?
This is some part of the code
page.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ff3333" >
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="300dp">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="#drawable/banner"
android:id="#+id/head"/>
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:textSize="20dp"
android:id="#+id/header"
android:gravity="center"/>
</RelativeLayout>
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/des"
android:textSize="30dp"
android:gravity="center"/>
</FrameLayout>
fragment_news_feed :
<merge xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:flipview="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<se.emilsjolander.flipview.FlipView
android:id="#+id/flip_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ffffff"
flipview:orientation="vertical"
tools:context="com.excel.excelapp.fragment.NewsFeedFragment" >
</se.emilsjolander.flipview.FlipView>
<TextView
android:id="#+id/empty_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="Empty!"
android:textSize="32sp"
android:visibility="gone" />
</merge>
NewsFeedFragment.java
public class NewsFeedFragment extends Fragment implements NewsFlipAdapter.Callback, FlipView.OnFlipListener, FlipView.OnOverFlipListener{
private FlipView mFlipView;
private NewsFlipAdapter mAdapter;
int i=0,no_of_items=7;
public NewsFeedFragment() {
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
LinearLayout wrapper = new LinearLayout(getActivity());
View view = inflater.inflate(R.layout.fragment_news_feed, wrapper, true);
setUpView(view);
return wrapper;
}
private void setUpView(View view) {
mFlipView = (FlipView) view.findViewById(R.id.flip_view);
mAdapter = new NewsFlipAdapter(getActivity());
mAdapter.setCallback(this);
mFlipView.setAdapter(mAdapter);
mFlipView.setOnFlipListener(this);
mFlipView.peakNext(false);
mFlipView.setOverFlipMode(OverFlipMode.RUBBER_BAND);
mFlipView.setEmptyView(view.findViewById(R.id.empty_view));
mFlipView.setOnOverFlipListener(this);
}
#Override
public void onPageRequested(int page) {
mFlipView.smoothFlipTo(page);
}
#Override
public void onFlippedToPage(FlipView v, int position, long id) {
Log.i("pageflip", "Page: " + position);
if(position > mFlipView.getPageCount()-3 && mFlipView.getPageCount()<30){
mAdapter.addItems(5);
}
}
#Override
public void onOverFlip(FlipView v, OverFlipMode mode,
boolean overFlippingPrevious, float overFlipDistance,
float flipDistancePerPage) {
Log.i("overflip", "overFlipDistance = "+overFlipDistance);
}
NewsFlipAdapter.java
public class NewsFlipAdapter extends BaseAdapter {
public interface Callback {
public void onPageRequested(int page);
}
static class Item {
static long id = 0;
long mId;
public Item() {
mId = id++;
}
long getId() {
return mId;
}
}
private LayoutInflater inflater;
private Callback callback;
private List<Item> items = new ArrayList<Item>();
public NewsFlipAdapter(Context context) {
inflater = LayoutInflater.from(context);
}
public void setCallback(Callback callback) {
this.callback = callback;
}
#Override
public int getCount() {
return items.size();
}
#Override
public Object getItem(int position) {
return position;
}
#Override
public long getItemId(int position) {
return items.get(position).getId();
}
#Override
public boolean hasStableIds() {
return true;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
holder = new ViewHolder();
convertView = inflater.inflate(R.layout.page, parent, false);
holder.heading = (TextView) convertView.findViewById(R.id.header);
holder.description = (TextView) convertView.findViewById(R.id.des);
holder.header = (ImageView) convertView.findViewById(R.id.head);
// holder.firstPage = (Button) convertView.findViewById(R.id.first_page);
// holder.lastPage = (Button) convertView.findViewById(R.id.last_page);
// holder.firstPage.setOnClickListener(this);
// holder.lastPage.setOnClickListener(this);
// convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
return convertView;
}
static class ViewHolder {
TextView heading;
ImageView header;
TextView description;
}
/* #Override
public void onClick(View v) {
switch(v.getId()){
case R.id.first_page:
if(callback != null){
callback.onPageRequested(0);
}
break;
case R.id.last_page:
if(callback != null){
callback.onPageRequested(getCount()-1);
}
break;
}
}*/
public void addItems(int amount) {
TextView text;
for (int i = 0; i < amount; i++) {
items.add(new Item());
}
notifyDataSetChanged();
}
public void addItemsBefore(int amount) {
for (int i = 0; i < amount; i++) {
items.add(0, new Item());
}
notifyDataSetChanged();
}
I am not a 100 % sure about the following explanation, so please correct me if I am wrong.
The <merge> tag merges the inflated layout with it's parent view.
It generally doesn't seem to sit well with fragments as explained in more detail here.
So try to replace merge with LinearLayout in your fragment_newsfeed_layout:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:flipview="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<se.emilsjolander.flipview.FlipView
android:id="#+id/flip_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ffffff"
flipview:orientation="vertical"
tools:context="com.excel.excelapp.fragment.NewsFeedFragment" >
</se.emilsjolander.flipview.FlipView>
<TextView
android:id="#+id/empty_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="Empty!"
android:textSize="32sp"
android:visibility="gone" />
</LinearLayout>
I am new to Android and am trying a sample application for showing ViewPagers in a Master-Detail Flow using custom PagerAdapters and FragmentStatePagerAdapters. My application has a list of dummy items managed by a SQLiteDatabase which contain a title String, a description String, a Boolean like status, and a list of images (I plan to implement them as downloading from String urls but presently I'm just trying with a single image resource). I am having two problems in the Detail View.
My intention is to use a ViewPager with a FragmentStatePagerAdapter to show the detail view, which consists of a ViewPager with a custom PagerAdapter for showing the list of images, TextView for title and description, a ToggleButton for the like status and a delete button for deleting items from the list.
Issues:
The ViewPager with the custom PagerAdapter does not display the image. It occupies the expected space and swipes performed on it also behave as expected. Only the image is not visible.
[RESOLVED] On using the delete button, I am able to delete the item from the database, and also update the Master View accordingly, but I am not able to update the Detail View, and the app crashes.
Here is my code:
Code that calls ItemDetailActivity.java
#Override
public void onClick(View v) {
Intent detailIntent = new Intent(getContext(), ItemDetailActivity.class);
detailIntent.putExtra(ItemDetailFragment.ARG_LIST_POSITION, holder.position);
getContext().startActivity(detailIntent);
}
ItemDetailActivity.java
public class ItemDetailActivity extends FragmentActivity {
static ItemDetailPagerAdapter idpa;
static ViewPager detailPager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_item_detail);
idpa = new ItemDetailPagerAdapter(getSupportFragmentManager());
// Show the Up button in the action bar.
getActionBar().setDisplayHomeAsUpEnabled(true);
detailPager = (ViewPager) findViewById(R.id.item_detail_container);
detailPager.setAdapter(idpa);
detailPager.setCurrentItem(getIntent().getIntExtra(ItemDetailFragment.ARG_LIST_POSITION, 0));
}
}
activity_item_detail.xml
<android.support.v4.view.ViewPager xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/item_detail_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.trial.piclist.ItemDetailActivity"
tools:ignore="MergeRootFrame" />
ItemDetailFragment.java
public class ItemDetailFragment extends Fragment {
public static final String ARG_ITEM_ID = "item_id";
public static final String ARG_LIST_POSITION = "list_index";
public static final String ARG_TWO_PANE = "is_two_pane";
int position = -1;
long id = -1;
boolean twoPane = false;
ViewPager pager;
private PicItem mItem;
public ItemDetailFragment() {
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
twoPane = getArguments().getBoolean(ARG_TWO_PANE, false);
position = getArguments().getInt(ARG_LIST_POSITION, -1);
id = getArguments().getLong(ARG_ITEM_ID, -1);
if (id == -1)
id = ItemListFragment.getIdByPosition(position);
setmItem(id);
}
public void setmItem(long id) {
if (id >= 0) {
try {
ItemListActivity.lds.open();
mItem = ItemListActivity.lds.getById(id);
ItemListActivity.lds.close();
} catch (Exception e) {
System.out.println(e.getMessage());
}
if (mItem != null) {
List<String> pics = new ArrayList<String>();
pics.add("1");
pics.add("2");
pics.add("3");
pics.add("4");
pics.add("5");
mItem.setPics(pics);
}
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_item_detail,
container, false);
DetailViewHolder holder = new DetailViewHolder();
pager = (ViewPager) rootView.findViewById(R.id.pager);
ImagePagerAdapter adapter = new ImagePagerAdapter(mItem, getActivity(),
inflater, position);
pager.setAdapter(adapter);
holder.position = getArguments().getInt(ARG_LIST_POSITION);
holder.ttv = (TextView) rootView.findViewById(R.id.item_title);
holder.dtv = (TextView) rootView.findViewById(R.id.item_detail);
holder.likeButton = (ToggleButton) rootView
.findViewById(R.id.item_like);
holder.deleteButton = (Button) rootView.findViewById(R.id.item_delete);
rootView.setTag(holder);
if (mItem != null) {
holder.ttv.setText(mItem.getTitle());
holder.dtv.setText(mItem.getDescription());
holder.likeButton.setChecked(mItem.getIsLiked());
holder.likeButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
ItemListActivity.lds.open();
ItemListActivity.lds.toggleLike(mItem.getId());
mItem.toggleIsLiked();
ItemListActivity.lds.close();
ItemListFragment.listDisplayHelper.toggleLiked(position);
}
});
holder.deleteButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
ItemListActivity.lds.open();
ItemListActivity.lds.removeItem(mItem.getId());
ItemListActivity.lds.close();
ItemListFragment.listDisplayHelper.remove(position);
ItemListActivity.idpa.notifyDataSetChanged();
// What do I do so that the FragmentStatePagerAdapter is
// updated and the viewpager shows the next item.
}
});
}
return rootView;
}
static private class DetailViewHolder {
TextView ttv;
TextView dtv;
ToggleButton likeButton;
Button deleteButton;
int position;
}
}
fragment_item_detail.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="16dp"
tools:context="com.trial.piclist.ItemDetailFragment" >
<android.support.v4.view.ViewPager xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/pager"
android:layout_width="match_parent"
android:layout_height="200dip">
</android.support.v4.view.ViewPager>
<TableRow
android:id="#+id/tableRow1"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<TextView
android:id="#+id/item_title"
style="?android:attr/textAppearanceLarge"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/hello"
android:textIsSelectable="true" />
<Space
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1" />
<include
android:layout_width="wrap_content"
android:layout_height="wrap_content"
layout="#layout/controls_layout" />
</TableRow>
<ScrollView
android:id="#+id/descScrollView"
android:layout_width="match_parent"
android:layout_height="0dip"
android:layout_weight="1" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<TextView
android:id="#+id/item_detail"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/hello" />
</LinearLayout>
</ScrollView>
</LinearLayout>
controls_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal" >
<ToggleButton
android:id="#+id/item_like"
android:layout_width="30dip"
android:layout_height="30dip"
android:layout_gravity="right"
android:background="#android:drawable/btn_star"
android:gravity="center"
android:text="#string/like_list_item"
android:textOff="#string/empty_text"
android:textOn="#string/empty_text" />
<Button
android:id="#+id/item_delete"
style="?android:attr/buttonStyleSmall"
android:layout_width="30dip"
android:layout_height="30dip"
android:background="#android:drawable/ic_menu_delete"
android:text="#string/empty_text" />
</LinearLayout>
Custom PagerAdapter
ImagePagerAdapter.java
public class ImagePagerAdapter extends PagerAdapter {
LayoutInflater inflater;
List<View> layouts = new ArrayList<>(5);
// Constructors.
#Override
public Object instantiateItem(ViewGroup container, int position) {
if (layouts.get(position) != null) {
return layouts.get(position);
}
View layout = inflater.inflate(R.layout.detail_image,
((ViewPager) container), true);
try {
ImageView loadSpace = (ImageView) layout
.findViewById(R.id.detail_image_view);
loadSpace.setBackgroundColor(0x000000);
loadSpace.setImageResource(R.drawable.light_grey_background);
loadSpace.setAdjustViewBounds(true);
} catch (Exception e) {
System.out.println(e.getMessage());
}
layout.setTag(images.get(position));
layouts.set(position, layout);
return layout;
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
}
#Override
public int getCount() {
return 5;
}
#Override
public boolean isViewFromObject(View view, Object object) {
return (((View) object).findViewById((view.getId())) != null);
}
}
FragmentPagerAdapter
ItemDetailPagerAdapter.java
public class ItemDetailPagerAdapter extends FragmentStatePagerAdapter {
public ItemDetailPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
Fragment fragment = new ItemDetailFragment();
Bundle args = new Bundle();
args.putLong(ItemDetailFragment.ARG_ITEM_ID, ItemListFragment.getIdByPosition(position));
args.putInt(ItemDetailFragment.ARG_LIST_POSITION, position);
args.putBoolean(ItemDetailFragment.ARG_TWO_PANE, ItemListActivity.mTwoPane);
fragment.setArguments(args);
return fragment;
}
#Override
public int getCount() {
openDatabase();
int c = database.getCount();
closeDatabase();
return c;
}
#Override
public int getItemPosition(Object object) {
long mId = ((ItemDetailFragment) object).getmId();
int pos = POSITION_NONE;
openDatabase();
if (database.contains(mId)) {
pos = database.getPositionById(mId);
}
closeDatabase();
return pos;
}
}
Any help is much appreciated. Thanks :)
In your ItemDetailFragment, remove the viewpager from the holder, it should be directly into the returned view, something like this:
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_item_detail,
container, false);
pager = (ViewPager) rootView.findViewById(R.id.pager);
ImagePagerAdapter adapter = new ImagePagerAdapter(mItem, getActivity(),inflater, position);
pager.setAdapter(adapter);
return rootView;
}
and the ViewHolder pattern should be applied inside your PagerAdapter.
In ImagePagerAdapter.java, correct the isViewFromObject method -
#Override
public boolean isViewFromObject(View view, Object object) {
return (view == (View) object);
}
This will correct the issue of the ImageView.
In ItemDetailPagerAdapter.java, override the getItemPosition method -
#Override
public int getItemPosition(Object object) {
int ret = POSITION_NONE;
long id = ((ItemDetailFragment) object).getId();
openDatabase();
if (databaseContains(id)) {
ret = positionInDatabase(id);
}
closeDatabase();
return ret;
}
On deleting call the FragmentStatePagerAdapter.NotifyDataSetChanged() method. This will make the Adapter update itself on deleting.
Although, the FragmentStatePagerAdapter uses a list of Fragments and of stored states to implement the adapter. That is also causing trouble. To remove that, implement your own list of Fragments.