I am using following code for my ListView..
My FragmentActivity
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
View view = inflater.inflate(R.layout.home, container, false);
listView = (ListView) view.findViewById(R.id.listView);
listView.setAdapter(new CustomArrayAdapterForHome(mContext,questions));
return view;
}
Here is the Adapter for ListView
#SuppressLint("DefaultLocale")
public class CustomArrayAdapterForHome extends EndlessAdapter
{
private final LayoutInflater inflator;
protected ImageLoader imageLoader;
private DisplayImageOptions options;
private RotateAnimation rotate=null;
private View pendingView = null;
public CustomArrayAdapterForHome(Context ctx,ArrayList<Question> questionList)
{
super( new ArrayAdapter<Question>(ctx, R.layout.question_adapter_layout, questionList));
inflator = mContext.getLayoutInflater();
imageLoader = ImageLoader.getInstance();
options = new DisplayImageOptions.Builder()
.cacheInMemory()
.cacheOnDisc()
.showImageForEmptyUri(R.drawable.user_male)
.displayer(new RoundedBitmapDisplayer(5))
.build();
rotate=new RotateAnimation(0f, 360f, Animation.RELATIVE_TO_SELF,
0.5f, Animation.RELATIVE_TO_SELF,
0.5f);
rotate.setDuration(600);
rotate.setRepeatMode(Animation.RESTART);
rotate.setRepeatCount(Animation.INFINITE);
}
class ViewHolder
{
// MY CODE
}
#Override
public int getCount() {
return questions.size();
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent)
{
final Question question = questions.get(position);
final OpenionUser myUser = question.getUser();
// MY CODE
return view;
}
#Override
protected View getPendingView(ViewGroup parent)
{
View row = LayoutInflater.from(parent.getContext()).inflate(R.layout.row, null);
pendingView = row.findViewById(android.R.id.text1);
pendingView.setVisibility(View.GONE);
pendingView=row.findViewById(R.id.throbber);
pendingView.setVisibility(View.VISIBLE);
startProgressAnimation();
return(row);
}
private void startProgressAnimation()
{
if (pendingView!=null)
{
pendingView.startAnimation(rotate);
}
}
#Override
protected void appendCachedData()
{
}
#Override
protected boolean cacheInBackground() throws Exception
{
getQuestions();
return true;
}
}
The above code is just behaving like simple ListView, cacheInBackground Or getPendingView are not getting called. FurtherMore I want to add a headerView too and its not working either.
What am I missing in this?
Most of the code that you have here does not belong in an EndlessAdapter. Quoting the documentation:
It is designed to wrap around another adapter, where you have your "real" data. Hence, it follows the Decorator pattern, augmenting your current adapter with new Endless Technology(TM).
So, first, create a regular ArrayAdapter, and get all the styling and stuff that you want (e.g., your getView() implementation). Then, create an EndlessAdapter subclass that adds in the "endlessness".
Of note:
An EndlessAdapter subclass should not override getView(), as that is where the endless behavior is added
An EndlessAdapter subclass should not override getCount(), as that is managed by the EndlessAdapter implementation itself
You may wish to examine the sample app to see how it implements EndlessAdapter subclasses.
Or, since EndlessAdapter will not work with header views, you may simply need to switch to a different endless list solution or roll your own.
Related
I am using a view pager with three tabs (three fragments). In one of these fragments I have a recycler view. The items in this recycler view get updated every 2 seconds from the web. When I first start up the app, the recycler view runs just fine. Even when navigating to different tabs or navigating out of my app with home button, it all works.
However when I close the app by using the backkey and then go into my app again, the recycler view is not updating anymore. It shows the status that it had when the app quit. I monitor the adapter via the console and it keeps on working with the correct data, only the recycler view doesn't show this. I tried all kinds of stuff to "reconnect" adapter and recycler view but it won't work. I am having this issue for days. Any idea for the cause of this problem? See the relevant code for troubleshooting. Thank you!
public class UserAreaFragment extends Fragment implements PopupMenu.OnMenuItemClickListener {
private RecyclerView mRecyclerview;
private UserAdapter mAdapter;
private RecyclerView.LayoutManager mLayoutmanager;
private Handler mainHandler = new Handler();
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.fragment_user_area, container, false);
...
mAdapter = new UserAdapter(getActivity(), UserDataSingleton.getUserList());
mRecyclerview = root.findViewById(R.id.userListing);
mRecyclerview.setLayoutManager(new LinearLayoutManager(getActivity()));
mRecyclerview.setAdapter(mAdapter);
mAdapter.setOnItemClickListener(new UserAdapter.OnItemClickListener() {
#Override
public void onItemClick(int position) {
...
}
});
}
//Somewhere in my method that receives the data from an online DB:
UserDataSingleton.getUserList().clear();
UserDataSingleton.getUserList().addAll(serverResponse);
mainHandler.post(updateUi);
//And finally the updateUi method: this is essential just sorting and then notifydatasetchanged
Runnable updateUi = new Runnable() {
#Override
public void run() {
Collections.sort(UserDataSingleton.getUserList(), new Comparator<UserItem>() {
#Override
public int compare(UserItem lhs, UserItem rhs) {
// -1 - less than, 1 - greater than, 0 - equal, all inversed for descending
return Double.parseDouble(lhs.getmDistance()) > Double.parseDouble(rhs.getmDistance()) ? 1 : Double.parseDouble(lhs.getmDistance()) < Double.parseDouble(rhs.getmDistance()) ? -1 : 0;
}
});
mAdapter.notifyDataSetChanged();
}
};
//and this is my Adapter:
public class UserAdapter extends RecyclerView.Adapter<UserAdapter.UserViewHolder> {
private UserAdapter.OnItemClickListener mListener;
private Context mContext;
private List<UserItem> mUserlist;
public UserAdapter(Context context,List<UserItem> userList){
mUserlist=userList;
mContext = context;
}
public interface OnItemClickListener{
void onItemClick(int position);
}
public void setOnItemClickListener(UserAdapter.OnItemClickListener listener) {
this.mListener = listener;
}
public static class UserViewHolder extends RecyclerView.ViewHolder{
public TextView mUsername;
public TextView mDistance;
public ImageView userIcon;
public UserViewHolder(#NonNull View itemView, final UserAdapter.OnItemClickListener listener) {
super(itemView);
mUsername = itemView.findViewById(R.id.tvNearUsername);
mDistance = itemView.findViewById(R.id.tvDistance);
userIcon = itemView.findViewById(R.id.usericon);
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (listener != null){
int position = getAdapterPosition();
if (position!= RecyclerView.NO_POSITION){
listener.onItemClick(position);
}
}
}
});
}
}
#NonNull
#Override
public UserAdapter.UserViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(mContext);
View v= inflater.inflate(R.layout.user_item, parent, false);
UserViewHolder uvh= new UserViewHolder(v,mListener);
return uvh;
}
#Override
public void onBindViewHolder(#NonNull UserAdapter.UserViewHolder holder, int position) {
UserItem currentitem = mUserlist.get(position);
holder.mUsername.setText(currentitem.getmNearUsername());
if (currentitem.isArea()){
holder.mDistance.setVisibility(View.INVISIBLE);
holder.userIcon.setImageResource(R.drawable.ic_placeicon);
}else{
holder.mDistance.setVisibility(View.VISIBLE);
}
int distToNextTen = ((Integer.parseInt(currentitem.getmDistance())+5)/10)*10+10;
holder.mDistance.setText("< "+distToNextTen+"m");
}
#Override
public int getItemCount() {
return mUserlist.size();
}
}
I tried to only display the lines that affect the issue for better readability. If you need to see more code just let me know. Thankful for this great community!
(I think problem might be in connection with the main Handler not pointing to the correct view or maybe an issue with adapter-recyclerview connection but I can't find a solution tried so many things already)
Ok I found the problem. It had something to do with my runnables and handlers not being declared within onCreate. Somehow that messed it up. I made a major reconstruction of my code to solve it so its hard to tell which line exactly was the problem but if you are facing a similar problem check that your runOnUi and handler declarations happen in the right places.
I'm getting a variable data sent from activity to my adapter by using
sendData method, but every time when I try to access it in my getView method it resets to 0, please help. I've tried to debug code to check if the data from an activity is passing and it looks ok. I also created a getNumb method but still, the variable resets to 0. Here is my adapter code:
public class WorkoutListAdapterTwo extends BaseAdapter {
private int y;
public WorkoutListAdapterTwo() {
}
public int sendData(int x){
this.y = x;
return y;
}
public int getNumb(){
return this.y;
}
private static LayoutInflater mLayoutInflater = null;
public WorkoutListAdapterTwo(Activity ctx) {
this.mLayoutInflater = ctx.getLayoutInflater();
}
#Override
public int getCount() {
return WorkoutContentTwo.WORKOUTSTWO.size();
}
#Override
public Object getItem(int position) {
return WorkoutContentTwo.WORKOUTSTWO.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
int j = getNumb();
WorkoutTwo workout = (WorkoutTwo) getItem(j);
String [] arrOfStrings = workout.name.split(",");
if (convertView == null) {
convertView = mLayoutInflater.inflate(R.layout.adapter_workout_row, parent, false);
holder = new ViewHolder();
holder.id = (TextView) convertView.findViewById(R.id.workout_id);
holder.name = (TextView) convertView.findViewById(R.id.workout_name);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
// Set the content for the ListView row
//holder.id.setText(workout.id);
//holder.name.setText(arrOfStrings[i]);
holder.id.setText(Integer.toString(position+1));
holder.name.setText(workout.ArrList[position]);
// Set the color for the ListView row
holder.id.setBackgroundColor(workout.dark);
holder.name.setBackgroundColor(workout.light);
return convertView;
}
Here I'm adding the code where I'm calling my method:
public void onItemSelected(int position) {
// Start the detail activity for the selected workout ID.
Intent detailIntent = new Intent(this, WorkoutDetailActivityTwo.class);
detailIntent.putExtra(WorkoutDetailFragmentTwo.ARG_WORKOUT_POS, position);
WorkoutListAdapterTwo newAdd = new WorkoutListAdapterTwo();
newAdd.sendData(position);
newAdd.notifyDataSetChanged();
startActivity(detailIntent);
}
Are you notifying your adapter to update views after updating the value? If your sendData() is not called until after the adapter has done it's first draw, you will need to call notifyDataSetChanged() so that the adapter knows there are new values that should be used to update your views.
You have to make a interface or you can a use notifyDataSetChanged depends on the use if you are doing search operation then use the notifyDataSetChanged method but if you want to send some data then
Fragment or activity
public class ExampleFragment extends Fragment implements MyAdapter.SuccessResponse{
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View contentView = inflater.inflate(R.layout.my_layout, container, false);
MyAdapter myAdapter = new MyAdapter(getActivity(), 0);
myAdapter.successResponse = this;
return contentView;
}
#Override
public void onSuccess() {
}
}
The adapter code
class MyAdapter extends ArrayAdapter{
SuccessResponse successResponse;
public MyAdapter(Context context, int resource) {
super(context, resource);
}
public interface SuccessResponse{
void onSuccess();
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
//ur views
linearLayout.setOnClickListener(new View.OnClickListener{
#Override
public void onClick (View view){
if(successResponse!=null)
successResponse.onSuccess();
}
})
}
}
You can use any type of adapter i am use arrayadaper here.
So I have created a generic PageAdapter to be used in various parts on the app, which looks like this:
public class ImagePagerAdapter extends PagerAdapter {
private final LayoutInflater layoutInflater;
private final Picasso picasso;
private final int layoutResId;
private final List<AssociatedMedia> images;
public ImagePagerAdapter(Context context, int layoutResId) {
layoutInflater = LayoutInflater.from(context);
picasso = Injector.getInstance().getPicasso();
this.layoutResId = layoutResId;
this.images = new ArrayList<>();
}
public void setMedia(List<AssociatedMedia> media) {
images.clear();
for (AssociatedMedia productMedia : media) {
if (productMedia.type == AssociatedMediaType.IMAGE) {
images.add(productMedia);
}
else {
// non-images all at the end
break;
}
}
}
#Override
public Object instantiateItem(ViewGroup container, int position) {
AssociatedMedia image = images.get(position);
ImageView imageView = (ImageView) layoutInflater.inflate(layoutResId, container, false);
container.addView(imageView);
picasso.load(Uri.parse(image.urls[0])).into(imageView);
return imageView;
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
ImageView imageView = (ImageView) object;
container.removeView(imageView);
picasso.cancelRequest(imageView);
}
#Override
public int getCount() {
return images.size();
}
#Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
}
I then call this adapter in a fragment, like this:
ImagePagerAdapter productImageAdapter = new ImagePagerAdapter(getActivity(), R.layout.photo_container_small);
productImageAdapter.setMedia(medias);
productImage.setAdapter(productImageAdapter);
My question is, how can I invoke a onClickListener in the fragment. So my scenario is that, we have a carousel of images, and once the user click on an image, it will open a large view on that image, so sort of need an onItemClickListener, but this can only be invoked in the pagerAdapter.
So is there a way to either call a onClickListener in the fragment, or notify the fragment from the adapter when an item has been clicked?
This is a response to your comment. For formating and size reasons I use an answer for it. It is a general example on how to use an interface to de-couple a fragment from an adapter class which makes the adapter re-usable in several fragments (and even other projects).
public class MyAdapter {
MyAdapterListener listener;
private MyAdapter() {}
public MyAdapter(MyAdapterListener listeningActivityOrFragment) {
listener = listeningActivityOrFragment;
}
}
public interface MyAdapterListener {
void somethingTheFragmentNeedsToKnow(Object someData);
}
public class SomeFragment extends Fragment implements MyAdapterListener {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.my_view, container, false);
// Do everyhting here to init your view.
// Create an Adapter and bind it to this fragment
MyAdapter myAdapter = new MyAdapter(this);
return view;
}
// Implement the listener interface
#Override
public void somethingTheFragmentNeedsToKnow(Object someData) {
// Get the data and process it.
}
}
So in your case the method within the interface may well be onClick(int position); If you need more than one method, then just add them.
I used fragment in my app and i'm using SQLite to save local data. But when I finished saving data, and I swipe the page, my listView is not refreshed with new data (Only showing old data). I have tried to provide a method notifyDataSetChanged() on my adapter, but it's not working.
My Base Adapter class :
public class LocalDataAdapter extends BaseAdapter {
private Activity activity;
private ArrayList<LocalDataBean> data;
private static LayoutInflater inflater = null;
public LocalDataAdapter(Activity a, ArrayList<LocalDataBean> d) {
activity = a;
data = d;
inflater = (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
#Override
public int getCount() {
return data.size();
}
#Override
public Object getItem(int position) {
return data.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
public void setItem(ArrayList<LocalDataBean> data){
this.data = data;
notifyDataSetChanged();
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = inflater.inflate(R.layout.list_item, null);
TextView nama_konsumen = (TextView) v.findViewById(R.id.nama_konsumen);
TextView no_telp = (TextView) v.findViewById(R.id.no_telp);
TextView no_hp_cdma = (TextView) v.findViewById(R.id.no_hp_cdma);
TextView no_hp_gsm = (TextView) v.findViewById(R.id.no_hp_gsm);
LocalDataBean obj = (LocalDataBean) getItem(position);
nama_konsumen.setText(obj.getNamaKonsumen());
no_telp.setText(obj.getNoTelp());
no_hp_cdma.setText(obj.getNoCMDA());
no_hp_gsm.setText(obj.getNoGSM());
return v;
}
}
My fragment class :
public class LocalDataFragment extends Fragment {
View view;
Activity act;
SQLHandlerBean utilSql;
ArrayList<LocalDataBean> localdatabean = new ArrayList<LocalDataBean>();
LocalDataAdapter adapter;
ListView list;
public static final String TAG = LocalDataFragment.class.getSimpleName();
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
view = inflater.inflate(R.layout.layout_local_data, null);
act = getActivity();
list = (ListView) view.findViewById(R.id.listViewLocalData);
utilSql = new SQLHandlerBean(this.act);
adapter = new LocalDataAdapter(act, localdatabean);
localdatabean = new ArrayList<LocalDataBean>();
list.setAdapter(adapter);
if (utilSql.ReadAllLocalData().size() < 1) {
Toast.makeText(act, "DATA EMPTY!", Toast.LENGTH_LONG).show();
} else {
localdatabean = utilSql.ReadAllLocalData();
Log.e(TAG, "TOTAL DATA : "+localdatabean.size());
adapter.setItem(localdatabean);
adapter.notifyDataSetChanged();
}
return view;
}
}
Is adapter.notifyDataSetChanged() placement correct?
No, the placement is not in the right place.
As you have placed the notifyDataSetChanged() inside of the onCreateView() method. It will be only invoked 1st time the fragment is launched.
Rather you can add a refresh button in your layout (or in you action bar). And along with the insertion/deletion method of the data, place the notifyDataSetChanged() at the bottom of the click event of that button.
By doing this user can refresh the page whenever they want.
And if you want to refresh the page by swipping the view then, SwipeRefreshLaoyout could be a perfect alternative.
You can check this blog.
I am trying to make a gridview on LayoutInflater, when i test my app, it always crashes.
here is my code :
public class Level1 extends Fragment {
public static Fragment newInstance(Context context) {
Level1 f = new Level1();
return f;
}
public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {
ViewGroup root = (ViewGroup) inflater.inflate(R.layout.grid_layout, null);
GridView gridView = (GridView) root.findViewById(R.id.grid_view);
gridView.setAdapter(new ImageAdapter(root.getContext()));
}
I think, my problem is in "setAdapter". I can't use context "xxx.this". I've try to change setAdapter context with "getContext" and "getApplicationContext" but it still crashes.
when i delete "setAdapter" my app working but without gridView.
My ImageAdapter is look like this :
public class ImageAdapter extends BaseAdapter {
private Context mContext;
public Integer[] mThumbIds = {
R.drawable.pic_1, R.drawable.pic_2,
R.drawable.pic_3, R.drawable.pic_4,
R.drawable.pic_5, R.drawable.pic_6,
R.drawable.pic_7, R.drawable.pic_8,
R.drawable.pic_9, R.drawable.pic_10,
R.drawable.pic_11, R.drawable.pic_12,
R.drawable.pic_13, R.drawable.pic_14,
R.drawable.pic_15
};
// Constructor
public ImageAdapter(Context c){
mContext = c;
}
#Override
public int getCount() {
return mThumbIds.length;
}
#Override
public Object getItem(int position) {
return mThumbIds[position];
}
#Override
public long getItemId(int position) {
return 0;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ImageView imageView = new ImageView(mContext);
imageView.setImageResource(mThumbIds[position]);
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
imageView.setLayoutParams(new GridView.LayoutParams(70, 70));
return imageView;
}
}
Please help me..
Please set a breakpoint on this line GridView gridView = (GridView) root.findViewById(R.id.grid_view); and start debugging your app (in eclipse it's the button on the left side of the button you usually use to start your application). When the breakpoint is reached please step over one step and see if gridView is null. For me this looks like the most reasonable source of your error. But without a detailled error message it's hard to say, so please update your post.
if you are getting OUTOFMEMORY exception its generally because you are using large size images. you will have to sample it down. and in fragment you have to use getactivity() for context.