recycler-adapter https://www.e-learn.cn/tag/recycler-adapter zh-hans How to get a TEXT VIEW value from selected item in RECYCLERVIEW https://www.e-learn.cn/topic/3668220 <span>How to get a TEXT VIEW value from selected item in RECYCLERVIEW</span> <span><span lang="" about="/user/239" typeof="schema:Person" property="schema:name" datatype="">旧城冷巷雨未停</span></span> <span>2020-06-17 09:59:18</span> <div class="field field--name-body field--type-text-with-summary field--label-hidden field--item"><h3>问题</h3><br /><p>I am trying to get a TextView value out of the selected item within the RecyclerView and send this value to an other activity . My RecyclerView layout file has two TextViews, one for the firstname and the lastname and the other one for the email . i found that recyclerview doesnt support some functionality like LIST VIEW , this is my code if any one can suggest for me something please.</p> <pre><code> import android.content.Context; import android.content.Intent; import android.os.Handler; import android.text.Editable; import android.text.Spannable; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; import android.widget.Toast; import androidx.recyclerview.widget.RecyclerView; import com.example.lab.Activities.MainActivity; import com.example.lab.Activities.ModifyPers; import com.example.lab.Activities.NewPersActivity; import com.example.lab.Entities.Personne; import java.util.List; public class ApiPersListAdapter extends RecyclerView.Adapter&lt;ApiPersListAdapter.ViewHolder&gt; { TextView text1; Handler handler =new Handler(); String s; private Context context; private List&lt;Personne&gt; list; String nom; public ApiPersListAdapter(Context context, List&lt;Personne&gt; list) { this.context = context; this.list = list; } @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View v = LayoutInflater.from(context).inflate(R.layout.recyclerview_api_list_item, parent, false); return new ViewHolder(v); } @Override public void onBindViewHolder(ViewHolder holder, int position) { Personne p = list.get(position); holder.nom_pre.setText(p.getPrenom()+" "+p.getNom()); holder.email.setText(p.getEmail()); } @Override public int getItemCount() { return list.size(); } public class ViewHolder extends RecyclerView.ViewHolder { public TextView nom_pre,email; public ViewHolder(View itemView) { super(itemView); nom_pre = itemView.findViewById(R.id.nom_pren); email = itemView.findViewById(R.id.email); itemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Intent intent = new Intent(itemView.getContext(), ModifyPers.class); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); Log.v("nom",nom); intent.putExtra("key_prenom",nom); itemView.getContext().startActivity(intent); } }); } } } </code></pre> <br /><h3>回答1:</h3><br /><p>In your <code>itemView.setOnClickListener</code> in the <code>ViewHolder</code> class , in the line <code>intent.putExtra("key_prenom",nom);</code>, replace variable <code>nom</code> with this:</p> <pre><code> list.get(getAdapterPosition()).getNom(); </code></pre> <br /><br /><br /><h3>回答2:</h3><br /><p>I have made changes in your class. Please have a look. Do implement listener in your activity</p> <pre><code> public class ApiPersListAdapter extends RecyclerView.Adapter&lt;ApiPersListAdapter.ViewHolder&gt; { public interface OnItemClickListener { void onItemClick(ContentItem item); } private final OnItemClickListener listener; TextView text1; Handler handler =new Handler(); String s; private Context context; private List&lt;Personne&gt; list; String nom; public ApiPersListAdapter(Context context, List&lt;Personne&gt; list,OnItemClickListener listener) { this.context = context; this.list = list; this.listener = listener; } @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View v = LayoutInflater.from(context).inflate(R.layout.recyclerview_api_list_item, parent, false); return new ViewHolder(v); } @Override public void onBindViewHolder(ViewHolder holder, int position) { holder.bind(items.get(position), listener); } @Override public int getItemCount() { return list.size(); } public class ViewHolder extends RecyclerView.ViewHolder { public TextView nom_pre,email; public ViewHolder(View itemView) { super(itemView); nom_pre = itemView.findViewById(R.id.nom_pren); email = itemView.findViewById(R.id.email); itemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { listener.onItemClick(item); } }); </code></pre> <br /><br /><br /><h3>回答3:</h3><br /><p>You can try this on your onCreateViewHolder</p> <pre><code>LayoutInflater inflater = LayoutInflater.from(getApplicationContext()); View v = inflater.inflate(R.layout.recyclerview_api_list_item, null); </code></pre> <p>To get or set value to the textview of <code>R.layout.recyclerview_api_list_item</code> recycleview you need to find the view first so you can access them by the defined view.</p> <pre><code>v.findViewById(R.id.textviewID1); v.findViewById(R.id.textviewID2); </code></pre> <p>Then return the view</p> <pre><code>return new ViewHolder(v); </code></pre> <br /><br /><p>来源:<code>https://stackoverflow.com/questions/57391700/how-to-get-a-text-view-value-from-selected-item-in-recyclerview</code></p></div> <div class="field field--name-field-tags field--type-entity-reference field--label-above"> <div class="field--label">标签</div> <div class="field--items"> <div class="field--item"><a href="/tag/java" hreflang="zh-hans">java</a></div> <div class="field--item"><a href="/tag/android" hreflang="zh-hans">android</a></div> <div class="field--item"><a href="/tag/android-recyclerview" hreflang="zh-hans">android-recyclerview</a></div> <div class="field--item"><a href="/tag/recycler-adapter" hreflang="zh-hans">recycler-adapter</a></div> </div> </div> Wed, 17 Jun 2020 01:59:18 +0000 旧城冷巷雨未停 3668220 at https://www.e-learn.cn The correct way of implementing getItemId() in RecyclerView.Adapter https://www.e-learn.cn/topic/3663393 <span>The correct way of implementing getItemId() in RecyclerView.Adapter</span> <span><span lang="" about="/user/214" typeof="schema:Person" property="schema:name" datatype="">半腔热情</span></span> <span>2020-06-11 20:06:04</span> <div class="field field--name-body field--type-text-with-summary field--label-hidden field--item"><h3>问题</h3><br /><p>I have generic class </p> <pre><code>public abstract class BaseAdapter&lt;T&gt; extends RecyclerView.Adapter { private List&lt;T&gt; itemsList = new ArrayList&lt;&gt;(); //other override methods @Override public long getItemId(int position) { return position; } } </code></pre> <p>What is the correct way to implementing getItemId()? I think that <code>return position</code> like in many example is not correct.</p> <br /><h3>回答1:</h3><br /><ol><li><p>Create a base interface that has a method that returns a type <code>long</code> eg.</p> <pre><code>interface BaseInterface{ long getId(); } </code></pre></li> <li><p>Change </p> <pre><code>abstract class BaseAdapter&lt;T&gt; extends RecyclerView.Adapter </code></pre> <p>to </p> <pre><code>abstract class BaseAdapter&lt;T extends BaseInterface&gt; extends RecyclerView.Adapter { </code></pre> <p>Note: The signature changed to <code>T extends BaseInterface</code></p></li> <li><p>Replace </p> <pre><code>@Override public long getItemId(int position) { return position; } </code></pre> <p>with</p> <pre><code>@Override public long getItemId(int position) { return itemsList.get(position).getId(); } </code></pre></li> </ol><br /><br /><br /><h3>回答2:</h3><br /><p>In the List you could only return the Id of the Item available at specific row as mentioned by Google documents:</p> <blockquote> <p>getItemId</p> <p>Get the row id associated with the specified position in the list.</p> </blockquote> <p>But that's not the case with RecyclerView, in RecyclerView you have to ensure that you either return a unique Id for each Item or In case of no Stable Id you should return <code>RecyclerView.NO_ID</code> (-1). Please Refrain from returning values that are not stable. (An Stable value would be a unique value that does not change even if position of dataset changes)</p> <br /><br /><br /><h3>回答3:</h3><br /><p>you should implement this methode: as you see you must tell the Adapter that you implemented that by <code>setHasStableIds(true);</code></p> <pre><code>class MyAdapter extends RecyclerView.Adapter&lt;MyAdapter.MyViewHolder&gt; { MyAdapter() { setHasStableIds(true); // **very importent** } @Override public long getItemId(int position) { // requires static value, it means need to keep the same value // even if the item position has been changed. return mItems.get(position).getId(); } </code></pre> <p>}</p> <br /><br /><p>来源:<code>https://stackoverflow.com/questions/42646950/the-correct-way-of-implementing-getitemid-in-recyclerview-adapter</code></p></div> <div class="field field--name-field-tags field--type-entity-reference field--label-above"> <div class="field--label">标签</div> <div class="field--items"> <div class="field--item"><a href="/tag/android" hreflang="zh-hans">android</a></div> <div class="field--item"><a href="/tag/android-recyclerview" hreflang="zh-hans">android-recyclerview</a></div> <div class="field--item"><a href="/tag/adapter" hreflang="zh-hans">adapter</a></div> <div class="field--item"><a href="/tag/recycler-adapter" hreflang="zh-hans">recycler-adapter</a></div> </div> </div> Thu, 11 Jun 2020 12:06:04 +0000 半腔热情 3663393 at https://www.e-learn.cn How to run my RecyclerView with CardView in fragment? https://www.e-learn.cn/topic/3656667 <span>How to run my RecyclerView with CardView in fragment?</span> <span><span lang="" about="/user/64" typeof="schema:Person" property="schema:name" datatype="">久未见</span></span> <span>2020-05-29 11:18:32</span> <div class="field field--name-body field--type-text-with-summary field--label-hidden field--item"><h3>问题</h3><br /><p>I have this code and everytime I tried to run it ..the application is not running not error but not running can anyone please help me to determine what is the reason for getting this kind of problem.</p> <p>because I'm doing RecyclerView with CardView in fragment I have this problem almost a week :(</p> <p>this is my code:</p> <pre><code>public class RecyclerViewAdapter extends RecyclerView.Adapter&lt;RecyclerViewAdapter.MyViewHolder&gt; { private Context mContext ; private List&lt;Book&gt; mData ; public RecyclerViewAdapter(Context mContext, List&lt;Book&gt; mData) { this.mContext = mContext; this.mData = mData; } public RecyclerViewAdapter(TimeFragment timeFragment, List&lt;Book&gt; lstBook) { } @Override public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view ; LayoutInflater mInflater = LayoutInflater.from(mContext); view = mInflater.inflate(R.layout.cardveiw_item_book,parent,false); return new MyViewHolder(view); } @Override public void onBindViewHolder(MyViewHolder holder, final int position) { holder.tv_book_title.setText(mData.get(position).getTitle()); holder.img_book_thumbnail.setImageResource(mData.get(position).getThumbnail()); } @Override public int getItemCount() { return mData.size(); } public static class MyViewHolder extends RecyclerView.ViewHolder { public TextView tv_book_title; public ImageView img_book_thumbnail; CardView cardView ; public MyViewHolder(View itemView) { super(itemView); tv_book_title = (TextView) itemView.findViewById(R.id.book_title_id) ; img_book_thumbnail = (ImageView) itemView.findViewById(R.id.book_img_id); cardView = (CardView) itemView.findViewById(R.id.cardview_id); } } } </code></pre> <p>Here's is the related POJO class.</p> <pre><code>public class Book { private String Title; private String Category ; private String Description ; private int Thumbnail ; public Book() { } public Book(String title, String category, String description, int thumbnail) { Title = title; Category = category; Description = description; Thumbnail = thumbnail; } public String getTitle() { return Title; } public String getCategory() { return Category; } public String getDescription() { return Description; } public int getThumbnail() { return Thumbnail; } public void setTitle(String title) { Title = title; } public void setCategory(String category) { Category = category; } public void setDescription(String description) { Description = description; } public void setThumbnail(int thumbnail) { Thumbnail = thumbnail; } } </code></pre> <p>Code for the fragment that sets the adapter to RecyclerView.</p> <pre><code>public class TimeFragment extends Fragment { List&lt;Book&gt; lstBook ; public TimeFragment() { } @Nullable @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); lstBook = new ArrayList&lt;&gt;(); lstBook.add(new Book("The Vegitarian","Categorie Book","Description book",R.drawable.ic_in)); lstBook.add(new Book("The Wild Robot","Categorie Book","Description book",R.drawable.ic_out)); lstBook.add(new Book("Maria Semples","Categorie Book","Description book",R.drawable.ic_in)); lstBook.add(new Book("The Martian","Categorie Book","Description book",R.drawable.ic_out)); } @Nullable @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View view; view = inflater.inflate( R.layout.recyclerview, container, false); RecyclerView myrv = (RecyclerView) view.findViewById(R.id.recyclerview_id); RecyclerViewAdapter myAdapter = new RecyclerViewAdapter(this,lstBook); GridLayoutManager gridLayoutManager = new GridLayoutManager(getActivity(), 2); myrv.setLayoutManager(gridLayoutManager); myrv.setAdapter(myAdapter); return view; } } </code></pre> <br /><h3>回答1:</h3><br /><p>There are actually two ways to do it.</p> <p><strong>1. Remove the below-mentioned line from the RecyclerViewAdapter.</strong></p> <p><strong><em>public RecyclerViewAdapter(TimeFragment timeFragment, List lstBook) { }</em></strong></p> <p>and in the fragment code, there is also a minor change kindly look the code below and also I didn't have the drawable so I used the default one.</p> <pre><code>public class TimeFragment extends Fragment { List&lt;Book&gt; lstBook ; public TimeFragment() { // Required empty public constructor } @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); lstBook = new ArrayList&lt;&gt;(); lstBook.add(new Book("The Vegitarian","Categorie Book","Description book",R.drawable.ic_launcher_background)); lstBook.add(new Book("The Wild Robot","Categorie Book","Description book",R.drawable.ic_launcher_background)); lstBook.add(new Book("Maria Semples","Categorie Book","Description book",R.drawable.ic_launcher_background)); lstBook.add(new Book("The Martian","Categorie Book","Description book",R.drawable.ic_launcher_background)); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // Inflate the layout for this fragment View view = inflater.inflate(R.layout.fragment_time, container, false); RecyclerView myrv = (RecyclerView) view.findViewById(R.id.recyclerview_id); RecyclerViewAdapter myAdapter = new RecyclerViewAdapter(getContext(),lstBook); GridLayoutManager gridLayoutManager = new GridLayoutManager(getContext(), 2); myrv.setLayoutManager(gridLayoutManager); myrv.setAdapter(myAdapter); return view; } } </code></pre> <p>And if you don't remove the above-mentioned line still it is going to work. Just modify the code of your TimeFragment.</p> <ol start="2"><li><p>What has happened is when you have the context in the adapter constructor you have actually used the second constructor of the adapter which takes the argument as shown below</p> <p><strong>public RecyclerViewAdapter(TimeFragment timeFragment, List lstBook) {<br /> }</strong></p></li> </ol><p>In this, you have actually not populated the list, which you have done in the first constructor shown below.</p> <pre><code>public RecyclerViewAdapter(Context mContext, List&lt;Book&gt; mData) { this.mContext = mContext; this.mData = mData; } </code></pre> <p>Now the app crashes because when it finds the list in the adapter it is always empty. so it crashes. I have changed a few lines in the code in both the adapter part and the fragment part. Kindly find the changes below.</p> <p>RecyclerViewAdapter:</p> <pre><code> public class RecyclerViewAdapter extends RecyclerView.Adapter&lt;RecyclerViewAdapter.MyViewHolder&gt; { private Context mContext ; private List&lt;Book&gt; mData ; private TimeFragment timeFragment; public RecyclerViewAdapter(Context mContext, List&lt;Book&gt; mData) { this.mContext = mContext; this.mData = mData; } public RecyclerViewAdapter(TimeFragment timeFragment, List&lt;Book&gt; lstBook) { this.timeFragment = timeFragment; this.mData = lstBook; } @Override public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view ; LayoutInflater mInflater = LayoutInflater.from(timeFragment.getContext()); view = mInflater.inflate(R.layout.cardveiw_item_book,parent,false); return new MyViewHolder(view); } @Override public void onBindViewHolder(MyViewHolder holder, final int position) { holder.tv_book_title.setText(mData.get(position).getTitle()); holder.img_book_thumbnail.setImageResource(mData.get(position).getThumbnail()); } @Override public int getItemCount() { return mData.size(); } public static class MyViewHolder extends RecyclerView.ViewHolder { public TextView tv_book_title; public ImageView img_book_thumbnail; CardView cardView ; public MyViewHolder(View itemView) { super(itemView); tv_book_title = (TextView) itemView.findViewById(R.id.book_title_id) ; img_book_thumbnail = (ImageView) itemView.findViewById(R.id.book_img_id); cardView = (CardView) itemView.findViewById(R.id.cardview_id); } } } </code></pre> <p>Time Fragment: </p> <pre><code>public class TimeFragment extends Fragment { List&lt;Book&gt; lstBook ; public TimeFragment() { // Required empty public constructor } @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); Log.d("TestFailed","OnCreate"); lstBook = new ArrayList&lt;&gt;(); lstBook.add(new Book("The Vegitarian","Categorie Book","Description book",R.drawable.ic_launcher_background)); lstBook.add(new Book("The Wild Robot","Categorie Book","Description book",R.drawable.ic_launcher_background)); lstBook.add(new Book("Maria Semples","Categorie Book","Description book",R.drawable.ic_launcher_background)); lstBook.add(new Book("The Martian","Categorie Book","Description book",R.drawable.ic_launcher_background)); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // Inflate the layout for this fragment Log.d("TestFailed","OnCreateView"); View view = inflater.inflate(R.layout.fragment_time, container, false); RecyclerView myrv = (RecyclerView) view.findViewById(R.id.recyclerview_id); RecyclerViewAdapter myAdapter = new RecyclerViewAdapter(this,lstBook); GridLayoutManager gridLayoutManager = new GridLayoutManager(getContext(), 2); myrv.setLayoutManager(gridLayoutManager); myrv.setAdapter(myAdapter); return view; } } </code></pre> <p>Hope that helps and clears the doubt.</p> <br /><br /><br /><h3>回答2:</h3><br /><p>No context is passed from your fragment. You are passing <strong>this</strong> which is TimeFragment so the constructor being invoked is</p> <pre><code>public RecyclerViewAdapter(TimeFragment timeFragment, List&lt;Book&gt; lstBook) </code></pre> <p>Use the activity context instead.</p> <pre><code>RecyclerViewAdapter myAdapter = new RecyclerViewAdapter(getActivity(),lstBook); </code></pre> <br /><br /><br /><h3>回答3:</h3><br /><p>Replace Three things in your code as follows:</p> <p><strong>From</strong></p> <pre><code>RecyclerViewAdapter myAdapter = new RecyclerViewAdapter(this,lstBook); </code></pre> <p><strong>To</strong></p> <pre><code>RecyclerViewAdapter myAdapter = new RecyclerViewAdapter(getActivity(),lstBook); </code></pre> <p><strong>From</strong></p> <pre><code>public class RecyclerViewAdapter extends RecyclerView.Adapter { </code></pre> <p><strong>To</strong></p> <pre><code>public class RecyclerViewAdapter extends RecyclerView.Adapter&lt;RecyclerViewAdapter.MyViewHolder&gt; { </code></pre> <p><strong>From (Replace from tow consturcter to one as Bellow)</strong></p> <pre><code>public RecyclerViewAdapter(Context mContext, List&lt;Book&gt; mData) { this.mContext = mContext; this.mData = mData; } public RecyclerViewAdapter(TimeFragment timeFragment, List&lt;Book&gt; lstBook) { } </code></pre> <p><strong>To</strong></p> <pre><code>public RecyclerViewAdapter(Context mContext, List&lt;Book&gt; mData) { this.mContext = mContext; this.mData = mData; } </code></pre> <br /><br /><br /><h3>回答4:</h3><br /><pre><code>public class TimeFragment extends Fragment { List&lt;Book&gt; lstBook ; public TimeFragment() { // Required empty public constructor } @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); lstBook = new ArrayList&lt;&gt;(); lstBook.add(new Book("The Vegitarian","Categorie Book","Description book",R.drawable.ic_launcher_background)); lstBook.add(new Book("The Wild Robot","Categorie Book","Description book",R.drawable.ic_launcher_background)); lstBook.add(new Book("Maria Semples","Categorie Book","Description book",R.drawable.ic_launcher_background)); lstBook.add(new Book("The Martian","Categorie Book","Description book",R.drawable.ic_launcher_background)); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // Inflate the layout for this fragment View view = inflater.inflate(R.layout.fragment_time, container, false); RecyclerView myrv = (RecyclerView) view.findViewById(R.id.recyclerview_id); RecyclerViewAdapter myAdapter = new RecyclerViewAdapter(getContext(),lstBook); GridLayoutManager gridLayoutManager = new GridLayoutManager(getContext(), 2); myrv.setLayoutManager(gridLayoutManager); myrv.setAdapter(myAdapter); return view; } } </code></pre> <br /><br /><p>来源:<code>https://stackoverflow.com/questions/50558081/how-to-run-my-recyclerview-with-cardview-in-fragment</code></p></div> <div class="field field--name-field-tags field--type-entity-reference field--label-above"> <div class="field--label">标签</div> <div class="field--items"> <div class="field--item"><a href="/tag/android" hreflang="zh-hans">android</a></div> <div class="field--item"><a href="/tag/android-fragments" hreflang="zh-hans">android-fragments</a></div> <div class="field--item"><a href="/tag/android-recyclerview" hreflang="zh-hans">android-recyclerview</a></div> <div class="field--item"><a href="/tag/recycler-adapter" hreflang="zh-hans">recycler-adapter</a></div> <div class="field--item"><a href="/tag/android-cardview" hreflang="zh-hans">android-cardview</a></div> </div> </div> Fri, 29 May 2020 03:18:32 +0000 久未见 3656667 at https://www.e-learn.cn How to pass or send data from recyclerview adapter to fragment https://www.e-learn.cn/topic/3650798 <span>How to pass or send data from recyclerview adapter to fragment</span> <span><span lang="" about="/user/113" typeof="schema:Person" property="schema:name" datatype="">╄→尐↘猪︶ㄣ</span></span> <span>2020-05-23 11:52:48</span> <div class="field field--name-body field--type-text-with-summary field--label-hidden field--item"><h3>问题</h3><br /><p>How to pass data from recyclerview adapter to fragment and what i have to write the code in fragment to receive data.I have already check the links in this website but unfortunately unable to get correct code. Below is the code</p> <blockquote> <p>ExampleAdapter.Java</p> </blockquote> <pre><code>public class ExampleAdapter extends RecyclerView.Adapter&lt;ExampleAdapter.ExampleViewHolder&gt; { private ArrayList&lt;ExampleItem&gt; mExampleList; @NonNull @Override public ExampleViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) { View v=LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.example_item,viewGroup,false); ExampleViewHolder evh=new ExampleViewHolder(v); return evh; } @Override public void onBindViewHolder(@NonNull ExampleViewHolder exampleViewHolder, int i) { final ExampleItem currentItem=mExampleList.get(i); exampleViewHolder.mTextView.setText(currentItem.getmText()); exampleViewHolder.mTextView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // pass the data to the fragment } }); } @Override public int getItemCount() { return mExampleList.size(); } public static class ExampleViewHolder extends RecyclerView.ViewHolder { public TextView mTextView; public ExampleViewHolder(@NonNull View itemView) { super(itemView); mTextView=itemView.findViewById(R.id.texttitle); } } public ExampleAdapter(ArrayList&lt;ExampleItem&gt; exampleList){ this.mExampleList=exampleList; } } </code></pre> <br /><h3>回答1:</h3><br /><p>You can pass data by attaching a callback into your adapter:</p> <p><strong>Create an interface</strong>:</p> <pre><code>interface OnTextClickListener { void onTextClick(ExampleItem data); } </code></pre> <p><strong>Delegate the callback</strong>:</p> <pre><code>class ExampleAdapter extends RecyclerView.Adapter&lt;ExampleAdapter.ExampleViewHolder&gt; { List&lt;ExampleItem&gt; items; OnTextClickListener listener; ExampleAdapter(List&lt;ExampleItem&gt; items, OnTextClickListener listener) { this.items = items; this.listener = listener; } @Override public void onBindViewHolder(ExampleViewHolder viewHolder, int position) { viewHolder.textView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // Say you want to pass an ExampleItem back to the fragment... ExampleItem data = items.get(position); listener.onTextClick(data); } }); } } </code></pre> <p><strong>Implement the fragment with the interface</strong>:</p> <pre><code>class YourFragment extends Fragment implements OnTextClickListener { public onViewCreated(View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); recyclerView.setAdapter(new ExampleAdapter(this)); } void onTextClick(ExampleItem data) { // Now you can do however you want with the data here... Toast.makeText(getActivity(), "Got: " + data, Toast.LENGTH_SHORT).show() } } </code></pre> <br /><br /><br /><h3>回答2:</h3><br /><p>You have two options;</p> <p><strong>Using <code>SharedPreferences</code></strong>:</p> <pre><code>Context myContext = exampleViewHolder.itemView.getContext() SharedPreferences.Editor editor = getSharedPreferences("DeviceToken", MODE_PRIVATE).edit(); editor.putString("YourKeyNameHere", currentItem.getmText()); // or add toString() after if needed editor.apply(); </code></pre> <p><sub>To get:</sub></p> <pre><code>SharedPreferences prefs = getSharedPreferences("DeviceToken", MODE_PRIVATE); String deviceToken = prefs.getString("YourKeyNameHere", null); // get it here </code></pre> <p><strong>Using <code>Intent</code></strong>: (If you want to start the another <code>Activity</code> when you pass the data)</p> <pre><code>Intent intent = new Intent(myContext , SignoutActivity.class); intent.putExtra("EXTRA_TEXT", currentItem.getmText()); startActivity(intent); // if needed, add myContext before starting myContext.startActivity... </code></pre> <p><sub>To get:</sub></p> <pre><code>String extraText = getIntent().getStringExtra("EXTRA_TEXT"); </code></pre> <br /><br /><br /><h3>回答3:</h3><br /><p>You have "ClickListener" in fragment.</p> <p>for example.</p> <pre><code>@Override public void onResume(){ super.onResume(); ((ExampleAdapter) mAdapter).onItemClick(new RecyclerViewItemClick() { @Override public void onItemClick(int position, View v) { //to do. ArrayList&lt;&gt; data.get(position).getYourItem(); } }); } </code></pre> <p>And you must create interface RecyclerViewItemClick.java</p> <pre><code>public interface RecyclerViewItemClick { public void onItemClick(int position, View v); } </code></pre> <p>Last. ExampleAdapter.java add</p> <pre><code>public void onItemClick(RecyclerViewItemClick mclick){ this.myClickListener = mclick; } </code></pre> <p>ExampleViewHolder method add in</p> <pre><code>@Override public void onClick(View v) { myClickListener.onItemClick(getAdapterPosition(), v); notifyDataSetChanged(); } </code></pre> <p>I hope you solve this problem. Thank.</p> <br /><br /><br /><h3>回答4:</h3><br /><p>Have a <code>IDataCollector</code> interface. Implement her in the <code>Fragment</code>, pass the <code>Fragment</code> reference as a constructor parameter, and use it inside the adapter</p> <pre><code>public interface IDataCollector { void setText(String text); void setAnything(Object anything); } // Fragment public class Fragment implements IDataCollector { private void initView() { // Add this as a parameter ExampleAdapter adapter = new ExampleAdapter(... , this); } @Override public void setText(String text){ this.textField = text; } @Override public void setText(Object anything){ this.anything = anything; } } // Adapter code // Constructor, parameters ommited public ExampleAdapter(...., IDataCollector dataCollector) { this.dataCollector = dataCollector; } @Override public void onBindViewHolder(@NonNull ExampleViewHolder exampleViewHolder, int i) { final ExampleItem currentItem=mExampleList.get(i); exampleViewHolder.mTextView.setText(currentItem.getmText()); exampleViewHolder.mTextView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { dataCollector.setText(((TextView)v.findViewById(R.id.label1)).getText()); .... } }); } </code></pre> <br /><br /><br /><h3>回答5:</h3><br /><p>Through Interface you can solve this 1. create an Interface in adapter , add required methods 2. call those methods in adapter wherever required 3. implement the interface in fragment or activity, pass a context to the adapter</p> <br /><br /><p>来源:<code>https://stackoverflow.com/questions/52829707/how-to-pass-or-send-data-from-recyclerview-adapter-to-fragment</code></p></div> <div class="field field--name-field-tags field--type-entity-reference field--label-above"> <div class="field--label">标签</div> <div class="field--items"> <div class="field--item"><a href="/tag/java" hreflang="zh-hans">java</a></div> <div class="field--item"><a href="/tag/android" hreflang="zh-hans">android</a></div> <div class="field--item"><a href="/tag/recycler-adapter" hreflang="zh-hans">recycler-adapter</a></div> </div> </div> Sat, 23 May 2020 03:52:48 +0000 ╄→尐↘猪︶ㄣ 3650798 at https://www.e-learn.cn Using ViewTreeObserver i am adding setMaxLines and setEllipsize in MaterialTextView inside RecyclerView.Adapter https://www.e-learn.cn/topic/3649921 <span>Using ViewTreeObserver i am adding setMaxLines and setEllipsize in MaterialTextView inside RecyclerView.Adapter</span> <span><span lang="" about="/user/112" typeof="schema:Person" property="schema:name" datatype="">回眸只為那壹抹淺笑</span></span> <span>2020-05-21 07:24:46</span> <div class="field field--name-body field--type-text-with-summary field--label-hidden field--item"><h3>问题</h3><br /><ul><li><p>I am set <code>MaterialTextView</code> inside <code>RelativeLayout</code> and set <code>RelativeLayout</code> size programmatically different size for every device.</p></li> <li><p>Then i have using <code>ViewTreeObserver</code> to set <code>setMaxLines</code> and <code>setEllipsize</code> in <code>MaterialTextView</code> but i am facing some problem show the text in <code>MaterialTextView</code> using RecyclerView.Adapter.</p></li> <li><p>I am using load more <code>RecyclerView</code> i am getting all data then after show text automatically in list and also notify data adapter then show text.</p></li> <li><p>not showing text inside <code>MaterialTextView</code> in list</p></li> <li><p>phone lock on/off then showing data in <code>MaterialTextView</code></p></li> </ul><p><strong>set recyclerview in fragment</strong></p> <pre><code>recyclerView = view.findViewById(R.id.recyclerView_sub_category); recyclerView.setHasFixedSize(true); final LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity()); recyclerView.setLayoutManager(layoutManager); </code></pre> <p><strong>adapter code</strong> </p> <pre><code>public class SubCategoryAdapter extends RecyclerView.Adapter { private final int VIEW_TYPE_LOADING = 0; private final int VIEW_TYPE_ITEM = 1; private final int VIEW_TYPE_QUOTES = 2; @NonNull @Override public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { if (viewType == VIEW_TYPE_ITEM) { other data load } else if (viewType == VIEW_TYPE_QUOTES) { View v = LayoutInflater.from(activity).inflate(R.layout.quotes_adapter, parent, false); return new Quotes(v); } else if (viewType == VIEW_TYPE_LOADING) { progressbar load } return null; } @Override public void onBindViewHolder(@NonNull final RecyclerView.ViewHolder holder, @SuppressLint("RecyclerView") final int position) { if (holder.getItemViewType() == VIEW_TYPE_ITEM) { final ViewHolder viewHolder = (ViewHolder) holder; // ------------- code ----- } else if (holder.getItemViewType() == VIEW_TYPE_QUOTES) { final Quotes quotes = (Quotes) holder; quotes.relativeLayout.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, columnWidth / 2)); Typeface typeface = Typeface.createFromAsset(activity.getAssets(), "text_font/" + subCategoryLists.get(position).getQuote_font()); quotes.textView.setTypeface(typeface); quotes.textView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { quotes.textView.getViewTreeObserver().removeOnGlobalLayoutListener(this); int noOfLinesVisible = quotes.textView.getHeight() / quotes.textView.getLineHeight(); quotes.textView.setMaxLines(noOfLinesVisible); quotes.textView.setEllipsize(TextUtils.TruncateAt.END); quotes.textView.setText(subCategoryLists.get(position).getStatus_title()); } }); } } @Override public int getItemCount() { return subCategoryLists.size() + 1; } @Override public int getItemViewType(int position) { if (position != subCategoryLists.size()) { if (subCategoryLists.get(position).getStatus_type().equals("quote")) { return VIEW_TYPE_QUOTES; } else { return VIEW_TYPE_ITEM; } } else { return VIEW_TYPE_LOADING; } } public class Quotes extends RecyclerView.ViewHolder { private RelativeLayout relativeLayout; private MaterialTextView textView; public Quotes(@NonNull View itemView) { super(itemView); textView = itemView.findViewById(R.id.textView_quotes_adapter); relativeLayout = itemView.findViewById(R.id.rel_quotes_adapter); } } } </code></pre> <br /><h3>回答1:</h3><br /><p>I am not completely sure about the problem that you are having there. However, I think I found some problems in your code. </p> <p>The first problem that I see in setting up your <code>RecyclerView</code> is setting the layout size fixed by the following. </p> <pre><code>recyclerView.setHasFixedSize(true); </code></pre> <p>Looks like you are changing the item layout size dynamically. Hence you need to remove the line above while setting up your <code>RecyclerView</code>. </p> <p>The second problem that I see is, there is no <code>textView_category</code> in the <code>ViewHolder</code> for <code>Quote</code>. Hence the following should throw an error. </p> <pre><code>quotes.textView_category.setText(subCategoryLists.get(position).getCategory_name()); </code></pre> <br /><br /><br /><h3>回答2:</h3><br /><p>One problem I can see is that you are calling</p> <pre><code>quotes.textView.getViewTreeObserver().removeOnGlobalLayoutListener(this); </code></pre> <p>in the first line of your listener callback no matter what. In a RecyclerView the first few times this is called the layout might still be unmeasured but you're cancelling the listener callback after the first callback. So this line fires, and if the view is still unmeasured then the next few lines are going to fail and your code will get no more opportunities to fill the view. Try checking the measuredWidth or measuredHeight of your view for something greater than 0 before cancelling future listener callbacks.</p> <br /><br /><br /><h3>回答3:</h3><br /><p><strong>I have using this. works perfectly</strong></p> <pre><code>textView.setText(subCategoryLists.get(position).getStatus_title()); textView.post(new Runnable() { @Override public void run() { ViewGroup.LayoutParams params = textView.getLayoutParams(); if (params == null) { params = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); } final int widthSpec = View.MeasureSpec.makeMeasureSpec(textView.getWidth(), View.MeasureSpec.UNSPECIFIED); final int heightSpec = View.MeasureSpec.makeMeasureSpec(textView.getHeight(), View.MeasureSpec.UNSPECIFIED); textView.measure(widthSpec, heightSpec); textView.setMaxLines(heightSpec / textView.getLineHeight()); textView.setEllipsize(TextUtils.TruncateAt.END); } }); </code></pre> <br /><br /><p>来源:<code>https://stackoverflow.com/questions/60790803/using-viewtreeobserver-i-am-adding-setmaxlines-and-setellipsize-in-materialtextv</code></p></div> <div class="field field--name-field-tags field--type-entity-reference field--label-above"> <div class="field--label">标签</div> <div class="field--items"> <div class="field--item"><a href="/tag/java" hreflang="zh-hans">java</a></div> <div class="field--item"><a href="/tag/android" hreflang="zh-hans">android</a></div> <div class="field--item"><a href="/tag/android-recyclerview" hreflang="zh-hans">android-recyclerview</a></div> <div class="field--item"><a href="/tag/recycler-adapter" hreflang="zh-hans">recycler-adapter</a></div> <div class="field--item"><a href="/tag/android-viewtreeobserver" hreflang="zh-hans">android-viewtreeobserver</a></div> </div> </div> Wed, 20 May 2020 23:24:46 +0000 回眸只為那壹抹淺笑 3649921 at https://www.e-learn.cn Using ViewTreeObserver i am adding setMaxLines and setEllipsize in MaterialTextView inside RecyclerView.Adapter https://www.e-learn.cn/topic/3649919 <span>Using ViewTreeObserver i am adding setMaxLines and setEllipsize in MaterialTextView inside RecyclerView.Adapter</span> <span><span lang="" about="/user/57" typeof="schema:Person" property="schema:name" datatype="">瘦欲@</span></span> <span>2020-05-21 07:23:02</span> <div class="field field--name-body field--type-text-with-summary field--label-hidden field--item"><h3>问题</h3><br /><ul><li><p>I am set <code>MaterialTextView</code> inside <code>RelativeLayout</code> and set <code>RelativeLayout</code> size programmatically different size for every device.</p></li> <li><p>Then i have using <code>ViewTreeObserver</code> to set <code>setMaxLines</code> and <code>setEllipsize</code> in <code>MaterialTextView</code> but i am facing some problem show the text in <code>MaterialTextView</code> using RecyclerView.Adapter.</p></li> <li><p>I am using load more <code>RecyclerView</code> i am getting all data then after show text automatically in list and also notify data adapter then show text.</p></li> <li><p>not showing text inside <code>MaterialTextView</code> in list</p></li> <li><p>phone lock on/off then showing data in <code>MaterialTextView</code></p></li> </ul><p><strong>set recyclerview in fragment</strong></p> <pre><code>recyclerView = view.findViewById(R.id.recyclerView_sub_category); recyclerView.setHasFixedSize(true); final LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity()); recyclerView.setLayoutManager(layoutManager); </code></pre> <p><strong>adapter code</strong> </p> <pre><code>public class SubCategoryAdapter extends RecyclerView.Adapter { private final int VIEW_TYPE_LOADING = 0; private final int VIEW_TYPE_ITEM = 1; private final int VIEW_TYPE_QUOTES = 2; @NonNull @Override public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { if (viewType == VIEW_TYPE_ITEM) { other data load } else if (viewType == VIEW_TYPE_QUOTES) { View v = LayoutInflater.from(activity).inflate(R.layout.quotes_adapter, parent, false); return new Quotes(v); } else if (viewType == VIEW_TYPE_LOADING) { progressbar load } return null; } @Override public void onBindViewHolder(@NonNull final RecyclerView.ViewHolder holder, @SuppressLint("RecyclerView") final int position) { if (holder.getItemViewType() == VIEW_TYPE_ITEM) { final ViewHolder viewHolder = (ViewHolder) holder; // ------------- code ----- } else if (holder.getItemViewType() == VIEW_TYPE_QUOTES) { final Quotes quotes = (Quotes) holder; quotes.relativeLayout.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, columnWidth / 2)); Typeface typeface = Typeface.createFromAsset(activity.getAssets(), "text_font/" + subCategoryLists.get(position).getQuote_font()); quotes.textView.setTypeface(typeface); quotes.textView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { quotes.textView.getViewTreeObserver().removeOnGlobalLayoutListener(this); int noOfLinesVisible = quotes.textView.getHeight() / quotes.textView.getLineHeight(); quotes.textView.setMaxLines(noOfLinesVisible); quotes.textView.setEllipsize(TextUtils.TruncateAt.END); quotes.textView.setText(subCategoryLists.get(position).getStatus_title()); } }); } } @Override public int getItemCount() { return subCategoryLists.size() + 1; } @Override public int getItemViewType(int position) { if (position != subCategoryLists.size()) { if (subCategoryLists.get(position).getStatus_type().equals("quote")) { return VIEW_TYPE_QUOTES; } else { return VIEW_TYPE_ITEM; } } else { return VIEW_TYPE_LOADING; } } public class Quotes extends RecyclerView.ViewHolder { private RelativeLayout relativeLayout; private MaterialTextView textView; public Quotes(@NonNull View itemView) { super(itemView); textView = itemView.findViewById(R.id.textView_quotes_adapter); relativeLayout = itemView.findViewById(R.id.rel_quotes_adapter); } } } </code></pre> <br /><h3>回答1:</h3><br /><p>I am not completely sure about the problem that you are having there. However, I think I found some problems in your code. </p> <p>The first problem that I see in setting up your <code>RecyclerView</code> is setting the layout size fixed by the following. </p> <pre><code>recyclerView.setHasFixedSize(true); </code></pre> <p>Looks like you are changing the item layout size dynamically. Hence you need to remove the line above while setting up your <code>RecyclerView</code>. </p> <p>The second problem that I see is, there is no <code>textView_category</code> in the <code>ViewHolder</code> for <code>Quote</code>. Hence the following should throw an error. </p> <pre><code>quotes.textView_category.setText(subCategoryLists.get(position).getCategory_name()); </code></pre> <br /><br /><br /><h3>回答2:</h3><br /><p>One problem I can see is that you are calling</p> <pre><code>quotes.textView.getViewTreeObserver().removeOnGlobalLayoutListener(this); </code></pre> <p>in the first line of your listener callback no matter what. In a RecyclerView the first few times this is called the layout might still be unmeasured but you're cancelling the listener callback after the first callback. So this line fires, and if the view is still unmeasured then the next few lines are going to fail and your code will get no more opportunities to fill the view. Try checking the measuredWidth or measuredHeight of your view for something greater than 0 before cancelling future listener callbacks.</p> <br /><br /><br /><h3>回答3:</h3><br /><p><strong>I have using this. works perfectly</strong></p> <pre><code>textView.setText(subCategoryLists.get(position).getStatus_title()); textView.post(new Runnable() { @Override public void run() { ViewGroup.LayoutParams params = textView.getLayoutParams(); if (params == null) { params = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); } final int widthSpec = View.MeasureSpec.makeMeasureSpec(textView.getWidth(), View.MeasureSpec.UNSPECIFIED); final int heightSpec = View.MeasureSpec.makeMeasureSpec(textView.getHeight(), View.MeasureSpec.UNSPECIFIED); textView.measure(widthSpec, heightSpec); textView.setMaxLines(heightSpec / textView.getLineHeight()); textView.setEllipsize(TextUtils.TruncateAt.END); } }); </code></pre> <br /><br /><p>来源:<code>https://stackoverflow.com/questions/60790803/using-viewtreeobserver-i-am-adding-setmaxlines-and-setellipsize-in-materialtextv</code></p></div> <div class="field field--name-field-tags field--type-entity-reference field--label-above"> <div class="field--label">标签</div> <div class="field--items"> <div class="field--item"><a href="/tag/java" hreflang="zh-hans">java</a></div> <div class="field--item"><a href="/tag/android" hreflang="zh-hans">android</a></div> <div class="field--item"><a href="/tag/android-recyclerview" hreflang="zh-hans">android-recyclerview</a></div> <div class="field--item"><a href="/tag/recycler-adapter" hreflang="zh-hans">recycler-adapter</a></div> <div class="field--item"><a href="/tag/android-viewtreeobserver" hreflang="zh-hans">android-viewtreeobserver</a></div> </div> </div> Wed, 20 May 2020 23:23:02 +0000 瘦欲@ 3649919 at https://www.e-learn.cn Can't get FirestoreRecyclerAdapter to show items https://www.e-learn.cn/topic/3645649 <span>Can&#039;t get FirestoreRecyclerAdapter to show items</span> <span><span lang="" about="/user/175" typeof="schema:Person" property="schema:name" datatype="">一笑奈何</span></span> <span>2020-05-15 08:27:05</span> <div class="field field--name-body field--type-text-with-summary field--label-hidden field--item"><h3>问题</h3><br /><p>I'm updating my app to use Firebase's Firestore database. I'm struggling to get the app to show the data that's been retrieved from the database. The data is retrieved ok, but doesn't show up. By setting breakpoints, I've established that the ViewHolder isn't being bound to the adapter at any point.</p> <p>The data is being shown in a Fragment. The Fragment layout is (I've taken out irrelevant stuff like padding, sizes etc):</p> <pre><code>&lt;android.support.constraint.ConstraintLayout android:id="@+id/layout_charts_list" tools:context="apppath.fragments.ChartListFragment"&gt; &lt;TextView android:id="@+id/loading_list" android:text="@string/loading_my_charts" /&gt; &lt;TextView android:id="@+id/empty_list" android:text="@string/my_charts_empty" android:visibility="gone"/&gt; &lt;android.support.v7.widget.RecyclerView android:id="@+id/charts_list" /&gt; &lt;/android.support.constraint.ConstraintLayout&gt; </code></pre> <p>The Fragment code itself is:</p> <pre><code>public abstract class ChartListFragment extends Fragment { private FirebaseFirestore mDatabaseRef; private FirestoreRecyclerAdapter&lt;Chart, ChartViewHolder&gt; mAdapter; private Query mChartsQuery; private RecyclerView mRecycler; public ChartListFragment() {} @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { super.onCreateView(inflater, container, savedInstanceState); View rootView = inflater.inflate( R.layout.fragment_charts_list, container, false); mRecycler = rootView.findViewById(R.id.charts_list); mRecycler.setHasFixedSize(true); // Set up Layout Manager, and set Recycler View to use it LinearLayoutManager mManager = new LinearLayoutManager(getActivity()); mManager.setReverseLayout(true); mManager.setStackFromEnd(true); mRecycler.setLayoutManager(mManager); // Connect to the database, and get the appropriate query (as set in the actual fragment) mDatabaseRef = FirebaseFirestore.getInstance(); mChartsQuery = getQuery(mDatabaseRef); // Set up Recycler Adapter FirestoreRecyclerOptions&lt;Chart&gt; recyclerOptions = new FirestoreRecyclerOptions.Builder&lt;Chart&gt;() .setQuery(mChartsQuery, Chart.class) .build(); mAdapter = new ChartListAdapter(recyclerOptions); // Use Recycler Adapter in RecyclerView mRecycler.setAdapter(mAdapter); return rootView; } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); // Add listener to charts collection, and deal with any changes by re-showing the list mChartsQuery.addSnapshotListener(new EventListener&lt;QuerySnapshot&gt;() { @Override public void onEvent(@Nullable QuerySnapshot queryDocumentSnapshots, @Nullable FirebaseFirestoreException e) { if (queryDocumentSnapshots != null &amp;&amp; queryDocumentSnapshots.isEmpty()) { ((MainActivity) getActivity()).setPage(1); mRecycler.setVisibility(View.GONE); }else { mRecycler.setVisibility(View.VISIBLE); } } }); } // HELPER FUNCTIONS public abstract Query getQuery(FirebaseFirestore databaseReference); } </code></pre> <p>ChartListAdapter is as follows:</p> <pre><code>public class ChartListAdapter extends FirestoreRecyclerAdapter&lt;Chart, ChartViewHolder&gt; { public ChartListAdapter(FirestoreRecyclerOptions recyclerOptions) { super(recyclerOptions); } @Override protected void onBindViewHolder(ChartViewHolder holder, int position, Chart model) { holder.setChartName(model.getName()); // Bind Chart to ViewHolder holder.bindToChart(model); } @Override public ChartViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()) .inflate(R.layout.item_chart, parent, false); return new ChartViewHolder(view); } } </code></pre> <p>ChartViewHolder:</p> <pre><code>public class ChartViewHolder extends RecyclerView.ViewHolder { private TextView chartNameView; private String chartKey; public ChartViewHolder(View itemView) { super(itemView); chartNameView = itemView.findViewById(R.id.chart_name); } public void setChartName(String chartName) { chartNameView.setText(chartName); } public void bindToChart(Chart chart) { chartKey = chart.getKey(); chartNameView.setText(chart.getName()); } public String getChartKey() { return chartKey; } } </code></pre> <p>The ChartListAdapter constructor is called, but onBindViewHolder and onCreateViewHolder are never called, and ChartViewHolder is never accessed at all. Am I missing a line of code? Or doing this completely wrong? I'm not all that familiar with Adapters and RecyclerViews, so I've found it quite hard to get to grips with putting it all together.</p> <br /><h3>回答1:</h3><br /><p>You need to add the following, to begin listening for data, call the <code>startListening()</code> method. You may want to call this in your <code>onStart()</code> method. Make sure you have finished any authentication necessary to read the data before calling <code>startListening()</code> or your query will fail:</p> <pre><code>@Override protected void onStart() { super.onStart(); adapter.startListening(); } </code></pre> <p>more info here:</p> <p>https://github.com/firebase/FirebaseUI-Android/tree/master/firestore</p> <br /><br /><br /><h3>回答2:</h3><br /><p>For those who came here from Google, set the lifecycle owner on the options so that start/stop listening is called automatically.</p> <pre><code>FirestoreRecyclerOptions&lt;Chart&gt; recyclerOptions = FirestoreRecyclerOptions.Builder&lt;Chart&gt;() .setQuery(mChartsQuery, Chart.class) .setLifecycleOwner(this) .build(); </code></pre> <br /><br /><p>来源:<code>https://stackoverflow.com/questions/50119627/cant-get-firestorerecycleradapter-to-show-items</code></p></div> <div class="field field--name-field-tags field--type-entity-reference field--label-above"> <div class="field--label">标签</div> <div class="field--items"> <div class="field--item"><a href="/tag/android" hreflang="zh-hans">android</a></div> <div class="field--item"><a href="/tag/firebase" hreflang="zh-hans">firebase</a></div> <div class="field--item"><a href="/tag/google-cloud-firestore" hreflang="zh-hans">google-cloud-firestore</a></div> <div class="field--item"><a href="/tag/recycler-adapter" hreflang="zh-hans">recycler-adapter</a></div> <div class="field--item"><a href="/tag/firebaseui" hreflang="zh-hans">firebaseui</a></div> </div> </div> Fri, 15 May 2020 00:27:05 +0000 一笑奈何 3645649 at https://www.e-learn.cn Recycler View: Inconsistency detected. Invalid view holder adapter positionViewHolder https://www.e-learn.cn/topic/3632776 <span>Recycler View: Inconsistency detected. Invalid view holder adapter positionViewHolder</span> <span><span lang="" about="/user/67" typeof="schema:Person" property="schema:name" datatype="">孤人</span></span> <span>2020-05-09 17:52:10</span> <div class="field field--name-body field--type-text-with-summary field--label-hidden field--item"><h3>问题</h3><br /><p>Recycler View Inconsistency Detected error, coming while scrolling fast or scrolling while loading more items..</p> <pre><code>FATAL EXCEPTION: main Process: com.pratap.endlessrecyclerview, PID: 21997 java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid view holder adapter positionViewHolder{56a082c position=40 id=-1, oldPos=39, pLpos:39 scrap [attachedScrap] tmpDetached no parent} at android.support.v7.widget.RecyclerView$Recycler.validateViewHolderForOffsetPosition(RecyclerView.java:4251) at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:4382) at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:4363) at android.support.v7.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:1961) at android.support.v7.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1370) at android.support.v7.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1333) at android.support.v7.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:562) at android.support.v7.widget.RecyclerView.dispatchLayout(RecyclerView.java:2864) at android.support.v7.widget.RecyclerView.consumePendingUpdateOperations(RecyclerView.java:1445) at android.support.v7.widget.RecyclerView.access$400(RecyclerView.java:144) at android.support.v7.widget.RecyclerView$1.run(RecyclerView.java:282) at android.view.Choreographer$CallbackRecord.run(Choreographer.java:858) at android.view.Choreographer.doCallbacks(Choreographer.java:670) at android.view.Choreographer.doFrame(Choreographer.java:603) at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:844) at android.os.Handler.handleCallback(Handler.java:746) at android.os.Handler.dispatchMessage(Handler.java:95) at android.os.Looper.loop(Looper.java:148) at android.app.ActivityThread.main(ActivityThread.java:5443) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:728) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:618) </code></pre> <p><strong>Adapter</strong></p> <pre><code>public class DataAdapter extends RecyclerView.Adapter { private final int VIEW_ITEM = 1; private final int VIEW_PROG = 0; private List&lt;Feed&gt; mFeed; // The minimum amount of items to have below your current scroll position // before loading more. private int visibleThreshold = 5; private int lastVisibleItem, totalItemCount; private boolean loading; private OnLoadMoreListener onLoadMoreListener; public DataAdapter(List&lt;Feed&gt; feeds, RecyclerView recyclerView) { mFeed = feeds; if (recyclerView.getLayoutManager() instanceof LinearLayoutManager) { final LinearLayoutManager linearLayoutManager = (LinearLayoutManager) recyclerView .getLayoutManager(); recyclerView .addOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); totalItemCount = linearLayoutManager.getItemCount(); lastVisibleItem = linearLayoutManager .findLastVisibleItemPosition(); if (!loading &amp;&amp; totalItemCount &lt;= (lastVisibleItem + visibleThreshold)) { // End has been reached // Do something if (onLoadMoreListener != null) { onLoadMoreListener.onLoadMore(); } loading = true; } } }); } } @Override public int getItemViewType(int position) { return mFeed.get(position) == null ? VIEW_PROG : VIEW_ITEM; } @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { RecyclerView.ViewHolder vh; if (viewType == VIEW_ITEM) { View v = LayoutInflater.from(parent.getContext()).inflate( R.layout.list_row, parent, false); vh = new StudentViewHolder(v); } else { View v = LayoutInflater.from(parent.getContext()).inflate( R.layout.progress_item, parent, false); vh = new ProgressViewHolder(v); } return vh; } @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { if (holder instanceof StudentViewHolder) { Feed singleStudent= (Feed) mFeed.get(position); ((StudentViewHolder) holder).tvName.setText(singleStudent.getTitle()); ((StudentViewHolder) holder).student= singleStudent; } else { ProgressViewHolder.PROGRESS_BAR.setIndeterminate(true); } } public void setLoaded() { loading = false; } public void addFeed(Feed feed) { mFeed.add(feed); //mFeed.addAll(0, (Collection&lt;? extends Feed&gt;) feed); notifyItemInserted(mFeed.size()); //notifyItemRangeInserted(0,mFeed.size()); notifyDataSetChanged(); //notifyItemInserted(mFeed.size()); //setLoaded(); //notifyItemInserted(mFeed.size()); } public void removeAll(){ mFeed.clear(); notifyDataSetChanged(); } @Override public int getItemCount() { return mFeed.size(); } public void setOnLoadMoreListener(OnLoadMoreListener onLoadMoreListener) { this.onLoadMoreListener = onLoadMoreListener; } public static class StudentViewHolder extends RecyclerView.ViewHolder { public TextView tvName; public Feed student; public StudentViewHolder(View v) { super(v); tvName = (TextView) v.findViewById(R.id.tvName); //tvEmailId = (TextView) v.findViewById(R.id.tvEmailId); } } public static class ProgressViewHolder extends RecyclerView.ViewHolder { //public ProgressBar progressBar; public static ProgressBar PROGRESS_BAR; public ProgressViewHolder(View v) { super(v); PROGRESS_BAR = (ProgressBar) v.findViewById(R.id.progressBar1); // progressBar = (ProgressBar) v.findViewById(R.id.progressBar1); } } } </code></pre> <p><strong>Activity</strong></p> <pre><code>public class MainActivity extends AppCompatActivity implements SwipeRefreshLayout.OnRefreshListener { private Toolbar toolbar; private TextView tvEmptyView; private RecyclerView mRecyclerView; private DataAdapter mAdapter; private LinearLayoutManager mLayoutManager; private RestManager mManager; private List&lt;Feed&gt; mFeed; SwipeRefreshLayout mSwipeRefreshLayout; protected Handler handler; private int currentPage=1; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); toolbar = (Toolbar) findViewById(R.id.toolbar); tvEmptyView = (TextView) findViewById(R.id.empty_view); mRecyclerView = (RecyclerView) findViewById(R.id.my_recycler_view); mSwipeRefreshLayout= (SwipeRefreshLayout) findViewById(R.id.swipe_refresh_layout); mSwipeRefreshLayout.setOnRefreshListener(this); //studentList = new ArrayList&lt;Student&gt;(); mFeed = new ArrayList&lt;Feed&gt;(); handler = new Handler(); if (toolbar != null) { setSupportActionBar(toolbar); getSupportActionBar().setTitle("Android Students"); } mManager = new RestManager(); // use this setting to improve performance if you know that changes // in content do not change the layout size of the RecyclerView mRecyclerView.setHasFixedSize(true); mLayoutManager = new LinearLayoutManager(this); // use a linear layout manager mRecyclerView.setLayoutManager(mLayoutManager); // create an Object for Adapter mAdapter = new DataAdapter(mFeed,mRecyclerView); // set the adapter object to the Recyclerview mRecyclerView.setAdapter(mAdapter); // mAdapter.notifyDataSetChanged(); loadData(false); // if (mFeed.isEmpty()) { // mRecyclerView.setVisibility(View.GONE); // tvEmptyView.setVisibility(View.VISIBLE); // // } else { // mRecyclerView.setVisibility(View.VISIBLE); // tvEmptyView.setVisibility(View.GONE); // } mAdapter.setOnLoadMoreListener(new OnLoadMoreListener() { @Override public void onLoadMore() { //add null , so the adapter will check view_type and show progress bar at bottom mFeed.add(null); mAdapter.notifyItemInserted(mFeed.size() - 1); handler.postDelayed(new Runnable() { @Override public void run() { // remove progress item mFeed.remove(mFeed.size() - 1); // mAdapter.notifyItemRemoved(mFeed.size()); //add items one by one int start = mFeed.size(); currentPage++; Log.d("CurrentPage", String.valueOf(currentPage)); Call&lt;Results&gt; listCall = mManager.getFeedApi().getAllFeeds(1); listCall.enqueue(new Callback&lt;Results&gt;() { @Override public void onResponse(Call&lt;Results&gt; call, Response&lt;Results&gt; response) { mSwipeRefreshLayout.setRefreshing(false); if (response.isSuccess()) { if (response.body() != null) { Results feedList = response.body(); // List&lt;Results&gt; newUsers = response.body(); Log.d("Retrofut", String.valueOf(feedList)); for (int i = 0; i &lt; feedList.results.size(); i++) { Feed feed = feedList.results.get(i); // mFeed.add(feed); mAdapter.addFeed(feed); // mAdapter.notifyDataSetChanged(); //mAdapter.notifyItemInserted(mFeed.size()); } // mAdapter.notifyDataSetChanged(); } } } @Override public void onFailure(Call&lt;Results&gt; call, Throwable t) { Log.d("Retrofut", "Error"); mFeed.remove(mFeed.size() - 1); mAdapter.notifyItemRemoved(mFeed.size()); mAdapter.setLoaded(); mSwipeRefreshLayout.setRefreshing(false); } }); // for (int i = 1; i &lt;= 20; i++) { // studentList.add(new Student("Student " + i, "androidstudent" + i + "@gmail.com")); // // } mAdapter.setLoaded(); //or you can add all at once but do not forget to call mAdapter.notifyDataSetChanged(); } }, 2000); } }); } // load initial data private void loadData(final boolean removePreData) { Call&lt;Results&gt; listCall = mManager.getFeedApi().getAllFeeds(1); listCall.enqueue(new Callback&lt;Results&gt;() { @Override public void onResponse(Call&lt;Results&gt; call, Response&lt;Results&gt; response) { if (response.isSuccess()) { if (response.body() != null) { // if(removePreData) mAdapter.removeAll(); Results feedList = response.body(); Log.d("Retrofut", String.valueOf(feedList)); for (int i = 0; i &lt; feedList.results.size(); i++) { Feed feed = feedList.results.get(i); // mFeed.add(feed); //mAdapter.notifyDataSetChanged(); mAdapter.addFeed(feed); } mSwipeRefreshLayout.setRefreshing(false); } } } @Override public void onFailure(Call&lt;Results&gt; call, Throwable t) { Log.d("Retrofut", String.valueOf(t)); mFeed.remove(mFeed.size() - 1); mAdapter.notifyItemRemoved(mFeed.size()); mAdapter.setLoaded(); mSwipeRefreshLayout.setRefreshing(false); } } ); // for (int i = 1; i &lt;= 20; i++) { // studentList.add(new Student("Student " + i, "androidstudent" + i + "@gmail.com")); // // } mSwipeRefreshLayout.setRefreshing(true); } @Override public void onRefresh() { mFeed.clear(); mAdapter.notifyDataSetChanged(); loadData(true); currentPage=1; } } </code></pre> <br /><h3>回答1:</h3><br /><p>It looks similar with known android bug</p> <p>There are quite ugly, but working approach</p> <pre><code>public class WrapContentLinearLayoutManager extends LinearLayoutManager { //... constructor @Override public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { try { super.onLayoutChildren(recycler, state); } catch (IndexOutOfBoundsException e) { Log.e("Error", "IndexOutOfBoundsException in RecyclerView happens"); } } } mRecyclerView.setLayoutManager(new WrapContentGridLayoutManager(getContext(), spanCount)); </code></pre> <p>For me it works without any by-effect.</p> <br /><br /><br /><h3>回答2:</h3><br /><p>This issue is a known bug of RecyclerView. The best solution is, clear the list every time before refresh RecyclerView.</p> <p>For fix this issue just call notifyDataSetChanged() with empty list before updating recycle view.</p> <p>For example</p> <pre><code>//Method for refresh recycle view if (!yourList.isEmpty()) yourList.clear(); //The list for update recycle view adapter.notifyDataSetChanged(); </code></pre> <br /><br /><br /><h3>回答3:</h3><br /><p>Use this to refresh a RecyclerView</p> <pre><code>items.clear(); //here items is an ArrayList populating the RecyclerView adapter.notifyDataSetChanged(); items.addAll(list);// add new data adapter.notifyItemRangeInserted(0, items.size);// notify adapter of new data </code></pre> <p>`</p> <br /><br /><br /><h3>回答4:</h3><br /><p>I had similiar issue, and also this solution has helped me, after I've added new item to my RV:</p> <pre><code>recyclerView.getRecycledViewPool().clear(); adapter.notifyDataSetChanged(); </code></pre> <br /><br /><br /><h3>回答5:</h3><br /><blockquote> <p>put this line along with setting recyclerView. issue was fixed by setting ItemAnimator to null for RecyclerView.</p> </blockquote> <pre><code>in kotlin recyclerView.layoutManager = LinearLayoutManager(this) recyclerView.itemAnimator = null </code></pre> <p>in java</p> <pre><code>recyclerView.setItemAnimator(null); </code></pre> <br /><br /><br /><h3>回答6:</h3><br /><p>Maybe you can try this before refresh the adapter:</p> <pre><code>dataList.clear(); patrolListAdapter.notifyDataSetChanged(); </code></pre> <br /><br /><br /><h3>回答7:</h3><br /><p>In my case I was doing it as <code>notifyItemInserted(position);</code> That caused me this issue then i used as and it worked perfectly.<code>notifyItemRangeInserted(startIndex,endIndex);</code></p> <br /><br /><br /><h3>回答8:</h3><br /><p>I had this problem when scrolling fast through my endless/paging <code>RecyclerView</code>. The root of my problem came from the fact that I had a “header” item at the beginning of the list, this header item was not a part of the data source, it was just inserted at the beginning of the <code>adapter</code> list. So when scrolling fast and adding new pages of items to the <code>RecyclerView</code> <code>Adapter</code> and notify the <code>adapter</code> that new data had been inserted, I was not taking into account the additional header item, thus making the size of the adapter’s list wrong... and causing this exception...</p> <p>So in short, if you’re using a header/footer in our <code>RecyclerView</code> adapter make sure you take it into account when updating the adapters data.</p> <p><strong>Example:</strong></p> <pre><code>public void addNewPageToList(List&lt;MyData&gt; list) { // // Make sure you account for any header/footer in your list! // // Add one to the currentSize to account for the header item. // int currentSize = this.adapterList.size() + 1; this.adapterList.addAll(list); notifyItemRangeInserted(currentSize, this.adapterList.size()); } </code></pre> <p><strong>Edit:</strong> I guess you could always just use the adapter method <code>getItemCount()</code> to get the size, instead of getting the size from the “data list” and adding to it. Your <code>getItemCount()</code> method should already be taking into account any additional headers/footers/etc that you have in your list.</p> <br /><br /><br /><h3>回答9:</h3><br /><p>I had similar problem. Removing all views from RecyclerView helped me:</p> <pre><code>RecyclerView.LayoutManager layoutManager = mRecyclerView.getLayoutManager(); layoutManager.removeAllViews(); </code></pre> <br /><br /><br /><h3>回答10:</h3><br /><p>For me the issue was I wasn't posting notifyDatasetChanged when the data set changed as I implemented incremental search.</p> <p>I had a list that was filtered based on what the user searched in the search widget. For each item in the list, I was making a remote request, and when I got the result back, I was updating that particular cell.</p> <p>I had to do both notifies for the recycler view to work</p> <p>Filter the original data set then post the dataset change</p> <pre><code>this.searchResultTable?.post { this.searchResultTable?.adapter?.notifyDataSetChanged() } </code></pre> <p>After receiving response, post notifications again</p> <pre><code>this.searchResultTable?.post { this.searchResultTable?.adapter?.notifyItemChanged(index, updateDataHashMap) } </code></pre> <p>You have to post updates rather than sending notifiy messages directly in order to prevent the recycler view from crashing when the update comes in before the view is laid out.</p> <p>Another important gotcha is that when you post the individual updates after the remote response, you have to make sure that the list the user currently sees is the list that existed when the requests were sent.</p> <br /><br /><br /><h3>回答11:</h3><br /><p>The problem is in this line of code:</p> <pre><code> mFeed = feeds; </code></pre> <p>you are assigning <code>mFeed</code> to the caller's instance <code>feeds</code> so whenever the caller changes it's variable (may be adding, clearing or removing items), your local <code>mFeed</code> will change</p> <p>try to change to </p> <pre><code>mFeed.addAll(feeds); </code></pre> <p>don't forget to initialize <code>mFeed</code> to any list tat fits your needs like <code>mFeed = new ArrayList&lt;&gt;();</code></p> <br /><br /><p>来源:<code>https://stackoverflow.com/questions/35653439/recycler-view-inconsistency-detected-invalid-view-holder-adapter-positionviewh</code></p></div> <div class="field field--name-field-tags field--type-entity-reference field--label-above"> <div class="field--label">标签</div> <div class="field--items"> <div class="field--item"><a href="/tag/android-recyclerview" hreflang="zh-hans">android-recyclerview</a></div> <div class="field--item"><a href="/tag/recycler-adapter" hreflang="zh-hans">recycler-adapter</a></div> </div> </div> Sat, 09 May 2020 09:52:10 +0000 孤人 3632776 at https://www.e-learn.cn RecyclerView with different types and different adapter https://www.e-learn.cn/topic/3603632 <span>RecyclerView with different types and different adapter</span> <span><span lang="" about="/user/228" typeof="schema:Person" property="schema:name" datatype="">故事扮演</span></span> <span>2020-04-30 11:11:27</span> <div class="field field--name-body field--type-text-with-summary field--label-hidden field--item"><h3>问题</h3><br /><p>and thank you for your attention to my request. I'm a newbie on Andorid Studio and I'm developing an App, it has to show a list of Events, Courses and News. There is a DrawerLayout which allow navigating into Event's, course's and news's area, each area has each specific RecyclerView, but into the home activity, I have to show all the items (Event, Course and News). I create an Adapter for each item (because they have different properties) and each section (fragment) works properly but now I'm stuck with the main activity (the home).</p> <p>Here are the models for explaining the difference between them: Event</p> <pre><code>public class Event { private int id; private String title; private String description; private LocalDateTime startingDate; private LocalDateTime endingDate; private String cost; private String website; private Category category; private Venue venue; private Organizer organizer; private String status; private int resImage; public Event(int id, String title, String description, LocalDateTime startingDate, LocalDateTime endingDate, String cost, String website, Category category, Venue venue, Organizer organizer, int image) { this.id = id; this.title = title; this.description = description; this.startingDate = startingDate; this.endingDate = endingDate; this.cost = cost; this.website = website; this.category = category; this.venue = venue; this.organizer = organizer; this.resImage = image; } public Event(){} public int getId() { return id; } public String getTitle() { return title; } public void setTitle(String name) { this.title = title; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } public LocalDateTime getStartingDate() { return startingDate; } public void setStartingDate(LocalDateTime startingDate) { this.startingDate = startingDate; } public LocalDateTime getEndingDate() { return endingDate; } public void setEndingDate(LocalDateTime endingDate) { this.endingDate = endingDate; } public String getCost() { return cost; } public void setCost(String cost) { this.cost = cost; } public String getWebsite() { return website; } public void setWebsite(String website) { this.website = website; } public Category getCategory() { return category; } public Venue getVenue() { return venue; } public Organizer getOrganizer() { return organizer; } public String getStatus() { return status; } public int getResImage() { return resImage; } } </code></pre> <p>News:</p> <pre><code>public class News { private int id; private String title; private String content; private int resImage; public News(int id, String title, String content, int image) { this.id = id; this.title = title; this.content = content; this.resImage = image; } public News(){} public int getId(){ return this.id; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getContent() { return content; } public void setDescription(String description) { this.content = content; } public int getResImage() { return resImage; } public void setResImage(int resImage) { this.resImage = resImage; } } </code></pre> <p>Courses</p> <pre><code>public Course(int id, String title, String content, float price, LocalDate startingDate, int availablePlace, Teacher teacher, CourseCategory courseCategory, Location location, Duration duration, Level level, int resImage) { this.id = id; this.title = title; this.content = content; this.price = price; this.startingDate = startingDate; this.availablePlace = availablePlace; this.teacher = teacher; this.courseCategory = courseCategory; this.location = location; this.duration = duration; this.level = level; this.resImage = resImage; } public int getId() { return id; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getContent() { return content; } public void setContent(String content) { this.content = content; } public float getPrice() { return price; } public void setPrice(float price) { this.price = price; } public LocalDate getStartingDate() { return startingDate; } public void setStartingDate(LocalDate startingDate) { this.startingDate = startingDate; } public int getAvailablePlace() { return availablePlace; } public void setAvailablePlace(int availablePlace) { this.availablePlace = availablePlace; } public Teacher getTeacher() { return teacher; } public void setTeacher(Teacher teacher) { this.teacher = teacher; } public CourseCategory getCourseCategory() { return courseCategory; } public void setCourseCategory(CourseCategory courseCategory) { this.courseCategory = courseCategory; } public Location getLocation() { return location; } public void setLocation(Location location) { this.location = location; } public Duration getDuration() { return duration; } public void setDuration(Duration duration) { this.duration = duration; } public Level getLevel() { return level; } public int getResImage() { return resImage; } public void setResImage(int resImage) { this.resImage = resImage; } } </code></pre> <p>Here is the Adapters: EventAdapter</p> <pre><code>public class EventViewAdapter extends RecyclerView.Adapter&lt;EventViewAdapter.EventViewHolder&gt; { ArrayList&lt;Event&gt; eventList; Context context; public EventViewAdapter(ArrayList&lt;Event&gt; eventList, Context context) { this.eventList = eventList; this.context = context; } public EventViewAdapter() { } public static class EventViewHolder extends RecyclerView.ViewHolder { ImageView eventImage; TextView startingDate, place, title; LinearLayout cellLayout; EventViewHolder(View eventView) { super(eventView); eventImage = eventView.findViewById(R.id.event_image); startingDate = eventView.findViewById(R.id.event_starting_date); place = eventView.findViewById(R.id.event_place); title = eventView.findViewById(R.id.event_title); cellLayout = eventView.findViewById(R.id.event_cell_layout); } } @NonNull @Override public EventViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.event_cell_def, parent, false); EventViewHolder evh = new EventViewHolder(view); return evh; } @Override public void onBindViewHolder(@NonNull EventViewHolder holder, int position) { final String title = eventList.get(position).getTitle(); final String description = eventList.get(position).getDescription(); final String place = eventList.get(position).getVenue().getCity(); final String address = eventList.get(position).getVenue().getAddress(); final String startDate = String.valueOf(eventList.get(position).getStartingDate().toLocalDate()); final String startTime = String.valueOf(eventList.get(position).getStartingDate().getHour() + ":" + String.valueOf(eventList.get(position).getStartingDate().getMinute())); final String endDate = String.valueOf(eventList.get(position).getEndingDate().toLocalDate()); final String cost = eventList.get(position).getCost(); final String website = eventList.get(position).getWebsite(); final String category = eventList.get(position).getCategory().getName(); final String organizer = eventList.get(position).getOrganizer().getOrganizer(); final String organizerWebsite = eventList.get(position).getOrganizer().getWebsite(); final int image = eventList.get(position).getResImage(); holder.eventImage.setImageResource(image); holder.startingDate.setText(startDate); holder.place.setText(place); holder.title.setText(title); holder.cellLayout.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent intent = new Intent(v.getContext(), DetailEventActivity.class); intent.putExtra("title", title); intent.putExtra("description", description); intent.putExtra("place", place); intent.putExtra("address", address); intent.putExtra("startDate", startDate); intent.putExtra("startTime", startTime); intent.putExtra("endDate", endDate); intent.putExtra("cost", cost); intent.putExtra("website", website); intent.putExtra("category", category); intent.putExtra("organizer", organizer); intent.putExtra("orgWebsite", organizerWebsite); intent.putExtra("image", image); v.getContext().startActivity(intent); Toast.makeText(context, "Hai premuto su: " + title, Toast.LENGTH_SHORT).show(); } }); } @Override public int getItemCount() { return eventList.size(); } public void eventSetSearchOperation(ArrayList&lt;Event&gt; newList){ eventList = new ArrayList&lt;&gt;(); eventList.addAll(newList); notifyDataSetChanged(); } } </code></pre> <p>CourseAdapter:</p> <pre><code>public class CourseViewAdapter extends RecyclerView.Adapter&lt;CourseViewAdapter.CourseViewHolder&gt; { ArrayList&lt;Course&gt; courseList; Context context; public CourseViewAdapter(ArrayList&lt;Course&gt; courseList, Context context) { this.courseList = courseList; this.context = context; } public CourseViewAdapter(){} public static class CourseViewHolder extends RecyclerView.ViewHolder { ImageView courseImage; TextView startingDate, place, title; LinearLayout courseLinear; CourseViewHolder(View courseView){ super(courseView); courseImage = courseView.findViewById(R.id.course_image); startingDate = courseView.findViewById(R.id.course_starting_date); place = courseView.findViewById(R.id.course_place); title = courseView.findViewById(R.id.course_title); courseLinear = courseView.findViewById(R.id.course_cell_layout); } } @NonNull @Override public CourseViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.course_cell_def, parent, false); CourseViewHolder cvh = new CourseViewHolder(view); return cvh; } @Override public void onBindViewHolder(@NonNull CourseViewHolder holder, int position) { final String title = courseList.get(position).getTitle(); final String category = courseList.get(position).getCourseCategory().getName(); final String description = courseList.get(position).getContent(); final String place = courseList.get(position).getLocation().getName(); final String startDate = String.valueOf(courseList.get(position).getStartingDate()); final int availablePlace = courseList.get(position).getAvailablePlace(); final String teacher = courseList.get(position).getTeacher().getName(); final String teacherEmail = courseList.get(position).getTeacher().getEmail(); final String teacherMobile = courseList.get(position).getTeacher().getPhone(); final String duration = courseList.get(position).getDuration().getName(); final String level = courseList.get(position).getLevel().getName(); final String price = String.valueOf(courseList.get(position).getPrice()); final int image = courseList.get(position).getResImage(); holder.courseImage.setImageResource(image); holder.startingDate.setText(startDate); holder.place.setText(place); holder.title.setText(title); holder.courseLinear.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent intent = new Intent(v.getContext(), DetailCourseActivity.class); intent.putExtra("title", title); intent.putExtra("category", category); intent.putExtra("content", description); intent.putExtra("startDate", startDate); intent.putExtra("availablePlace", availablePlace); intent.putExtra("teacher", teacher); intent.putExtra("teacherEmail", teacherEmail); intent.putExtra("teacherMobile", teacherMobile); intent.putExtra("duration", duration); intent.putExtra("price", price); intent.putExtra("place", place); intent.putExtra("level", level); intent.putExtra("image", image); v.getContext().startActivity(intent); Toast.makeText(context, "Hai premuto su: " + title, Toast.LENGTH_SHORT).show(); } }); } @Override public int getItemCount() { return courseList.size(); } public void courseSetSearchOperation(ArrayList&lt;Course&gt; newList){ courseList = new ArrayList&lt;&gt;(); courseList.addAll(newList); notifyDataSetChanged(); } } </code></pre> <p>News:</p> <pre><code>public class NewsViewAdapter extends RecyclerView.Adapter&lt;NewsViewAdapter.NewsViewHolder&gt; { ArrayList&lt;News&gt; newsList; Context context; public NewsViewAdapter(ArrayList&lt;News&gt; newsList, Context context) { this.newsList = newsList; this.context = context; } public NewsViewAdapter(){} public static class NewsViewHolder extends RecyclerView.ViewHolder { ImageView newsImage; TextView newsTitle, newsContent; LinearLayout newsLayout; NewsViewHolder(View newView){ super(newView); newsImage = newView.findViewById(R.id.news_image); newsTitle = newView.findViewById(R.id.news_title); newsContent = newView.findViewById(R.id.news_content); newsLayout = newView.findViewById(R.id.news_cell_layout); } } @NonNull @Override public NewsViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.news_cell_def, parent, false); NewsViewHolder nvh = new NewsViewHolder(view); return nvh; } @Override public void onBindViewHolder(@NonNull NewsViewHolder holder, int position) { final String title = newsList.get(position).getTitle(); final String content = newsList.get(position).getContent(); final int image = newsList.get(position).getResImage(); holder.newsImage.setImageResource(image); holder.newsTitle.setText(title); holder.newsContent.setText(content); holder.newsLayout.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent intent = new Intent(v.getContext(), DetailNewsActivity.class); intent.putExtra("title", title); intent.putExtra("content", content); intent.putExtra("image", image); v.getContext().startActivity(intent); Toast.makeText(context, "Premuto su: " + title, Toast.LENGTH_SHORT).show(); } }); } @Override public int getItemCount() { return newsList.size(); } public void newsSetSearchOperation(ArrayList&lt;News&gt; newList){ newsList = new ArrayList&lt;&gt;(); newsList.addAll(newList); notifyDataSetChanged(); } } </code></pre> <p>Each specific list of item is into a fragment, indeed here is the Main Activity (home), where I would like to display a RecyclerView of all the itmes:</p> <pre><code>public class MainActivity extends AppCompatActivity { private DrawerLayout drawerLayout; private NavigationView mNavigationView; private Toolbar toolbar; private ActionBarDrawerToggle drawerToggle; private FloatingActionButton fab; private RecyclerView mRecyclerView; private ImageView openFilter; private SearchView searchView; private DataMock dataMock = new DataMock(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mRecyclerView = findViewById(R.id.recycler_view_main); drawerLayout = findViewById(R.id.drawer_layout); mNavigationView = findViewById(R.id.nav_view); toolbar = findViewById(R.id.toolbar); openFilter = findViewById(R.id.filter_icon); searchView = findViewById(R.id.action_search); fab = findViewById(R.id.fab); fab.show(); setSupportActionBar(toolbar); getSupportActionBar().setDisplayHomeAsUpEnabled(true); searchView.setQueryHint(getString(R.string.search_hint)); drawerToggle = setupDrawerToggle(); drawerToggle.setDrawerIndicatorEnabled(true); drawerToggle.syncState(); drawerLayout.setDrawerListener(drawerToggle); drawerLayout.setDrawerListener(new DrawerLayout.SimpleDrawerListener() { @Override public void onDrawerOpened(View drawerView) { super.onDrawerOpened(drawerView); } @Override public void onDrawerClosed(View drawerView) { super.onDrawerClosed(drawerView); } }); mNavigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() { @Override public boolean onNavigationItemSelected(@NonNull MenuItem menuItem) { Fragment nextFragment; switch (menuItem.getItemId()){ case R.id.event_list: nextFragment = new EventFragment(); break; case R.id.course_list: nextFragment = new CourseFragment(); break; case R.id.news_list: nextFragment = new NewsFragment(); break; default: throw new IllegalArgumentException("No Fragment for the given menu item"); } if (nextFragment != null){ getSupportFragmentManager() .beginTransaction() .replace(R.id.anchor_point, nextFragment) .commit(); menuItem.setChecked(true); setTitle(menuItem.getTitle()); drawerLayout.closeDrawer(mNavigationView); } return false; } }); openFilter.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { BottomSheetDialog filterDialog = new BottomSheetDialog(); filterDialog.show(getSupportFragmentManager(), "filter dialog opened!"); } }); // mRecyclerView.setHasFixedSize(true); // LinearLayoutManager layoutManager = new LinearLayoutManager(this); // mRecyclerView.setLayoutManager(layoutManager); } @Override public boolean onOptionsItemSelected(MenuItem item) { // The action bar home/up action should open or close the drawer. switch (item.getItemId()) { case android.R.id.home: drawerLayout.openDrawer(GravityCompat.START); return true; } return super.onOptionsItemSelected(item); } private ActionBarDrawerToggle setupDrawerToggle() { // NOTE: Make sure you pass in a valid toolbar reference. ActionBarDrawToggle() does not require it // and will not render the hamburger icon without it. return new ActionBarDrawerToggle(this, drawerLayout, toolbar, R.string.drawer_open, R.string.drawer_close); } public void backToHome(View view){ for (Fragment fragment : getSupportFragmentManager().getFragments()){ if (fragment != null &amp;&amp; (fragment instanceof CourseFragment || fragment instanceof EventFragment || fragment instanceof NewsFragment)){ getSupportFragmentManager().beginTransaction().remove(fragment).commit(); toolbar.setTitle("WePress"); fab.show(); } } Toast.makeText(this, "Premuto sul logo", Toast.LENGTH_SHORT).show(); drawerLayout.closeDrawer(mNavigationView); } @Override protected void onPostCreate(Bundle savedInstanceState) { super.onPostCreate(savedInstanceState); // Sync the toggle state after onRestoreInstanceState has occurred. drawerToggle.syncState(); } @Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); // Pass any configuration change to the drawer toggles drawerToggle.onConfigurationChanged(newConfig); } public void addItem(View view){ PopupMenu popupMenu = new PopupMenu(MainActivity.this, fab); popupMenu.getMenuInflater().inflate(R.menu.fab_main_menu, popupMenu.getMenu()); popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() { @Override public boolean onMenuItemClick(MenuItem item) { switch (item.getItemId()){ case R.id.add_event: Toast.makeText(MainActivity.this, "Pronti per aggiungere un evento", Toast.LENGTH_SHORT).show(); Intent intentEvent = new Intent(MainActivity.this, AddItemActivity.class); intentEvent.putExtra("isFrom", "event"); startActivity(intentEvent); break; case R.id.add_course: Toast.makeText(MainActivity.this, "Pronti per aggiungere un corso", Toast.LENGTH_SHORT).show(); Intent intentCourse = new Intent(MainActivity.this, AddItemActivity.class); intentCourse.putExtra("isFrom", "course"); startActivity(intentCourse); break; case R.id.add_news: Toast.makeText(MainActivity.this, "Pronti per aggiungere una news", Toast.LENGTH_SHORT).show(); Intent intentNews = new Intent(MainActivity.this, AddItemActivity.class); intentNews.putExtra("isFrom", "news"); startActivity(intentNews); break; } return true; } }); popupMenu.show(); } } </code></pre> <p>if it's possible to show the list with differents layouts, can you also suggest a way to improve the quality of my code avoiding to repeat lines of code? If I'm not wrong, I would like to re-use each Adapter or part of them that I can put into a specific class (?). Thank you so much for your help! If I'm missing some information, please ask me in order to edit the post. </p> <br /><h3>回答1:</h3><br /><blockquote> <p>You must do only one adapter (using view type) with a view model class that contain either an event or a news or a course</p> <p>the adapter should be something like that:</p> </blockquote> <pre><code>public class EventViewAdapter extends RecyclerView.Adapter&lt;RecyclerView.ViewHolder&gt; { private static final int TYPE_EVENT = 10; private static final int TYPE_COURSE = 11; private static final int TYPE_NEWS = 12; ArrayList&lt;EventViewModel&gt; eventList; Context context; public EventViewAdapter(ArrayList&lt;EventViewModel&gt; eventList, Context context) { this.eventList = eventList; this.context = context; } public EventViewAdapter() { } @Override public int getItemViewType(int position) { EventViewModel event = eventList.get(position); if (event.isEvent()) { return TYPE_EVENT ; } else if(event.isCourse()) { return TYPE_COURSE; } else { return TYPE_NEWS; } } public static class EventViewHolder extends RecyclerView.ViewHolder { ImageView eventImage; //.... EventViewHolder(View eventView) { super(eventView); eventImage = eventView.findViewById(R.id.event_image); //..... } } public static class CourseViewHolder extends RecyclerView.ViewHolder { ImageView courseImage; //..... CourseViewHolder(View courseView) { super(courseView); courseImage = courseView.findViewById(R.id.course_image); //..... } public static class NewsViewHolder extends RecyclerView.ViewHolder { ImageView newsImage; //..... NewsViewHolder(View newView){ super(newView); newsImage = newView.findViewById(R.id.news_image); //..... } @NonNull @Override public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { if (viewType == TYPE_EVENT) { View rootView = LayoutInflater.from(parent.getContext()).inflate(R.layout.event_cell_def, parent, false); return new EventViewHolder (rootView); } else if (viewType == TYPE_COURSE) { View rootView = LayoutInflater.from(parent.getContext()).inflate(R.layout.course_cell_def, parent, false); return new CourseViewHolder(rootView); } else { View rootView = LayoutInflater.from(parent.getContext()).inflate(R.layout.news_cell_def, parent, false); return new NewsViewHolder(rootView); } } @Override public void onBindViewHolder(@NonNull EventViewHolder holder, int position) { final EventViewModel eventViewModel = eventList.get(position); if (eventViewModel .isEvent()) { onBindEvent(holder, eventViewModel.getEvent()); } else if(eventViewModel .isCourse()) { onBindCourse(holder, eventViewModel.getCourse()); } else { onBindNews(holder, eventViewModel.getNews()); } } private void onBindEvent(RecyclerView.ViewHolder holder, Event event) { EventViewHolder eventHolder= (EventViewHolder ) holder; final String title = event.getTitle(); final String description = event.getDescription(); // others ... holder.eventImage.setImageResource(image); holder.startingDate.setText(startDate); // others ... holder.cellLayout.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { } }); // ... } @Override public int getItemCount() { return eventList.size(); } public void eventSetSearchOperation(ArrayList&lt;Event&gt; newList){ eventList = new ArrayList&lt;&gt;(); eventList.addAll(newList); notifyDataSetChanged(); } } </code></pre> <blockquote> <p>And a View Model classes like that :</p> </blockquote> <pre><code>public class EventViewModel() { private Event mEvent; private Course mCourse; private News mNews; private EventViewModel(Event event, Course course, News news) { this.mEvent = event; this.mCourse = course; this.mNews = news; } public boolean isEvent() { return mEvent != null } public boolean isCourse() { return mCourse != null } public boolean isNews() { return mNews != null } public static EventViewModel getEventInstance(Event event) { return new EventViewModel(event, null, null } public static EventViewModel getCourseInstance(Course course) { return new EventViewModel(null, course, null } public static EventViewModel getNewsInstance(News news) { return new EventViewModel(null, null, news } public Event getEvent() { return mEvent; } public Event getCourse() { return mScore; } public Event getNews() { return mNews; } } </code></pre> <blockquote> <p>You can use this adapter in all of your fragments (event, course, news) and each fragment contaions a list of EventViewModel with only its specific type. The adapter display in the main activity contains EventViewModel of all types to display all events.</p> </blockquote> <br /><br /><p>来源:<code>https://stackoverflow.com/questions/58078114/recyclerview-with-different-types-and-different-adapter</code></p></div> <div class="field field--name-field-tags field--type-entity-reference field--label-above"> <div class="field--label">标签</div> <div class="field--items"> <div class="field--item"><a href="/tag/android" hreflang="zh-hans">android</a></div> <div class="field--item"><a href="/tag/android-studio" hreflang="zh-hans">android-studio</a></div> <div class="field--item"><a href="/tag/android-recyclerview" hreflang="zh-hans">android-recyclerview</a></div> <div class="field--item"><a href="/tag/android-adapter" hreflang="zh-hans">android-adapter</a></div> <div class="field--item"><a href="/tag/recycler-adapter" hreflang="zh-hans">recycler-adapter</a></div> </div> </div> Thu, 30 Apr 2020 03:11:27 +0000 故事扮演 3603632 at https://www.e-learn.cn Fragment stucks when, in OnCreateView, a Bitmap (path from SharedPreferences) is set by onBindViewHolder https://www.e-learn.cn/topic/3602466 <span>Fragment stucks when, in OnCreateView, a Bitmap (path from SharedPreferences) is set by onBindViewHolder</span> <span><span lang="" about="/user/154" typeof="schema:Person" property="schema:name" datatype="">主宰稳场</span></span> <span>2020-04-30 06:31:33</span> <div class="field field--name-body field--type-text-with-summary field--label-hidden field--item"><h3>问题</h3><br /><p>I will try to be more specific about my issue. I start saying I've already seen this question that shows the same kind of problem, I guess, but I didn't really understand the right solution.</p> <p><em>Note: I have created the drawer activity and all navigation dependencies from a template in creating new project step</em></p> <p>Initially, I found that when, in ShowProfileFragment, I tried to update the header of the navigation drawer, the same issue happened, so when I put that <code>if</code> statement (see code below) to update it only if necessary, the problem seemed to be vanished (because opening this fragment from drawer doesn't perform this action anymore).</p> <p>Now, when in ItemListFragment I add all my objects, taken from SharedPreferences to the <code>ArrayList</code> passed to an adapter (<code>ItemCardsAdapter</code>) everything works well until in <code>onBindViewHolder</code> of my adapter I perform <code>setImageBitmap</code> on the <code>ImageView</code>. It appears to be wasting time loading bitmaps...</p> <p><em>Note: when I run the app on a real device (my phone) the issue is very highlighted, unlike what happens in the emulator on my pc (here, it was highlighted at the beginning, when issue regarded the profile picture's updating on the drawer's header)</em></p> <p>Here is my code: </p> <p><strong>MainActivity.kt</strong></p> <pre class="lang-kotlin prettyprint-override"><code> import ... class MainActivity : AppCompatActivity() { private lateinit var appBarConfiguration: AppBarConfiguration private var host: NavHostFragment? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) val toolbar: Toolbar = findViewById(R.id.toolbar) setSupportActionBar(toolbar) host = supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment? val drawerLayout: DrawerLayout = findViewById(R.id.drawer_layout) val navView: NavigationView = findViewById(R.id.nav_view) var navController = host?.navController //findNavController(R.id.nav_host_fragment) // Passing each menu ID as a set of Ids because each // menu should be considered as top level destinations. // if (savedInstanceState != null) { // //Restore the fragment's instance // navController = (supportFragmentManager.getFragment(savedInstanceState, "myFragmentEdit")!! as NavHostFragment?)!!.navController // } appBarConfiguration = AppBarConfiguration(setOf(R.id.nav_showprofile, R.id.nav_itemlist), drawerLayout) setupActionBarWithNavController(navController!!, appBarConfiguration) navView.setupWithNavController(navController) /*short info in drawer's header taken from SharedPrefs*/ val sharedPref = getSharedPreferences(getString(R.string.shared_pref_key), Context.MODE_PRIVATE) val parsedData = sharedPref.getString(getString(R.string.profile_json),"missing data") if(parsedData != "missing data") { val json = Json(JsonConfiguration.Stable) val obj = json.parse(User.serializer(),parsedData!!) if(obj.photoPath != "") navView.getHeaderView(0).header_userpic.setImageBitmap(getCircledBitmap(decodeSampledBitmapFromResource(obj.photoPath,256,256))) navView.getHeaderView(0).header_username.text = obj.name navView.getHeaderView(0).header_usermail.text = obj.email } else { //profile pic path as for as other info are taken from resources here navView.getHeaderView(0).header_username.text = getString(R.string.user_name) navView.getHeaderView(0).header_usermail.text = getString(R.string.user_mail) } } // override fun onSaveInstanceState(outState: Bundle) { // super.onSaveInstanceState(outState) // supportFragmentManager.putFragment(outState, "myFragmentEdit", host!!) // } override fun onSupportNavigateUp(): Boolean { val navController = findNavController(R.id.nav_host_fragment) return navController.navigateUp(appBarConfiguration) || super.onSupportNavigateUp() } override fun onBackPressed() { super.onBackPressed() } } </code></pre> <p><strong>ShowProfileFragment.kt</strong></p> <pre class="lang-kotlin prettyprint-override"><code> import ... class ShowProfileFragment : Fragment() { companion object { fun newInstance() = ShowProfileFragment() } private lateinit var viewModel: ShowProfileViewModel @SuppressLint("RestrictedApi") override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { val root = inflater.inflate(R.layout.show_profile_fragment, container, false) viewModel = ViewModelProviders.of(this).get(ShowProfileViewModel::class.java) /*get User info from SharedPrefs*/ val sharedPref = this.activity!!.getSharedPreferences(getString(R.string.shared_pref_key), Context.MODE_PRIVATE) val parsedData = sharedPref.getString(getString(R.string.profile_json),"missing data") if(parsedData != "missing data") { val json = Json(JsonConfiguration.Stable) val obj = json.parse(User.serializer(),parsedData!!) /*update header info after user clicks save*/ val header = activity!!.findViewById(R.id.nav_view) as NavigationView header.getHeaderView(0).header_username.text = obj.name header.getHeaderView(0).header_usermail.text = obj.email if(obj.photoPath != "") { if(arguments?.getString("headerPic") == "update") /*I mean this statement*/ header.getHeaderView(0).header_userpic.setImageBitmap(getCircledBitmap(decodeSampledBitmapFromResource(obj.photoPath,256,256))) root.photo.setImageBitmap(getCircledBitmap(decodeSampledBitmapFromResource(obj.photoPath,256,256))) } viewModel.userKey = obj.userId root.full_name.text = obj.name root.nickname.text = obj.nickname root.email.text = obj.email root.geographic_area.text = obj.country //Log.d("kkk","header info from showProfile: name = ${header.getHeaderView(0).header_username.text}") } val storageDir = activity!!.getExternalFilesDir(Environment.DIRECTORY_PICTURES)!! removeIllegalProfilePic(storageDir,sharedPref) setHasOptionsMenu(true) return root } override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { inflater.inflate(R.menu.edit_profile, menu) } override fun onOptionsItemSelected(item: MenuItem): Boolean { return when(item.itemId){ R.id.editProfileFragment -&gt; { val bundle = bundleOf("userKey" to viewModel.userKey) findNavController().navigate(R.id.action_nav_showprofile_to_editProfileFragment, bundle) true } else -&gt; { super.onOptionsItemSelected(item) } } //return NavigationUI.onNavDestinationSelected(item, view!!.findNavController()) || super.onOptionsItemSelected(item) } @SuppressLint("SimpleDateFormat") private fun removeIllegalProfilePic(root: File, sPrefs: SharedPreferences){ /*check for illegal 0B file, caused of app termination from the camera activity*/ /*and for illegal file generated by any Activity.RESULT_OK caused of app termination from EditProfileActivity*/ val illegalProfilePic = sPrefs.getString(getString(R.string.illegal_profile_pic_key),"saved") for(f in root.listFiles()!!) if (f.length() &lt;= 0 || f.absolutePath == illegalProfilePic) f.delete() } override fun onActivityCreated(savedInstanceState: Bundle?) { super.onActivityCreated(savedInstanceState) viewModel = ViewModelProviders.of(this).get(ShowProfileViewModel::class.java) // TODO: Use the ViewModel } } </code></pre> <p><strong>ItemListFragment.kt</strong></p> <pre class="lang-kotlin prettyprint-override"><code> import ... class ItemListFragment : Fragment() { companion object { fun newInstance() = ItemListFragment() } private lateinit var viewModel: ItemListViewModel //var itemCardsArray= ArrayList&lt;Item&gt;() lateinit var mAdapter : ItemCardsAdapter @SuppressLint("RestrictedApi") override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { viewModel = ViewModelProviders.of(this).get(ItemListViewModel::class.java) val root = inflater.inflate(R.layout.item_list_fragment, container, false) val viewManagerPortrait = LinearLayoutManager(activity) val viewManagerLandscape = GridLayoutManager(activity, 3) /*adapter -&gt; taken from SharedPrefs*/ var itemCardsArray= ArrayList&lt;Item&gt;() //itemCardsArray.add( Item("path","Teddy Bear","Sweet Bear baby peluche","13.49","Toddler Toys","Turin","20/12/2020") ) val sharedPref = this.activity!!.getSharedPreferences(getString(R.string.shared_pref_key), Context.MODE_PRIVATE) val itemCount = sharedPref.getInt(getString(R.string.item_count), 0) if(itemCount == 0) root.listItems.visibility = View.GONE else { root.emptyAds.visibility = View.GONE mAdapter = ItemCardsAdapter(itemCardsArray, this) //viewAdapter.notifyDataSetChanged() root.listItems.apply { setHasFixedSize(true) // use a linear layout manager if portrait, grid one else layoutManager = if(activity!!.resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE) viewManagerLandscape else viewManagerPortrait // specify an viewAdapter (see also next example) adapter = mAdapter //adapter!!.notifyDataSetChanged() } for(i in 1..itemCount) { val parsedData = sharedPref.getString(getString(R.string.item_json)+i.toString(),"missing data") if(parsedData != "missing data") { val json = Json(JsonConfiguration.Stable) val obj = json.parse(Item.serializer(),parsedData!!) itemCardsArray.add(i-1, obj) mAdapter.notifyItemInserted(i-1) } } } root.fab_addItem.setOnClickListener { Snackbar.make(it, "Creating new advertisement...", Snackbar.LENGTH_LONG) .setAction("Action", null).show() findNavController().navigate(R.id.action_nav_itemlist_to_itemEditFragment) } return root } override fun onActivityCreated(savedInstanceState: Bundle?) { super.onActivityCreated(savedInstanceState) viewModel = ViewModelProviders.of(this).get(ItemListViewModel::class.java) // TODO: Use the ViewModel } } </code></pre> <p><strong>ItemCardsAdapter.kt</strong></p> <pre class="lang-kotlin prettyprint-override"><code> import ... class ItemCardsAdapter(private val myDataset: ArrayList&lt;Item&gt;, private val f: Fragment) : RecyclerView.Adapter&lt;ItemCardsAdapter.MyViewHolder&gt;() { class MyViewHolder(viewItem: View) : RecyclerView.ViewHolder(viewItem){ val itemphoto = viewItem.itemphoto val itemtitle = viewItem.title val itemprice = viewItem.itemprice val itemlocation = viewItem.itemlocation val editpencil = viewItem.editCard } // Create new views (invoked by the layout manager) override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder { // create a new view val viewItem = LayoutInflater.from(parent.context).inflate(R.layout.item_card, parent, false) // set the view's size, margins, paddings and layout parameters return MyViewHolder(viewItem) } // Replace the contents of a view (invoked by the layout manager) override fun onBindViewHolder(holder: MyViewHolder, position: Int) { holder.itemtitle.text = myDataset[position].title holder.itemprice.text = myDataset[position].price holder.itemlocation.text = myDataset[position].location if(myDataset[position].photoPath != "") /*Here it stucks on load !?*/ holder.itemphoto.setImageBitmap(decodeSampledBitmapFromResource(myDataset[position].photoPath,256,256)) //holder.View.startAnimation(AnimationUtils.loadLayoutAnimation(this,R.anim.layout_animation)) val bundle = bundleOf("itemAdKey" to myDataset[position].adId) holder.editpencil.setOnClickListener { bundle.putString("nav", "editCard") f.findNavController().navigate(R.id.action_nav_itemlist_to_itemEditFragment, bundle) } holder.itemView.setOnClickListener { f.findNavController().navigate(R.id.action_nav_itemlist_to_nav_itemdetails, bundle) } } // Return the size of your dataset (invoked by the layout manager) override fun getItemCount() = myDataset.size } </code></pre> <br /><h3>回答1:</h3><br /><p>I found the solution, following this official documentation:</p> <p>https://developer.android.com/topic/performance/graphics</p> <p>that recommends to use this external library to solve that kind of memory caching issues: Glide</p> <p> So, I changed, for example, this</p> <p><strong>ItemCardsAdapter.kt</strong></p> <pre><code>holder.itemphoto.setImageBitmap(decodeSampledBitmapFromResource(myDataset[position].photoPath,256,256)) </code></pre> <p>with this</p> <pre><code>Glide.with(f.activity!!).load(myDataset[position].photoPath).into(holder.itemphoto) </code></pre> <br /><br /><p>来源:<code>https://stackoverflow.com/questions/61387288/fragment-stucks-when-in-oncreateview-a-bitmap-path-from-sharedpreferences-is</code></p></div> <div class="field field--name-field-tags field--type-entity-reference field--label-above"> <div class="field--label">标签</div> <div class="field--items"> <div class="field--item"><a href="/tag/android" hreflang="zh-hans">android</a></div> <div class="field--item"><a href="/tag/android-fragments" hreflang="zh-hans">android-fragments</a></div> <div class="field--item"><a href="/tag/kotlin" hreflang="zh-hans">kotlin</a></div> <div class="field--item"><a href="/tag/recycler-adapter" hreflang="zh-hans">recycler-adapter</a></div> <div class="field--item"><a href="/tag/android-bitmap" hreflang="zh-hans">android-bitmap</a></div> </div> </div> Wed, 29 Apr 2020 22:31:33 +0000 主宰稳场 3602466 at https://www.e-learn.cn