This is one of my tab fragment.
I just wanted to show the list of Movies & Tv Shows that includes the word in SearchView
And when I click one of the images, it moves to the Detail Activity.
The problem happens when I search two or more words continuously.
It moves to proper Detail Activity and when I close that Activity it comes with several other unrelated Detail Activity.
I need you guys help
First code is the Fragment Code
package com.example.endterm.Fragment;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.graphics.Rect;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.SearchView;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.view.GestureDetector;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.view.inputmethod.InputMethodManager;
import android.widget.TextView;
import android.widget.Toast;
import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.StringRequest;
import com.android.volley.toolbox.Volley;
import com.example.endterm.ItemAdapter;
import com.example.endterm.Items;
import com.example.endterm.MovieDetail;
import com.example.endterm.R;
import com.example.endterm.TVDetail;
import org.json.JSONArray;
import org.json.JSONObject;
import java.util.ArrayList;
public class SearchFragment extends Fragment {
// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private static final String ARG_PARAM1 = "param1";
private static final String ARG_PARAM2 = "param2";
// TODO: Rename and change types of parameters
private String mParam1;
private String mParam2;
SearchView searchView;
TextView tVQuery;
String queryWord;
//RecyclerView recyclerView7, recyclerView8;
ItemAdapter adapter7 = new ItemAdapter(7);
ItemAdapter adapter8 = new ItemAdapter(8);
public SearchFragment() {
// Required empty public constructor
}
class MyItmeDecoration extends RecyclerView.ItemDecoration{
#Override
public void getItemOffsets(#NonNull Rect outRect, #NonNull View view, #NonNull RecyclerView parent, #NonNull RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
outRect.set(10, 10, 10, 10);
view.setBackgroundColor(Color.BLACK);
}
}
// TODO: Rename and change types and number of parameters
public static SearchFragment newInstance(String param1, String param2) {
SearchFragment fragment = new SearchFragment();
Bundle args = new Bundle();
args.putString(ARG_PARAM1, param1);
args.putString(ARG_PARAM2, param2);
fragment.setArguments(args);
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mParam1 = getArguments().getString(ARG_PARAM1);
mParam2 = getArguments().getString(ARG_PARAM2);
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
ViewGroup rootView = (ViewGroup) inflater.inflate(R.layout.fragment_search, container, false);
tVQuery = (TextView) rootView.findViewById(R.id.query);
searchView = (SearchView) rootView.findViewById(R.id.search);
//final MyItmeDecoration Deco = new MyItmeDecoration();
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
#Override
public boolean onQueryTextSubmit(String s) {
queryWord = s;
tVQuery.setText("Searched by : " + s);
// 입력받은 문자열 처리
searchView.onActionViewCollapsed();
adapter7.empty();
adapter8.empty();
adapter7.notifyDataSetChanged();
adapter8.notifyDataSetChanged();
exp(adapter7, "https://api.themoviedb.org/3/search/movie?api_key=0a9a6b6bcc6ed2a798fb5401045dd81f&language=ko&query=" + s + "&page=1&include_adult=false", true);
exp(adapter8, "https://api.themoviedb.org/3/search/tv?api_key=0a9a6b6bcc6ed2a798fb5401045dd81f&language=ko&page=1&query=" + s + "&include_adult=false", false);
return true;
}
#Override
public boolean onQueryTextChange(String s) {
// 입력란의 문자열이 바뀔 때 처리
return false;
}
});
return rootView;
}
private void exp(final ItemAdapter adapterS, String urlE, final boolean movieortv){
final RecyclerView rec;
if(movieortv) {
rec = (RecyclerView) getActivity().findViewById(R.id.searchedMovie);
}
else{
rec = (RecyclerView) getActivity().findViewById(R.id.searchedTV);
}
LinearLayoutManager linearLayoutManager=new LinearLayoutManager(getActivity());
linearLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
rec.setLayoutManager(linearLayoutManager);
MyItmeDecoration Deco = new MyItmeDecoration();
if(Deco != null){
rec.removeItemDecoration(Deco);
}
rec.addItemDecoration(Deco);
rec.setAdapter(adapterS);
RequestQueue queue= Volley.newRequestQueue(getActivity());
StringRequest fR=new StringRequest(Request.Method.GET, urlE, new Response.Listener<String>(){
#Override
public void onResponse(String response) {
parseXMLForecast(rec, response, adapterS, movieortv);
}
}, new Response.ErrorListener(){
#Override
public void onErrorResponse(VolleyError error) {
}
});
queue.add(fR);
}
private void parseXMLForecast(RecyclerView rec, String response, ItemAdapter adaptersample, final boolean movieortv){
try{
final ArrayList<Items> items = new ArrayList<>();
JSONObject jsonObject = new JSONObject(response);
String results = jsonObject.getString("results");
JSONArray jsonArray = new JSONArray(results);
for(int i = 0; i < jsonArray.length(); i++){
JSONObject subJsonObject = jsonArray.getJSONObject(i);
String url = "https://image.tmdb.org/t/p/w300" + subJsonObject.getString("poster_path");
String title;
if(movieortv) {
title = subJsonObject.getString("title");
}
else{
title = subJsonObject.getString("name");
}
String id = subJsonObject.getString("id");
Items jump = new Items(url, title, id);
items.add(jump);
}
adaptersample.setItems(items);
adaptersample.notifyDataSetChanged();
rec.addOnItemTouchListener(new RecyclerTouchListener(getActivity(), rec, new ClickListener() {
#Override
public void onClick(View view, int position) {
Items dict = items.get(position);
Intent intent;
if(movieortv == true) {
intent = new Intent(getActivity(), MovieDetail.class);
}
else{
intent = new Intent(getActivity(), TVDetail.class);
}
intent.putExtra("id", dict.getId());
intent.putExtra("url", dict.getUrl());
intent.putExtra("title", dict.getTitle());
startActivity(intent);
}
#Override
public void onLongClick(View view, int position) {
Items dict = items.get(position);
Toast.makeText(getActivity(), dict.getTitle()+' '+dict.getId()+' '+dict.getUrl(), Toast.LENGTH_LONG).show();
}
}));
}catch(Exception e){
e.printStackTrace();
}
}
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
}
public interface ClickListener {
void onClick(View view, int position);
void onLongClick(View view, int position);
}
public static class RecyclerTouchListener implements RecyclerView.OnItemTouchListener {
private GestureDetector gestureDetector;
private SearchFragment.ClickListener clickListener;
public RecyclerTouchListener(Context context, final RecyclerView recyclerView, final SearchFragment.ClickListener clickListener) {
this.clickListener = clickListener;
gestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
#Override
public boolean onSingleTapUp(MotionEvent e) {
return true;
}
#Override
public void onLongPress(MotionEvent e) {
View child = recyclerView.findChildViewUnder(e.getX(), e.getY());
if (child != null && clickListener != null) {
clickListener.onLongClick(child, recyclerView.getChildAdapterPosition(child));
}
}
});
}
#Override
public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
View child = rv.findChildViewUnder(e.getX(), e.getY());
if (child != null && clickListener != null && gestureDetector.onTouchEvent(e)) {
clickListener.onClick(child, rv.getChildAdapterPosition(child));
}
return false;
}
#Override
public void onTouchEvent(RecyclerView rv, MotionEvent e) {
}
#Override
public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
}
}
}
And the Second one is the Adapter Code if you need
package com.example.endterm;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.bumptech.glide.Glide;
import com.example.endterm.Items;
import java.util.ArrayList;
public class ItemAdapter extends RecyclerView.Adapter<ItemAdapter.ViewHolder>{
private ArrayList<Items> items = new ArrayList<>();
#Override
public void onDetachedFromRecyclerView(#NonNull RecyclerView recyclerView) {
super.onDetachedFromRecyclerView(recyclerView);
}
private int wheree;
#Override
public long getItemId(int position) {
return super.getItemId(position);
}
public ItemAdapter(int wheree){
this.wheree = wheree;
}
public ItemAdapter.ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType){
View itemView = null;
if(wheree == 1) {
itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.imageswork1, parent, false);
}
else if(wheree == 2){
itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.imageswork2, parent, false);
}
else if(wheree == 3){
itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.imageswork3, parent, false);
}
else if(wheree == 4){
itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.imageswork4, parent, false);
}
else if(wheree == 5){
itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.imageswork5, parent, false);
}
else if(wheree == 6){
itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.imageswork6, parent, false);
}
else if(wheree == 7){
itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.imageswork7, parent, false);
}
else if(wheree == 8){
itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.imageswork8, parent, false);
}
ViewHolder viewHolder = new ViewHolder(itemView);
return viewHolder;
}
public void onBindViewHolder(#NonNull ItemAdapter.ViewHolder viewHolder, int position) {
Items item = items.get(position);
Glide.with(viewHolder.itemView.getContext())
.load(item.getUrl())
.into(viewHolder.weatherImageView);
}
class ViewHolder extends RecyclerView.ViewHolder{
public ImageView weatherImageView;
public ViewHolder(View itemView){
super(itemView);
if(wheree == 1){
weatherImageView=(ImageView)itemView.findViewById(R.id.item_image1);
}
else if(wheree == 2){
weatherImageView = (ImageView)itemView.findViewById(R.id.item_image2);
}
else if(wheree == 3){
weatherImageView = (ImageView)itemView.findViewById(R.id.item_image3);
}
else if(wheree == 4){
weatherImageView = (ImageView)itemView.findViewById(R.id.item_image4);
}
else if(wheree == 5){
weatherImageView = (ImageView)itemView.findViewById(R.id.item_image5);
}
else if(wheree == 6){
weatherImageView = (ImageView)itemView.findViewById(R.id.item_image6);
}
else if(wheree == 7){
weatherImageView = (ImageView)itemView.findViewById(R.id.item_image7);
}
else if(wheree == 8){
weatherImageView = (ImageView)itemView.findViewById(R.id.item_image8);
}
}
}
public void empty(){
for(int i = 0; i < getItemCount(); i++){
items.remove(0);
}
}
public int getItemCount() {
return items.size();
}
public void setItems(ArrayList<Items> items){
this.items = items;
}
}
First of all, remove this code, you do not need this here
#Override
public void onDetachedFromRecyclerView(#NonNull RecyclerView recyclerView) {
super.onDetachedFromRecyclerView(recyclerView);
}
Then, you did not implement getItemId() correctly. You can change this like that:
#Override
public long getItemId(int position) {
return items.get(position).getId(); //if you have item id, of course
}
I think the problem is because you are not specifying the items id, that is why it is opening several activities. Try this out. Hope it helps
Related
My scrolling list is displaying properly.
OnBindViewHolder is called for each item in initial display and when scrolling brings new items into view.
When I click on an item, I do see my ItemDetailsLookup and getItemDetails functions getting called, HOWEVER it doesn't call the OnBindViewHolder, and so setActivated isn't getting run.
The documentation for androidx.recyclerview.selection says "... When the user selects an item the library will record that in SelectionTracker then notify RecyclerView that the state of the item has changed. This will ultimately cause the value to be rebound by way of RecyclerView.Adapter#onBindViewHolder..." and I think I've done everything up to this point, but I must have missed something...
Any ideas?
Thanks
Here's my fragment:
package com.example.smartflashcards;
import android.content.Context;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.selection.ItemDetailsLookup;
import androidx.recyclerview.selection.SelectionPredicates;
import androidx.recyclerview.selection.SelectionTracker;
import androidx.recyclerview.selection.StableIdKeyProvider;
import androidx.recyclerview.selection.StorageStrategy;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class StackSelectionFragment extends Fragment {
private static final String ARG_COLUMN_COUNT = "column-count";
private int mColumnCount = 1;
static SelectionTracker<Long> tracker;
public StackSelectionFragment() {
}
#SuppressWarnings("unused")
public static StackSelectionFragment newInstance(int columnCount) {
StackSelectionFragment fragment = new StackSelectionFragment();
Bundle args = new Bundle();
args.putInt(ARG_COLUMN_COUNT, columnCount);
fragment.setArguments(args);
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mColumnCount = getArguments().getInt(ARG_COLUMN_COUNT);
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_stack_selection_list, container, false);
File directory = getActivity().getFilesDir();
List<String> filesList = new ArrayList(Arrays.asList(directory.list()));
if (view instanceof RecyclerView) {
Context context = view.getContext();
RecyclerView recyclerView = (RecyclerView) view;
if (mColumnCount <= 1) {
recyclerView.setLayoutManager(new LinearLayoutManager(context));
} else {
recyclerView.setLayoutManager(new GridLayoutManager(context, mColumnCount));
}
recyclerView.setAdapter(new MyItemRecyclerViewAdapter(filesList));
recyclerView.getAdapter().hasStableIds();
this.tracker = new SelectionTracker.Builder<Long>(
"stack_selector",
recyclerView,
new StableIdKeyProvider(recyclerView),
new MyDetailsLookup(recyclerView),
StorageStrategy.createLongStorage()
).withSelectionPredicate(SelectionPredicates.<Long>createSelectAnything()).build();
}
return view;
}
final class MyDetailsLookup extends ItemDetailsLookup {
private final RecyclerView mRecyclerView;
MyDetailsLookup(RecyclerView recyclerView) {
mRecyclerView = recyclerView;
}
public #Nullable
ItemDetails getItemDetails(#NonNull MotionEvent e) {
View view = mRecyclerView.findChildViewUnder(e.getX(), e.getY());
if (view != null) {
RecyclerView.ViewHolder holder = mRecyclerView.getChildViewHolder(view);
if (holder instanceof MyItemRecyclerViewAdapter.ViewHolder) {
return ((MyItemRecyclerViewAdapter.ViewHolder)holder).getItemDetails();
}
}
return null;
}
}
}
Here's my adapter:
package com.example.smartflashcards;
import androidx.annotation.Nullable;
import androidx.recyclerview.selection.ItemDetailsLookup;
import androidx.recyclerview.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.ViewGroup;
import android.widget.TextView;
import com.example.smartflashcards.databinding.FragmentStackSelectionBinding;
import java.util.List;
public class MyItemRecyclerViewAdapter extends RecyclerView.Adapter<MyItemRecyclerViewAdapter.ViewHolder> {
private final List<String> mValues;
public MyItemRecyclerViewAdapter(List<String> items) {
setHasStableIds(true);
mValues = items;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new ViewHolder(FragmentStackSelectionBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false));
}
#Override
public void onBindViewHolder(final ViewHolder holder, int position) {
holder.mItem = getItemId(position);
holder.mContentView.setText(mValues.get(position));
holder.mContentView.setActivated(StackSelectionFragment.tracker.isSelected((long) position));
}
#Override
public int getItemCount() {
return mValues.size();
}
#Override
public long getItemId(int position) {
return (long)position;
}
public class ViewHolder extends RecyclerView.ViewHolder {
public final TextView mIdView;
public final TextView mContentView;
public Long mItem;
public ViewHolder(FragmentStackSelectionBinding binding) {
super(binding.getRoot());
mIdView = binding.itemNumber;
mContentView = binding.content;
}
#Override
public String toString() {
return super.toString() + " '" + mContentView.getText() + "'";
}
public ItemDetailsLookup.ItemDetails<Long> getItemDetails() {
return new ItemDetailsLookup.ItemDetails<Long>() {
#Override
public int getPosition() {
return getAbsoluteAdapterPosition();
}
#Nullable
#Override
public Long getSelectionKey() {
return mItem;
}
};
}
}
}
By following the example at https://github.com/Thumar/recyclerview-selection/tree/master/app
I was able to get it working. See my working code below.
But I still don't know which of the changes made it work and why.
If anyone figures out what was causing my problem, please post a comment or answer.
Any and all other feedback is welcome as well.
THANKS
Here's my new fragment:
package com.example.smartflashcards;
import android.content.Context;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.selection.ItemDetailsLookup;
import androidx.recyclerview.selection.Selection;
import androidx.recyclerview.selection.SelectionPredicates;
import androidx.recyclerview.selection.SelectionTracker;
import androidx.recyclerview.selection.StableIdKeyProvider;
import androidx.recyclerview.selection.StorageStrategy;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class StackSelectionFragment extends Fragment {
// TODO: Customize parameter argument names
private static final String ARG_COLUMN_COUNT = "column-count";
// TODO: Customize parameters
private int mColumnCount = 1;
SelectionTracker<Long> tracker; //TODO: add private?
private StackSelectionListener listener;
public interface StackSelectionListener {
public void onSelectStack(String stack);
}
String selections = "";
/**
* Mandatory empty constructor for the fragment manager to instantiate the
* fragment (e.g. upon screen orientation changes).
*/
public StackSelectionFragment() {
}
// TODO: Customize parameter initialization
#SuppressWarnings("unused")
public static StackSelectionFragment newInstance(int columnCount) {
StackSelectionFragment fragment = new StackSelectionFragment();
Bundle args = new Bundle();
args.putInt(ARG_COLUMN_COUNT, columnCount);
fragment.setArguments(args);
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mColumnCount = getArguments().getInt(ARG_COLUMN_COUNT);
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_stack_selection_list, container, false);
File directory = getActivity().getFilesDir();
List<String> filesList = new ArrayList(Arrays.asList(directory.list()));
// Set the adapter
if (view instanceof RecyclerView) {
Context context = view.getContext();
RecyclerView recyclerView = (RecyclerView) view;
if (mColumnCount <= 1) {
recyclerView.setLayoutManager(new LinearLayoutManager(context));
} else {
recyclerView.setLayoutManager(new GridLayoutManager(context, mColumnCount));
}
MyItemRecyclerViewAdapter adapter = new MyItemRecyclerViewAdapter(filesList);
recyclerView.setAdapter(adapter);
adapter.hasStableIds();
this.tracker = new SelectionTracker.Builder<Long>(
"stack_selector",
recyclerView,
new StableIdKeyProvider(recyclerView),
new MyDetailsLookup(recyclerView),
StorageStrategy.createLongStorage()
).withSelectionPredicate(SelectionPredicates.<Long>createSelectAnything()).build();
adapter.injectTracker(this.tracker);
SelectionTracker.SelectionObserver<Long> observer = new SelectionTracker.SelectionObserver<Long>() {
#Override
public void onSelectionChanged() {
super.onSelectionChanged();
//TODO: replace this placeholder action with something useful
selections = "";
tracker.getSelection().forEach(item -> selections += adapter.getContent(item.intValue()));//selections += item);
//listener.onSelectStack("selections"); //This causes an error???
Context context = getContext();
Toast toast = Toast.makeText(context, selections, Toast.LENGTH_LONG);
toast.show();
}
};
this.tracker.addObserver(observer);
}
return view;
}
final class MyDetailsLookup extends ItemDetailsLookup {
private final RecyclerView mRecyclerView;
MyDetailsLookup(RecyclerView recyclerView) {
mRecyclerView = recyclerView;
}
public #Nullable
ItemDetails getItemDetails(#NonNull MotionEvent e) {
View view = mRecyclerView.findChildViewUnder(e.getX(), e.getY());
if (view != null) {
RecyclerView.ViewHolder holder = mRecyclerView.getChildViewHolder(view);
if (holder instanceof MyItemRecyclerViewAdapter.ViewHolder) {
return ((MyItemRecyclerViewAdapter.ViewHolder)holder).getItemDetails();
}
}
return null;
}
}
Here's my new adapter:
package com.example.smartflashcards;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.recyclerview.selection.ItemDetailsLookup;
import androidx.recyclerview.selection.SelectionTracker;
import androidx.recyclerview.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import java.util.List;
public class MyItemRecyclerViewAdapter extends RecyclerView.Adapter<MyItemRecyclerViewAdapter.ViewHolder> {
private final List<String> mValues;
private SelectionTracker<Long> selectionTracker;
public MyItemRecyclerViewAdapter(List<String> items) {
setHasStableIds(true); //TODO: remove redundancy between this and "recyclerView.getAdapter().hasStableIds()" in the Fragment
mValues = items;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.fragment_stack_selection, parent, false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull ViewHolder holder, int position) {
String item = this.mValues.get(position);
holder.bind(item, selectionTracker.isSelected((long) position));
}
#Override
public int getItemCount() {
return mValues.size();
}
#Override
public long getItemId(int position) {
return (long)position;
}
public String getContent(int position) {
return mValues.get(position);
}
public void injectTracker(SelectionTracker<Long> tracker)
{
this.selectionTracker = tracker;
}
public class ViewHolder extends RecyclerView.ViewHolder {
public final TextView mContentView;
public ViewHolder(#NonNull View itemView) {
super(itemView);
mContentView = itemView.findViewById(R.id.content);
}
#Override
public String toString() {
return super.toString() + " '" + mContentView.getText() + "'";
}
public void bind(String item, Boolean activate) {
this.mContentView.setText(item);
itemView.setActivated(activate); //TODO: understand how "itemView" exists outside of the constructor
}
public ItemDetailsLookup.ItemDetails<Long> getItemDetails() {
return new ItemDetailsLookup.ItemDetails<Long>() {
#Override
public int getPosition() {
return getAbsoluteAdapterPosition();
}
#Nullable
#Override
public Long getSelectionKey() {
return (long) getAbsoluteAdapterPosition();
}
};
}
}
}
I'm currently learning Android programming. My task is to update view after clicking "search button" in the menu (onCreateOptionsMenu method).
Should I kill thread "ThumbnailDownloader" and start new one to update the view. Or maybe should I add listener to mPhotoRecyclerView? It's also could be something with cache. I don't realy know. Any advice or solution would be very helpful.
package com.bignerdranch.photogallery;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.widget.ImageView;
import android.widget.SearchView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import java.util.ArrayList;
import java.util.List;
public class PhotoGalleryFragment extends Fragment{
private static final String TAG = "PhotoGalleryFragment";
private RecyclerView mPhotoRecyclerView;
private TextView mCurrentPageText;
private List<GalleryItem> mItems = new ArrayList<>();
private int pageFetched = 0;
private GridLayoutManager mGridManager;
boolean asyncFetching = false;
int mCurrentPage = 1;
int mMaxPage = 1;
int mItemsPerPage = 1;
int mFirstItemPosition, mLastItemPosition;
private ThumbnailDownloader<Integer> mThumbnailDownloader;
public static Fragment newInstance() {
return new PhotoGalleryFragment();
}
#Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setRetainInstance(true);
setHasOptionsMenu(true);
updateItems();
Handler responseHandler = new Handler();
mThumbnailDownloader = new ThumbnailDownloader<>(responseHandler);
mThumbnailDownloader.setThumbnailDownloadListener(
new ThumbnailDownloader.ThumbnailDownloadListener<Integer>() { //chanched to Integer
#Override
public void onThumbnailDownloaded(Integer position, Bitmap bitmap) {
mPhotoRecyclerView.getAdapter().notifyItemChanged(position);
}
}
);
mThumbnailDownloader.start();
mThumbnailDownloader.getLooper();
Log.i(TAG, "Background thread started");
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
View v = inflater.inflate(R.layout.fragment_photo_gallery, container, false);
mCurrentPageText = (TextView) v.findViewById(R.id.currentPageText);
mPhotoRecyclerView = (RecyclerView) v.findViewById(R.id.photo_recycler_view);
mPhotoRecyclerView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
// Context context;
float columnWidthInPixels = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 140, getActivity().getResources().getDisplayMetrics());
int width = mPhotoRecyclerView.getWidth();
int columnNumber = Math.round(width / columnWidthInPixels);
mGridManager = new GridLayoutManager(getActivity(), 3);
mPhotoRecyclerView.setLayoutManager(mGridManager);
mPhotoRecyclerView.scrollToPosition(mCurrentPage);
mPhotoRecyclerView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
});
mPhotoRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrolled(#NonNull RecyclerView recyclerView, int dx, int dy) {
int lastVisibleItem = mGridManager.findLastVisibleItemPosition();
int firstVisibleItem = mGridManager.findFirstVisibleItemPosition();
if (mLastItemPosition != lastVisibleItem || mFirstItemPosition != firstVisibleItem) {
Log.d(TAG,"Showing item " + firstVisibleItem +" to " + lastVisibleItem);
updatePageText(firstVisibleItem);
mLastItemPosition = lastVisibleItem;
mFirstItemPosition = firstVisibleItem;
int begin = Math.max(firstVisibleItem-10,0 );
int end = Math.min(lastVisibleItem +10,mItems.size()-1);
for (int position = begin; position <= end; position++){
String url=mItems.get(position).getUrl();
if(mThumbnailDownloader.mPhotoCache.get(url)== null) {
Log.d(TAG,"Requesting Download at position: "+ position);
mThumbnailDownloader.queueThumbnail(position,url);
}
}
}
Log.d(TAG, "Scrolling, First Item: "+ firstVisibleItem + " Last item: " + lastVisibleItem);
if(!(asyncFetching) && (dy>0)&&(mCurrentPage<mMaxPage)&& (lastVisibleItem>=(mItems.size()-1))){
Log.d(TAG, "Fetching more");
updateItems();
} else updatePageText(firstVisibleItem);
}
});
if(mPhotoRecyclerView.getAdapter() == null)setupAdapter();
return v;
}
#Override
public void onDestroyView(){
super.onDestroyView();
mThumbnailDownloader.clearQueue();
mThumbnailDownloader.clearCache();
}
#Override
public void onDestroy(){
super.onDestroy();
mThumbnailDownloader.quit();
Log.i(TAG, "Background thread destroyed");
}
#Override
public void onCreateOptionsMenu(final Menu menu, MenuInflater menuInflater){
super.onCreateOptionsMenu(menu, menuInflater);
menuInflater.inflate(R.menu.fragmen_photo_gallery, menu);
final MenuItem searchItem = menu.findItem(R.id.menu_item_search);
final SearchView searchView = (SearchView) searchItem.getActionView();
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
#Override
public boolean onQueryTextSubmit(String s) {
Log.d(TAG, "QueryTextSubmit: " + s);
QueryPreferences.setStoredQuery(getActivity(), s);
updateItems();
return true;
}
#Override
public boolean onQueryTextChange(String s) {
Log.d(TAG, "QueryTextChange: " +s);
return false;
}
});
searchView.setOnSearchClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String query = QueryPreferences.getStoredQuery(getActivity());
searchView.setQuery(query, false);
}
});
}
#Override
public boolean onOptionsItemSelected(MenuItem item){
switch (item.getItemId()){
case R.id.menu_item_clear:
QueryPreferences.setStoredQuery(getActivity(), null);
updateItems();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
private void updateItems(){
String query = QueryPreferences.getStoredQuery(getActivity());
new FetchItemsTask(query).execute();
}
private void updatePageText(int pos){
mCurrentPage = pos / mItemsPerPage+1;
mCurrentPageText.setText("Page " + mCurrentPage + " of " + mMaxPage);
}
private void setupAdapter(){
if(isAdded()){
mPhotoRecyclerView.setAdapter(new PhotoAdapter(mItems));
}
}
private class PhotoHolder extends RecyclerView.ViewHolder{
private ImageView mItemImageView;
public PhotoHolder(View itemView){
super(itemView);
mItemImageView = (ImageView) itemView.findViewById(R.id.item_image_view);
}
public void bindDrawable (Drawable drawable){
mItemImageView.setImageDrawable(drawable); }
}
private class PhotoAdapter extends RecyclerView.Adapter<PhotoHolder>{
private List<GalleryItem> mGalleryItems;
public PhotoAdapter(List<GalleryItem> galleryItems){
mGalleryItems = galleryItems;
}
#NonNull
#Override
public PhotoHolder onCreateViewHolder(#NonNull ViewGroup viewGroup, int viewType) {
Context context;
LayoutInflater inflater = LayoutInflater.from(getActivity());
View view = inflater.inflate(R.layout.gallery_item, viewGroup, false);
return new PhotoHolder(view);
}
#Override
public void onBindViewHolder(#NonNull PhotoHolder photoHolder, int position) {
Log.d(TAG,"Binding item "+ position + " to " + photoHolder.hashCode());
GalleryItem galleryItem = mGalleryItems.get(position);
String url = galleryItem.getUrl();
Bitmap bitmap = mThumbnailDownloader.mPhotoCache.get(url);
if(bitmap == null) {
Drawable placeholder = getResources().getDrawable(R.drawable.ic_launcher_background);
photoHolder.bindDrawable(placeholder);
}else {
Drawable drawable = new BitmapDrawable(getResources(), bitmap);
photoHolder.bindDrawable(drawable);
}
}
#Override
public int getItemCount() {
return mGalleryItems.size();
}
}
private class FetchItemsTask extends AsyncTask<Void, Void, List<GalleryItem>>{
private String mQuery;
public FetchItemsTask(String query){
mQuery = query;
}
#Override
protected List<GalleryItem> doInBackground(Void...params){
asyncFetching = true;
if(mQuery == null){
return new FlickrFetch().fetchRecentPhotos(pageFetched+1);
} else{
return new FlickrFetch().searchPhotos(mQuery, pageFetched+1);
}
}
#Override
protected void onPostExecute(List<GalleryItem>items){
pageFetched++;
asyncFetching=false;
mItems.addAll(items);
GalleryPage pge = GalleryPage.getGalleryPage();
mMaxPage = pge.getTotalPages();
mItemsPerPage = pge.getItemPerPage();
if(mPhotoRecyclerView.getAdapter()==null)setupAdapter();
mPhotoRecyclerView.getAdapter().notifyDataSetChanged();
updatePageText(mGridManager.findFirstVisibleItemPosition());
}
}
}
The issue was in onPostExecute method in the very end of the class.
I deleted
mItems.addAll(items);
and added
mItems = items;
setupAdapter();
Now it works fine.
Here is my code.
I try to add OnItenClickListener to "lastCommand" listView but it is not responde. Any errors at compile.
package pl.globoox.sprawdzsprzedawce;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.support.design.widget.NavigationView;
import android.support.v4.view.GravityCompat;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.SearchView;
import android.widget.TextView;
import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.toolbox.Volley;
import com.facebook.CallbackManager;
import com.facebook.FacebookCallback;
import com.facebook.FacebookException;
import com.facebook.FacebookSdk;
import com.facebook.GraphRequest;
import com.facebook.GraphResponse;
import com.facebook.login.LoginManager;
import com.facebook.login.LoginResult;
import com.facebook.login.widget.LoginButton;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList;
import pl.globoox.sprawdzsprzedawce.Utils.LastCommentHome;
import pl.globoox.sprawdzsprzedawce.Utils.QueryCheck;
import static pl.globoox.sprawdzsprzedawce.R.id.buttonCheckButton;
public class MainActivity extends AppCompatActivity
implements NavigationView.OnNavigationItemSelectedListener {
ListView lastComments;
LoginButton loginButton;
CallbackManager callbackManager;
ArrayList<String> comments_userList = new ArrayList();
ArrayList<String> comments_olxUserList = new ArrayList();
ArrayList<String> comments_dateList = new ArrayList();
ArrayList<String> comments_messageList = new ArrayList();
ArrayList<String> comments_statusList = new ArrayList();
ImageView imageViewFBUser;
TextView textViewFBName;
TextView textViewFBEmail;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
FacebookSdk.sdkInitialize(getApplicationContext());
setContentView(R.layout.activity_main);
initializeControls();
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
loginWithFb();
// MENU DRAWER
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
drawer.addDrawerListener(toggle);
toggle.syncState();
NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
navigationView.setNavigationItemSelectedListener(this);
View headerView = navigationView.getHeaderView(0);
textViewFBName = headerView.findViewById(R.id.textViewFBName);
textViewFBEmail = headerView.findViewById(R.id.textViewFBEmail);
imageViewFBUser = headerView.findViewById(R.id.imageViewFBUser);
imageViewFBUser.setVisibility(View.INVISIBLE);
textViewFBName.setText("");
textViewFBEmail.setText("");
// MAIN CONTENT APP
final SearchView editTextOfferLink = (SearchView) findViewById(R.id.editTextOfferLink);
final Button buttonCheck = (Button) findViewById(buttonCheckButton);
lastComments = (ListView) findViewById(R.id.listViewLastComments);
buttonCheck.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
final String offerLink = editTextOfferLink.getQuery().toString();
boolean error = false;
// CHECK FORM EMPTY
if (offerLink.isEmpty()) {
AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
builder.setMessage(R.string.formEmpty).setNegativeButton(R.string.tryAgain, null).create().show();
error = true;
return;
}
if (error == false) {
Response.Listener<String> responseListener = new Response.Listener<String>() {
#Override
public void onResponse(String response) {
try {
JSONObject jsonResponse = new JSONObject(response);
int errorCode = jsonResponse.getInt("errorCode");
String userID = jsonResponse.getString("userID");
// CANT CONNECT TO DATABASE
if (errorCode == 1) {
AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
builder.setMessage(R.string.cantConnectToDatabase).setNegativeButton(R.string.tryAgain, null).create().show();
}
// USER NOT FOUND
else if (errorCode == 2) {
Boolean isBank = jsonResponse.getBoolean("isBank");
Intent i;
i = new Intent(getApplicationContext(), AddNewUserActivity.class);
if (isBank == true) {
i.putExtra("isBank", "true");
} else {
i.putExtra("isBank", "false");
}
String userName = jsonResponse.getString("userName");
String registerDate = jsonResponse.getString("registerDate");
i.putExtra("userID", userID);
i.putExtra("userName", userName);
i.putExtra("registerDate", registerDate);
finish();
startActivity(i);
}
// EMPTY OFFER VARIABLE
else if (errorCode == 3) {
AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
builder.setMessage(R.string.omptyOfferVariable).setNegativeButton(R.string.tryAgain, null).create().show();
}
// BAD LINK
else if (errorCode == 4) {
AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
builder.setMessage(R.string.badOfferLink).setNegativeButton(R.string.tryAgain, null).create().show();
}
// USER FOUND!
else if (errorCode == 5) {
Boolean isBank = jsonResponse.getBoolean("isBank");
Intent i;
i = new Intent(getApplicationContext(), UserAreaActivity.class);
i.putExtra("userID", userID);
i.putExtra("isBank", isBank.toString());
finish();
startActivity(i);
}
} catch (JSONException e) {
e.printStackTrace();
}
}
};
QueryCheck offerQueryRequest = new QueryCheck(offerLink, responseListener);
RequestQueue queue = Volley.newRequestQueue(MainActivity.this);
queue.add(offerQueryRequest);
}
}
});
// LAST COMMENTS SHOW
Response.Listener<String> responseListenerLastComments = new Response.Listener<String>() {
#Override
public void onResponse(String response) {
try {
JSONObject jsonResponse = new JSONObject(response);
int errorCode = jsonResponse.getInt("errorCode");
int count = jsonResponse.getInt("count");
Log.d("Tag", String.valueOf(errorCode));
JSONArray commentsArray = jsonResponse.getJSONArray("comments");
Log.d("TAG", String.valueOf(commentsArray));
for (int i = 0; i < count; i++) {
JSONObject jsonObject = commentsArray.getJSONObject(i);
comments_userList.add(jsonObject.getString("user"));
comments_olxUserList.add(jsonObject.getString("olxUser"));
comments_dateList.add(jsonObject.getString("date"));
comments_messageList.add(jsonObject.getString("message"));
comments_statusList.add(jsonObject.getString("status"));
}
MainActivity.CustomAdapter customAdapter = new MainActivity.CustomAdapter();
lastComments.setAdapter(customAdapter);
} catch (JSONException e) {
e.printStackTrace();
}
}
};
LastCommentHome lastCommentHome = new LastCommentHome("3", responseListenerLastComments);
RequestQueue queue = Volley.newRequestQueue(MainActivity.this);
queue.add(lastCommentHome);
}
private void loginWithFb() {
// LOGIN MANAGER FACEBOOK
LoginManager.getInstance().registerCallback(callbackManager, new FacebookCallback<LoginResult>() {
#Override
public void onSuccess(LoginResult loginResult) {
GraphRequest.newMeRequest(
loginResult.getAccessToken(), new GraphRequest.GraphJSONObjectCallback() {
#Override
public void onCompleted(JSONObject me, GraphResponse response) {
if (response.getError() != null) {
// handle error
} else {
String email = me.optString("email");
String name = me.optString("name");
String picture = me.optString("picture");
imageViewFBUser.setVisibility(View.VISIBLE);
imageViewFBUser.setImageURI(Uri.parse(picture));
textViewFBName.setText(name);
textViewFBEmail.setText(email);
}
}
}).executeAsync();
}
#Override
public void onCancel() {
textViewFBName.setText("Login canceled!");
}
#Override
public void onError(FacebookException error) {
textViewFBName.setText("Login error: " + error.getMessage());
}
});
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
callbackManager.onActivityResult(requestCode, resultCode, data);
super.onActivityResult(requestCode, resultCode, data);
}
// FACEBOOK INITALZIZE LOGIN
private void initializeControls() {
callbackManager = CallbackManager.Factory.create();
loginButton = findViewById(R.id.login_button);
}
#Override
public void onBackPressed() {
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
} else {
super.onBackPressed();
}
}
#SuppressWarnings("StatementWithEmptyBody")
#Override
public boolean onNavigationItemSelected(MenuItem item) {
// Handle navigation view item clicks here.
int id = item.getItemId();
if (id == R.id.nav_search) {
// Handle the camera action
} else if (id == R.id.nav_best) {
} else if (id == R.id.nav_worst) {
} else if (id == R.id.nav_comments) {
} else if (id == R.id.nav_policy) {
} else if (id == R.id.nav_rules) {
} else if (id == R.id.nav_about) {
} else if (id == R.id.nav_contact) {
}
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
drawer.closeDrawer(GravityCompat.START);
return true;
}
class CustomAdapter extends BaseAdapter {
#Override
public int getCount() {
return comments_dateList.size();
}
#Override
public Object getItem(int position) {
return null;
}
#Override
public long getItemId(int position) {
return 0;
}
#Override
public boolean isEnabled(int position) {
return false;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
convertView = getLayoutInflater().inflate(R.layout.customlayout_lastcomment_homepage, null);
TextView textViewUser = (TextView) convertView.findViewById(R.id.textViewUser);
TextView textViewDate = (TextView) convertView.findViewById(R.id.textViewDate);
TextView textViewMessage = (TextView) convertView.findViewById(R.id.textViewMessage);
textViewUser.setText(comments_userList.get(position));
textViewDate.setText(comments_dateList.get(position));
textViewMessage.setText(comments_messageList.get(position));
lastComments.setOnItemClickListener(new AdapterView.OnItemClickListener(){
#Override
public void onItemClick(AdapterView<?> parent,
View view, int position, long id) {
Log.d("asdasdxxxxx", String.valueOf(position));
}});
return convertView;
}
}
}
You can create your own interface :
private interface OnListItemClickListener
{
void onListItemClicked(View view, int position);
}
Then use it in your adapter class this way:
class CustomAdapter extends BaseAdapter {
//create an instance
private OnListItemClickListener onListItemClickListener;
//define the object setter
void setOnListItemClickListener(OnListItemClickListener listener)
{
this.onListItemClickListener=listener;}
#Override
public int getCount() {
return comments_dateList.size();
}
#Override
public Object getItem(int position) {
return null;
}
#Override
public long getItemId(int position) {
return 0;
}
#Override
public boolean isEnabled(int position) {
return false;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
convertView = getLayoutInflater().inflate(R.layout.customlayout_lastcomment_homepage, null);
TextView textViewUser = (TextView) convertView.findViewById(R.id.textViewUser);
TextView textViewDate = (TextView) convertView.findViewById(R.id.textViewDate);
TextView textViewMessage = (TextView) convertView.findViewById(R.id.textViewMessage);
textViewUser.setText(comments_userList.get(position));
textViewDate.setText(comments_dateList.get(position));
textViewMessage.setText(comments_messageList.get(position));
//Then here trigger
convertView.setOnClickListener(new View.OnClickListener()
{
#override
void onClick(View v)
{
onListItemClickListener.onListItemClicked(v,position);
//you may be asked to set position as final
}
});
return convertView;
}
}
Then in your onCreate method where you attached the adapter, set the listener to your adapter:
MainActivity.CustomAdapter customAdapter = new MainActivity.CustomAdapter();
customAdapter.setOnListItemClickListener(new OnListItemClickListener()
{
#override
void onListItemClicked(View view,int position)
{
//then here place your desired action
}
});
lastComments.setAdapter(customAdapter);
I hope this may be helpful. You can still ask for clarifications in comment
I created a small application where I have a list of products and for each of the product I have an expiry time. If the user chooses to like a certain product(showTimerPost), the expiry time of the product will increase lets say 5 second. I tried it with a handler and it actually worked but my app started to run really slow maybe because it was changing the UI every second. I am really stuck with this problem for 1 month. Help will be appreciated.
package com.blueflair.incre;
import com.blueflair.incre.app.AppController;
import com.blueflair.incre.data.FeedItem;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.text.TextUtils;
import android.text.format.DateUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import com.android.volley.toolbox.ImageLoader;
public class FeedListAdapter extends BaseAdapter {
private Activity activity;
private LayoutInflater inflater;
LocalUserData userLocalStore;
long postExpiry;
String timerFormat;
private int defaultPostIncrementation = 900000;
private List<FeedItem> feedItems;
boolean favourite;
ImageLoader imageLoader = AppController.getInstance().getImageLoader();
private long timeDiff;
private final List<ViewHolder> lstHolders;
private int avatarSize;
Handler handler = new Handler();
private Runnable timerRunnable = new Runnable() {
#Override
public void run() {
for (final ViewHolder holder : lstHolders) {
holder.showTimerPost.postDelayed(new Runnable() {
#Override
public void run() {
long currentTime = System.currentTimeMillis();
currentTime--;
holder.showTimerPost.setText(String.valueOf(holder.updateTimeRemaining(currentTime)));
notifyDataSetChanged();
}
}, 2000);
}
}
};
public FeedListAdapter(Activity activity, List<FeedItem> feedItems) {
this.activity = activity;
this.feedItems = feedItems;
lstHolders = new ArrayList<>();
}
#Override
public int getCount() {
return feedItems.size();
}
#Override
public Object getItem(int location) {
return feedItems.get(location);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
final ViewHolder holder;
if (inflater == null)
inflater = (LayoutInflater) activity
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
if (convertView == null)
convertView = inflater.inflate(R.layout.feed_item, null);
if (imageLoader == null)
imageLoader = AppController.getInstance().getImageLoader();
final FeedItem item = feedItems.get(position);
holder = new ViewHolder();
userLocalStore = new LocalUserData(activity);
final User user = userLocalStore.getLoggedInUser();
postExpiry = item.getPostExpiry();
avatarSize = activity.getResources().getDimensionPixelSize(R.dimen.feed_avater_size);
holder.name = (TextView) convertView.findViewById(R.id.userFeedName);
holder.timestamp = (TextView) convertView
.findViewById(R.id.timestamp);
holder.statusMsg = (TextView) convertView
.findViewById(R.id.txtStatusMsg);
holder.profilePic = (ImageView) convertView
.findViewById(R.id.profilePic);
holder.profilePic.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Bundle args= new Bundle();
args.putInt("userId", item.getUserId());
Fragment profileViewFragment = new ProfileViewFragment();
profileViewFragment.setArguments(args);
FragmentTransaction ft = ((MainActivity)activity).getSupportFragmentManager().beginTransaction();
ft.setCustomAnimations(R.anim.slide_in_done, R.anim.slide_out_send);
ft.replace(R.id.container_body, profileViewFragment);
ft.addToBackStack(null);
ft.commit();
}
});
holder.feedImageView = (FeedImageView) convertView
.findViewById(R.id.feedImage1);
String username = "#"+item.getUserName();
holder.name.setText(username);
convertView.setTag(holder);
synchronized ( lstHolders) {
lstHolders.add(holder);
}
// Converting timestamp into x ago format
CharSequence timeAgo = DateUtils.getRelativeTimeSpanString(
Long.parseLong(item.getTimeCreated()),
System.currentTimeMillis(), DateUtils.SECOND_IN_MILLIS);
holder.timestamp.setText(timeAgo);
holder.showTimerPost = (Button) convertView.findViewById(R.id.showPostTimer);
handler.post(timerRunnable);
holder.showTimerPost.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
item.setIncrementToExpiry(50000);
notifyDataSetChanged();
}
});
// Chcek for empty status message
if (!TextUtils.isEmpty(item.getPostMessage())) {
holder.statusMsg.setText(item.getPostMessage());
holder.statusMsg.setVisibility(View.VISIBLE);
} else {
// status is empty, remove from view
holder.statusMsg.setVisibility(View.GONE);
}
// Feed image
if (item.getUserImage() != null) {
holder.feedImageView.setImageUrl(item.getUserImage(), imageLoader);
holder.feedImageView.setVisibility(View.VISIBLE);
holder.feedImageView
.setResponseObserver(new FeedImageView.ResponseObserver() {
#Override
public void onError() {
}
#Override
public void onSuccess() {
}
});
} else {
holder.feedImageView.setVisibility(View.GONE);
}
//Setting the timer adapter for the post and their respective contents
holder.setData(item);
return convertView;
}
private class ViewHolder {
FeedItem item;
public TextView name;
public TextView timestamp;
public TextView statusMsg;
public ImageView profilePic;
public FeedImageView feedImageView;
public Button showTimerPost;
public void setData(FeedItem item) {
this.item = item;
updateTimeRemaining(System.currentTimeMillis());
}
public String updateTimeRemaining(long currentTime) {
timeDiff = (item.getPostExpiry()+400000000) - currentTime;
if (timeDiff > 0) {
timerFormat = String.format("%02d:%02d:%02d", TimeUnit.MILLISECONDS.toHours(timeDiff),
TimeUnit.MILLISECONDS.toMinutes(timeDiff) - TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS.toHours(timeDiff)),
TimeUnit.MILLISECONDS.toSeconds(timeDiff) - TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(timeDiff)));
showTimerPost.setText(timerFormat);
return timerFormat;
} else {
//Delete feed items when post is expired
showTimerPost.setText("Expired!");//only to explimify
}
return timerFormat;
}
}
}
I need to add ListView items that can contain different count of TextView and Imageview objects. How can I do it? And how to determine and setup the id's of this objects? When I try to add an ImageView or TextView to LinearLayout with id R.id.chat_message, the application crashes :(
package com.me.my_app;
import java.util.ArrayList;
import android.app.ListActivity;
import android.content.Context;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
public class FriendSendMessageActivity extends ListActivity {
ListView view;
public ContactAdapter contactAdapter;
LinearLayout LL;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.chat_send_message);
Bundle extras = getIntent().getExtras();
if(extras != null)
{
int index = Integer.parseInt(extras.get(getPackageName() + ".IndexInList").toString());
String sentFrom = extras.get(getPackageName() + ".SentFrom").toString();
int id = Integer.parseInt(extras.get(getPackageName() + ".Id").toString()); //либо id друга либо id друга
FriendItem.Friend item = TabFriendsActivity.getList().get(index);
view = getListView();
contactAdapter = new ContactAdapter();
contactAdapter.addItem(new MessageItem.Message(1, true, true, true, "123","13:31",new ArrayList<MessageItem.Message.Attachment>()));
ArrayList<MessageItem.Message.Attachment> list = new ArrayList<MessageItem.Message.Attachment>();
list.add(new MessageItem.Message.Attachment(MessageAttachmentType.PHOTO, RoundedImage.createRoundedPhoto(BitmapFactory.decodeResource(MainActivity.res,R.drawable.temp_user_photo))));
contactAdapter.addItem(new MessageItem.Message(1, true, true, true, "123","9:10",list));
view.setAdapter(contactAdapter);
}
}
class ContactAdapter extends BaseAdapter {
private ArrayList<MessageItem.Message> mData = new ArrayList<MessageItem.Message>();
private LayoutInflater mInflater;
private static final int IGNORE_ITEM_VIEW_TYPE = -1;
private static final int TYPE_ITEM = 0; //обычный item
private static final int TYPE_MAX_COUNT = 2; //макс. число layout'ов отображения item'ов
public ContactAdapter()
{
mInflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
public void addItem(final MessageItem.Message item) {
mData.add(item);
notifyDataSetChanged();
}
public int getItemViewType(int position)
{
return TYPE_ITEM;
}
#Override
public int getViewTypeCount() {
return TYPE_MAX_COUNT;
}
public int getCount()
{
return mData.size();
}
public MessageItem.Message getItem(int position)
{
return mData.get(position);
}
public long getItemId(int position)
{
return position;
}
public boolean isEnabled(int pos)
{
return true;
}
public View getView(int position, View convertView, ViewGroup parent) {
MessageItem.ViewHolder holder = null;
MessageItem.Message item = mData.get(position);
LayoutParams params = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
if (convertView == null)
{
holder = new MessageItem.ViewHolder();
convertView = mInflater.inflate(item.in_out ? R.layout.chat_message_in_item : R.layout.chat_message_out_item, null, false);
if(item.listAttach.size() > 0)
holder.attachLL = (LinearLayout) findViewById(R.id.chat_message);
for(MessageItem.Message.Attachment attach : item.listAttach)
{
switch(attach.type)
{
case PHOTO:
if(attach.photo != null)
{
ImageView iv = new ImageView(convertView.getContext());
//iv.setLayoutParams(params);
iv.setId(0x7f000000 - 1);
holder.listAttach.add(new MessageItem.Message.Attachment(attach.type,iv));
Log.v("","1" + iv.getId() + " " + holder.listAttach.size());
}
else
Log.v("", "Null!");
break;
}
}
convertView.setTag(holder);
} else {
holder = (MessageItem.ViewHolder) convertView.getTag();
}
for(int i = 0; i < holder.listAttach.size();i++)
{
if(holder.listAttach.get(i).type == MessageAttachmentType.PHOTO && item.listAttach.get(i).photo != null && holder.listAttach.get(i).image != null)
{
holder.attachLL.addView(holder.listAttach.get(i).image);
holder.listAttach.get(i).image.setImageBitmap(item.listAttach.get(i).photo);
}
else
Log.v("", "Unable to add image!");
}
return convertView;
}
}
}
And MessageItem.java:
package com.me.my_app;
import java.util.ArrayList;
import java.util.Comparator;
import android.graphics.Bitmap;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
public class MessageItem
{
public static class Message implements Comparator<Message>
{
int id;
boolean in_out;
boolean is_read;
boolean is_delivered;
String message;
String time;
ArrayList<Attachment> listAttach;
public Message(int id, boolean in_out, boolean is_read, boolean is_delivered, String message, String time, ArrayList<Attachment> list)
{
this.id = id;
this.in_out = in_out;
this.is_read = is_read;
this.is_delivered = is_delivered;
this.message = message;
this.time = time;
listAttach = new ArrayList<Attachment>();
if(list != null)
{
for(Attachment a : list)
listAttach.add(a);
}
}
public int compare(Message object1, Message object2) {
return object1.time.compareTo(object2.time);
}
public static class Attachment
{
ImageView image;
MessageAttachmentType type;
Bitmap photo;
String Uri;
public Attachment(MessageAttachmentType type, Bitmap photo)
{
this.type = type;
this.photo = photo;
}
public Attachment(MessageAttachmentType type, ImageView image)
{
this.type = type;
this.image = image;
}
}
}
public static class ViewHolder
{
LinearLayout attachLL;
TextView text, time;
ArrayList<MessageItem.Message.Attachment> listAttach;
public ViewHolder()
{
listAttach = new ArrayList<MessageItem.Message.Attachment>();
}
}
}
enter code here
You will most probably have to implement your own list view adapter. Then you can create any layout for your item and set it up. Here is how it's done in my code:
public class ExpAdapter extends BaseExpandableListAdapter {
/*SOME CODE HERE*/
#Override
public View getChildView(int groupPosition, int childPosition,
boolean isLastChild, View convertView, ViewGroup parent) {
if (convertView == null) {
LayoutInflater inflater = (LayoutInflater) myContext
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.child_row, null);
}
int groupId = ((ListTaskElement)this.getGroup(groupPosition)).id;
this.setupTaskView(convertView, this.childrenOfGroup(groupId, false).get(childPosition));
convertView.setTag(this.getChildId(groupPosition, childPosition));
return convertView;
}
/*SOME CODE HERE*/
}
You can find all the details here: http://jnastase.alner.net/archive/2010/12/19/custom-android-listadapter.aspx