First Item of RecyclerView is Missing - android

I have an Activity. I am creating a File which has some data when activity is created. All the files are properly created and data is correctly written.
Following is my code
public class MyRecordingsActivity extends AppCompatActivity {
private RecyclerView recyclerView;
private RecordingsAdapter recordingsAdapter;
private ArrayList<Recording> recordingArrayList;
private File userRecordingFile;
private static final String USER_MIX_DIR = "UserMix";
private String lines[]=new String[]{};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my_recordings);
for(int i=0;i<5;i++){
try{
userRecordingFile = new File(createRecordingFiles(), "Recording"+i+".txt");
FileWriter writer = new FileWriter(userRecordingFile);
writer.append("DEF"+i+"\nHIJ "+i);
writer.flush();
writer.close();
}
catch (Exception e){
e.printStackTrace();
}
}
getSupportActionBar().hide();
recordingArrayList=new ArrayList<>();
recyclerView=findViewById(R.id.recyclerView);
recyclerView.setLayoutManager(new LinearLayoutManager(getApplicationContext()));
recyclerView.setHasFixedSize(true);
readFiles();
Toast.makeText(getApplicationContext(),lines[0],Toast.LENGTH_SHORT).show();
Toast.makeText(getApplicationContext(),lines[1],Toast.LENGTH_SHORT).show();
recordingArrayList.add(new Recording(R.drawable.ic_launcher,lines[0],lines[1]));
recordingArrayList.add(new Recording(R.drawable.ic_launcher,lines[2],lines[3]));
recordingArrayList.add(new Recording(R.drawable.ic_launcher,lines[4],lines[5]));
recordingArrayList.add(new Recording(R.drawable.ic_launcher,lines[6],lines[7]));
recordingArrayList.add(new Recording(R.drawable.ic_launcher,lines[8],lines[9]));
recordingsAdapter=new RecordingsAdapter(recordingArrayList);
recyclerView.setAdapter(recordingsAdapter);
}
public File createRecordingFiles() {
File dirRoot = getExternalCacheDir();
File workDir = new File(dirRoot, USER_MIX_DIR);
//Toast.makeText(getApplicationContext(), "HI", Toast.LENGTH_SHORT).show();
if (!workDir.exists()) {
workDir.mkdirs();
File recordingFile = new File(workDir, "Recording File ");
try {
recordingFile.createNewFile();
} catch (IOException e) {
}
}
return workDir;
}
public void readFiles(){
StringBuilder text = new StringBuilder();
BufferedReader br=null;
try {
File dirRoot = getExternalCacheDir();
File workDir = new File(dirRoot, USER_MIX_DIR);
for(int i=0;i<5;i++){
File file = new File(workDir,"Recording"+i+".txt");
br = new BufferedReader(new FileReader(file));
String line;
while ((line = br.readLine()) != null) {
text.append(line);
text.append('\n');
lines=text.toString().split("\n");
}
}
br.close() ;
}catch (IOException e) {
e.printStackTrace();
}
}
}
The Toast which i have written correcly displays DEF0 and HIJ 0, but they are not displayed in the recyclerview. Following is screenshot of the screen
Following is my Adapter Class
public class RecordingsAdapter extends RecyclerView.Adapter<RecordingsAdapter.RecyclerViewHolder> {
public static final int TYPE_HEAD=0;
public static final int TYPE_LIST=1;
private ArrayList<Recording> recordingArrayList;
public RecordingsAdapter(ArrayList<Recording> recordingArrayList) {
this.recordingArrayList = recordingArrayList;
}
#Override
public RecyclerViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view;
RecyclerViewHolder recyclerViewHolder;
if(viewType == TYPE_LIST){
view= LayoutInflater.from(parent.getContext()).inflate(R.layout.cell_my_recordings,parent,
false);
recyclerViewHolder=new RecyclerViewHolder(view,viewType);
return recyclerViewHolder;
}else if(viewType == TYPE_HEAD){
view= LayoutInflater.from(parent.getContext()).inflate(R.layout.head_layout,parent,
false);
recyclerViewHolder=new RecyclerViewHolder(view,viewType);
return recyclerViewHolder;
}
return null;
}
#Override
public void onBindViewHolder(RecyclerViewHolder holder, int position) {
Recording recording;
if(holder.view_type==TYPE_LIST){
recording=recordingArrayList.get(position);
holder.imageView.setImageResource(recording.getImage_id());
holder.typeTextView.setText(recording.getTitle());
holder.dateTimeTextView.setText(recording.getDatetime());
}else if (holder.view_type == TYPE_HEAD){
holder.typeHeaderTextView.setText("TYPE");
holder.titleHeaderTextView.setText("TITLE");
holder.dateTimeHeaderTextView.setText("DATE/TIME");
}
}
#Override
public int getItemCount() {
return recordingArrayList.size();
}
#Override
public int getItemViewType(int position) {
if(position==0){
return TYPE_HEAD;
}
return TYPE_LIST;
}
public static class RecyclerViewHolder extends RecyclerView.ViewHolder{
int view_type;
ImageView imageView;
TextView typeTextView,dateTimeTextView;
TextView typeHeaderTextView,titleHeaderTextView,dateTimeHeaderTextView;
public RecyclerViewHolder(View itemView, int viewType) {
super(itemView);
if(viewType==TYPE_LIST){
typeTextView=itemView.findViewById(R.id.tv_cell_recording_recording_name);
imageView=itemView.findViewById(R.id.iv_cell_recordings);
dateTimeTextView=itemView.findViewById(R.id.tv_cell_recording_date_time);
view_type=1;
}else if(viewType==TYPE_HEAD){
typeHeaderTextView=itemView.findViewById(R.id.tv_type_head_layout);
titleHeaderTextView=itemView.findViewById(R.id.tv_title_head_layout);
dateTimeHeaderTextView=itemView.findViewById(R.id.tv_date_time_head_layout);
view_type=0;
}
}
}
}
DEf0 and HIJ 0 are not displayed in the recyclerview. I am not able to understand why they are not displaying in my recyclerview. I have no errors in my log. Any help would be greatly appreciated

You are doing it in wrong way....
You are adding five items in recyclerview, but consider first is header.
So this takes your first item as header, and you see other four items.
What you need to do is, pass dummy item as first item and then add your 5 items.
this way you can solve your problem.
You can try this way:
recordingArrayList.add(new Recording(R.drawable.ic_launcher,"", ""));
recordingArrayList.add(new Recording(R.drawable.ic_launcher,lines[0],lines[1]));
recordingArrayList.add(new Recording(R.drawable.ic_launcher,lines[2],lines[3]));
recordingArrayList.add(new Recording(R.drawable.ic_launcher,lines[4],lines[5]));
recordingArrayList.add(new Recording(R.drawable.ic_launcher,lines[6],lines[7]));
recordingArrayList.add(new Recording(R.drawable.ic_launcher,lines[8],lines[9]));
or you can also do it as below:
change Adapter code
#Override
public int getItemCount() {
return recordingArrayList.size() + 1;
}
#Override
public void onBindViewHolder(RecyclerViewHolder holder, int position) {
Recording recording;
if(holder.view_type==TYPE_LIST){
recording=recordingArrayList.get(position - 1);
...
}else if (holder.view_type == TYPE_HEAD){
holder.typeHeaderTextView.setText("TYPE");
holder.titleHeaderTextView.setText("TITLE");
holder.dateTimeHeaderTextView.setText("DATE/TIME");
}
}
but you need to verify for empty list in this way

Your recycler view might be hidden under the toolbar. Give a top margin of 56dp.
android:layout_marginTop="56dp"

Try this your first position is set your Title.
Use this
#Override
public int getItemViewType(int position) {
return TYPE_LIST;
}
Instead of this
#Override
public int getItemViewType(int position) {
if(position==0){
return TYPE_HEAD;
}
return TYPE_LIST;
}

What worked for me is that first I remove from the array any null value (since the first element could be null) and then I add null value again. That way I'm avoiding of duplicating null value. I don't use "if" or any adapter implemented methods so I made my app more efficient.
My code is as follow:
myArray.remove(null); // here I remove any preview added null value as first (0 position) element
myArray.add(0, null); //now I add null as first element
//this way I am avoiding showing content with a null values
I hope this helps someone

The toast is displayed because your card is there, but it's hidden by the toolbar. You can add some margin to the RecyclerView:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="schemas.android.com/apk/res/android"
xmlns:app="schemas.android.com/apk/res-auto"
xmlns:tools="schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:layout_marginTop:"?android:attr/actionBarSize"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/recyclerView" />
</RelativeLayout>

If you wants to add Header without passing first blank data from activity, than you need to add blank entry at first position inside your Adapter like this.
Replace this code inside your Adapter:
public RecordingsAdapter(ArrayList<Recording> recordingArrayList) {
this.recordingArrayList = recordingArrayList;
this.recordingArrayList.add(0,null);
}

Related

Empty Listbox is showing in the Listview

i have created a list view in my android project and its showing an empty list at the beginning of the ListView. All the data is showing accurately from the database. but it creates a null list at the top of the List view. for example if we are taking one record from the database, two records are showing. first record is null as shown in the picture here
I dont know the fault is in the custom adapter or the listview. several days i have searched for an solution and could not find. Please assist me to complete the project. thanks.
below i will past my custom adapter code and the ListView
Custom Adapter
else {
LISTVIEW = (ListView) findViewById(R.id.listView1);
customAdapter = new CustomAdapter();
LISTVIEW.setAdapter(customAdapter);
LISTVIEW.setTranscriptMode(ListView.TRANSCRIPT_MODE_ALWAYS_SCROLL);
LISTVIEW.setStackFromBottom(true);
}
static class ViewHolder {
TextView ord_num;
TextView cus_name;
TextView cus_tel;
TextView ord_status;
}
class CustomAdapter extends BaseAdapter {
#Override
public int getCount() {
return ID_ArrayList.size() + 1;
}
#Override
public int getViewTypeCount() {
return getCount();
}
#Override
public int getItemViewType(int position) {
return position;
}
#Override
public Object getItem(int i) {
return i;
}
#Override
public long getItemId(int i) {
return -1;
}
#Override
public View getView(int i, View view, ViewGroup viewGroup) {
ViewHolder holder = null;
if (view == null) {
view = getLayoutInflater().inflate(R.layout.listtemplate, viewGroup,false);
holder = new ViewHolder();
holder.ord_num = (TextView) findViewById(R.id.lblID);
holder.cus_name = (TextView) findViewById(R.id.cus_name);
holder.cus_tel = (TextView) findViewById(R.id.cus_tel);
holder.ord_status = (TextView) findViewById(R.id.ord_status);
view.setTag(holder);
} else {
holder = (ViewHolder) view.getTag();
}
try {
holder.ord_num.setText("Order ID :" + ID_ArrayList.get(i));
holder.cus_name.setText("Name : " + NAME_ArrayList.get(i));
holder.cus_tel.setText("Telephone No : " + PHONE_NUMBER_ArrayList.get(i));
holder.ord_status.setText("Status : " + STATUS_ArrayList.get(i));
} catch (Exception ex) {
System.out.println(ex);
}
final int a=i;
view.findViewById(R.id.item_info).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent intent = new Intent(MainActivity.this, View_Items.class);
String x = getItem(a).toString();
String y = ID_ArrayList.get(Integer.parseInt(x)-1).toString();
AlertDialog.Builder alt = new AlertDialog.Builder(MainActivity.this)
.setTitle("HI")
.setMessage(y);
alt.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
}
});
alt.show();
}
});
return (view != null) ? view : null;
Here is My ListView
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.a_hamoud.listview_sqlserver.MainActivity"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
tools:showIn="#layout/activity_main">
<ListView
android:id="#+id/listView1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="8"
>
</ListView>
Please help me to find where the error is.
Thanks.
Try change:
holder.ord_num = (TextView) findViewById(R.id.lblID);
holder.cus_name = (TextView) findViewById(R.id.cus_name);
holder.cus_tel = (TextView) findViewById(R.id.cus_tel);
holder.ord_status = (TextView) findViewById(R.id.ord_status);
to:
holder.ord_num = (TextView) view.findViewById(R.id.lblID);
holder.cus_name = (TextView) view.findViewById(R.id.cus_name);
holder.cus_tel = (TextView) view.findViewById(R.id.cus_tel);
holder.ord_status = (TextView) view.findViewById(R.id.ord_status);
Also remove the +1 in getCount(). Hope that helps!
before set text you must check one codition which is null in your list at first index.
if (ID_ArrayList.get(i) != null){
holder.ord_num.setText("Order ID :" + ID_ArrayList.get(i));
holder.cus_name.setText("Name : " + NAME_ArrayList.get(i));
holder.cus_tel.setText("Telephone No : " + PHONE_NUMBER_ArrayList.get(i));
holder.ord_status.setText("Status : " + STATUS_ArrayList.get(i));
}
i dont know which field is null show you can check.
The adapter thinks it has more items than it really has. Remove the +1 in getCount():
#Override
public int getCount() {
return ID_ArrayList.size();
}
Just update your update your getCount method with this one
#Override
public int getCount() {
return ID_ArrayList.size();
}

RecyclerView is not refreshing

In my application I receive some data from a web server. This data is sent to a RecyclerView. Firstly, all data is displayed fine. However, when I try to refresh it, the data no-longer shows. The data arrives from the web service (as verified using Logcat).
Setting the data
ArrayList<FoodItem> allFood = response.body();
if(foodAdapter != null) {
foodAdapter.swap(allFood);
} else {
foodAdapter = new FoodAdapter(FoodViewForCustomerActivity.this, allFood);
}
photoCollectionView.setAdapter(foodAdapter);
My RecyclerView Adapter
public class FoodAdapter extends RecyclerView.Adapter<FoodAdapter.ViewHolder> {
Context mContext;
ArrayList<FoodItem> foodItems;
public FoodAdapter(Context context, ArrayList<FoodItem> foodItems) {
this.mContext = context;
this.foodItems = foodItems;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.food_item_row, parent, false);
return new ViewHolder(view);
}
public void swap(ArrayList<FoodItem> newFoods) {
foodItems.clear();
foodItems.addAll(newFoods);
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
notifyDataSetChanged();
}
}, 500);
}
#Override
public void onBindViewHolder(final ViewHolder holder, final int position) {
FoodItem foodItem = foodItems.get(position);
String stringPicture = foodItem.getPhoto();
byte[] decodedPictureStringArray = Base64.decode(stringPicture, Base64.DEFAULT);
Bitmap bitmapPhoto = BitmapFactory.decodeByteArray(decodedPictureStringArray, 0, decodedPictureStringArray.length);
Uri photoUri = getImageUri(mContext, bitmapPhoto);
Picasso.with(mContext).load(photoUri).resize(300, 300)
.centerCrop().into(holder.foodImage);
holder.foodItemNameText.setText(foodItem.getFoodItemName());
holder.foodPriceText.setText(foodItem.getUnitPrice() + " / " + foodItem.getUnitType());
}
public Uri getImageUri(Context inContext, Bitmap inImage) {
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
inImage.compress(Bitmap.CompressFormat.JPEG, 10, bytes);
String path = MediaStore.Images.Media.insertImage(inContext.getContentResolver(), inImage, "Title", null);
return Uri.parse(path);
}
#Override
public int getItemCount() {
return foodItems.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
public ImageView foodImage;
public TextView foodItemNameText;
public TextView foodPriceText;
public ViewHolder(View itemView) {
super(itemView);
foodImage = (ImageView) itemView.findViewById(R.id.foodPhoto);
foodItemNameText = (TextView) itemView.findViewById(R.id.foodItemNameText);
foodPriceText = (TextView) itemView.findViewById(R.id.foodPriceText);
}
}
}
The RelativeLayout that contains my Toolbar and RecyclerView
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".FoodViewForCustomerActivity">
<include
android:id="#+id/toolbar"
layout="#layout/toolbar"
/>
<android.support.v7.widget.RecyclerView
android:layout_below="#id/toolbar"
android:id="#+id/photoCollectionView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#f8f8f8"
android:divider="#null"
android:listSelector="#android:color/transparent"/>
</RelativeLayout>
Sorry, for answering my own question. I solved my question by following solution provided here.Main cause of my problem was that RecyclerView was not calling onCreateViewHolder or onBindView, when i was trying to refresh it.
foodAdapter=new FoodAdapter(FoodViewForCustomerActivity.this,allFood);
Change above line.
Send foodItems arraylist reference in adapter constructor instead of allFood
Correct line is
foodAdapter=new FoodAdapter(FoodViewForCustomerActivity.this,foodItems);
Diagnosis #1
Judging from the comment discussion. It seems like your RecyclerView is being fed the correct data from your source.
However, when the data count is 1, it is hidden underneath other UI elements.
You need to make sure that your RecyclerView is not obscured by other UI elements, such as the Toolbar.
There are multiple ways you can do this.
You could add a marginTop of ?attr/actionBarSize to your RecyclerView.
You could add a layout rule to ConstraintLayout similar to android:layout_constraintTop_toBottomOf ="#id/toolbar".
You could add a layout rule to RelativeLayout similar to android:layout_below="#id/toolbar".
Diagnosis #2
Your code for refreshing data is a little strange:
ArrayList<FoodItem> allFood = response.body();
if(foodAdapter != null) {
foodAdapter.swap(allFood);
} else {
foodAdapter = new FoodAdapter(FoodViewForCustomerActivity.this, allFood);
}
photoCollectionView.setAdapter(foodAdapter);
Normally, you do not set the Adapter every time your data has changed. You set it once on initialization, and then refresh the data with the notify methods.
Instead of what you have, please separate the structure as follows:
Member variable of your FoodViewForCustomerActivity:
private ArrayList<FoodItem> mAllFood = new ArrayList<>();
In onCreate():
foodAdapter = new FoodAdapter(FoodViewForCustomerActivity.this, mAllFood);
photoCollectionView.setAdapter(foodAdapter);
In your data collection method:
ArrayList<FoodItem> food = response.body();
if(foodAdapter != null) {
Log.e(TAG, "Data retrieved (size="+food.size()+"), sending it to Adapter.");
foodAdapter.swap(food);
} else {
Log.e(TAG, "Data retrieved (size="+food.size()+"), but Adapter is null!");
}
Change code like this
public void swap(ArrayList<FoodItem> newFoods){
foodItems.clear();
foodItems.addAll(newFoods);
foodAdapter.notifyDataSetChanged();
}
Fine, you can change too
allFood.clear();
allFood.addAll(newFoods);
notifyDataSetChanged();

Data on recycleview item is not correct when scroll

My adapter code:
public class BrandAdapter extends RecyclerView.Adapter<BrandAdapter.BrandViewHolder> {
private static final String TAG = BrandAdapter.class.getSimpleName();
private List<BrandItem> brands;
private Context context;
public BrandAdapter(Context context, List<BrandItem> data) {
this.context = context;
this.brands = data;
}
public void setData(List<BrandItem> dataDownload) {
this.brands = dataDownload;
}
#Override
public BrandViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.row_item_brand, null);
BrandViewHolder holder = new BrandViewHolder(view);
return holder;
}
#Override
public void onBindViewHolder(BrandViewHolder holder, int position) {
BrandItem brandItem = brands.get(position);
String name = brandItem.getName();
int count = brandItem.getCountArticles();
holder.tvName.setText(name);
if (count > 0) {
holder.tvCount.setText("" + count);
} else {
holder.tvCount.setVisibility(View.GONE);
}
}
#Override
public int getItemCount() {
return brands.size();
}
public static class BrandViewHolder extends RecyclerView.ViewHolder {
TextView tvName;
TextView tvCount;
public BrandViewHolder(View itemView) {
super(itemView);
tvName = (TextView) itemView.findViewById(R.id.tv_brand_name);
tvCount = (TextView) itemView.findViewById(R.id.tv_count_article);
}
}
}
Fragment code :
recyclerView = (RecyclerView) view.findViewById(R.id.recycleView);
linearLayoutManager = new LinearLayoutManager(getActivity());
recyclerView.setLayoutManager(linearLayoutManager);
adapter = new BrandAdapter(getActivity(), brands);
recyclerView.setAdapter(adapter);
Data for brands is downloaded from server. After downloaded finished, I just set new data for adapter by this code :
brands = downloadedBrands();
adapter.setData(brands);
adapter.notifyDataSetChanged();
Everything is Ok when data loaded for first time after the download finish. But when I scroll down the recycleview and scroll up again, data for each item is wrong now, all textview tvCount is gone. I do not know why.
Is there any problem from my code ?
Greenrobo's answer is correct but here is an explanation as to WHY you are having this issue.
You are assuming that your view is always set to the default values in your onBindViewHolder method.
The RecyclerView re-uses views that have scrolled off screen and therefore the view you are binding to may have already been previously used (and changed).
You onBindViewHolder method should always set EVERYTHING up. i.e all views reset to the exact values you want and do not assume that because you default an item to visible, it will always be so.
Please make tvCount visible when setting a non-zero count.
if (count > 0) {
holder.tvCount.setText("" + count);
holder.tvCount.setVisibility(View.VISIBLE);
} else {
holder.tvCount.setVisibility(View.GONE);
}
See if this helps.
You told that if count is less than 0, hide the view. What if count is greater than zero ? You are not making the view visible again. So simply make the below changes in your if condition:
if (count > 0) {
holder.tvCount.setText("" + count);
holder.tvCount.setVisibility(View.VISIBLE);
} else {
holder.tvCount.setVisibility(View.GONE);
}

Recyclerview Changing Items During Scroll

I have a RecyclerView. Each row has a play button, textview and Progressbar. when click on the play button have to play audio from my sdcard and have to progress Progressbar
The problem is when i scroll down the recyclerview change the Progressbar in next row.means I can fit 5 items on the screen at once. When I scroll to the 6th, 6th row seekbar changes suddenly.
public class ListAdapter extends RecyclerView.Adapter {
private List<Historyitem> stethitems;
public Context mContext;
public Activity activity;
public Handler mHandler;
static MediaPlayer mPlayer;
static Timer mTimer;
public ListAdapter(Activity activity,Context mContext,List<Historyitem> stethitems) {
this.stethitems = stethitems;
this.mContext = mContext;
this.activity = activity;
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
View rootView = LayoutInflater.
from(mContext).inflate(R.layout.stethoscopeadapteritem, null, false);
RecyclerView.LayoutParams lp = new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
rootView.setLayoutParams(lp);
mHandler = new Handler();
return new MyViewHolder(rootView);
}
#Override
public void onBindViewHolder(final RecyclerView.ViewHolder viewHolder, int position) {
final Historyitem dataItem = stethitems.get(position);
final MyViewHolder myViewHolder = (MyViewHolder) viewHolder;
myViewHolder.progressplay.setProgress(0);
myViewHolder.stethdatetime.setText(dataItem.getReported_Time());
myViewHolder.stethhosname.setText(dataItem.getdiv());
if(dataItem.getPatient_Attribute().replaceAll(" ","").equals("")){
myViewHolder.stethdoctorname.setText(dataItem.getunit());
} else {
myViewHolder.stethdoctorname.setText(dataItem.getPatient_Attribute());
}
myViewHolder.stethstreamplay.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
FileDownload(dataItem.getmsg(),
myViewHolder.progressplay);
}
});
}
#Override
public int getItemCount() {
return stethitems.size();
}
public class MyViewHolder extends RecyclerView.ViewHolder {
final CustomTextRegular stethdatetime;
final CustomTextView stethhosname;
final CustomTextBold stethdoctorname;
final ImageButton stethstreamplay;
final NumberProgressBar progressplay;
public MyViewHolder(View itemView) {
super(itemView);
stethdatetime = (CustomTextRegular)
itemView.findViewById(R.id.stethdatetime);
stethhosname = (CustomTextView)
itemView.findViewById(R.id.stethhosname);
stethdoctorname = (CustomTextBold)
itemView.findViewById(R.id.stethdoctorname);
stethstreamplay = (ImageButton)
itemView.findViewById(R.id.stethstreamplay);
progressplay= (NumberProgressBar)
itemView.findViewById(R.id.progressplay);
}
}
public void FileDownload(final String downloadpath,
final NumberProgressBar progressplay) {
new AsyncTask<NumberProgressBar, Integer, NumberProgressBar>() {
NumberProgressBar progress;
#Override
protected void onPreExecute() {
super.onPreExecute();
try {
if(mPlayer!=null){
mPlayer.stop();
}
}catch (Exception e){
}
try {
if(mTimer != null){
mTimer.purge();
mTimer.cancel();
}
}catch (Exception e){
}
}
#Override
protected NumberProgressBar doInBackground(NumberProgressBar... params) {
int count;
progress = progressplay;
try {
final List<NameValuePair> list = new ArrayList<NameValuePair>();
list.add(new BasicNameValuePair("pid",id));
URL url = new URL(Config.requestfiledownload + "?path=" +
downloadpath);
URLConnection connection = url.openConnection();
connection.connect();
int lenghtOfFile = connection.getContentLength();
// download the file
InputStream input = new BufferedInputStream(url.openStream());
OutputStream output = new FileOutputStream(Environment.getExternalStorageDirectory() +
"record.wav");
byte data[] = new byte[1024];
long total = 0;
while ((count = input.read(data)) != -1) {
total += count;
// publishing the progress....
publishProgress((int) (total * 100 / lenghtOfFile));
output.write(data, 0, count);
}
output.flush();
output.close();
input.close();
} catch (Exception e) {
}
return progress;
}
#Override
protected void onPostExecute(final NumberProgressBar numberProgressBar) {
super.onPostExecute(numberProgressBar);
try {
StartMediaPlayer(numberProgressBar);
} catch (Exception e){
e.printStackTrace();
}
}
}.execute();
}
public void StartMediaPlayer(final NumberProgressBar progressbar){
Uri playuri = Uri.parse("file:///sdcard/record.wav");
mPlayer = new MediaPlayer();
mPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mPlayer.reset();
try {
mPlayer.setDataSource(mContext, playuri);
} catch (IllegalArgumentException e) {
} catch (SecurityException e) {
} catch (IllegalStateException e) {
} catch (Exception e) {
}
try {
mPlayer.prepare();
} catch (Exception e) {
}
mPlayer.start();
progressbar.setMax(mPlayer.getDuration());
mPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer mp) {
if(mPlayer!=null) {
mPlayer.release();
progressbar.setProgress(0);
}
if(mTimer != null){
mTimer.purge();
mTimer.cancel();
}
}
});
mTimer = new Timer();
mTimer.schedule(new TimerTask() {
#Override
public void run() {
mHandler.post(new Runnable() {
#Override
public void run() {
progressbar.setProgress(mPlayer.getCurrentPosition());
}
});
}
},0,500);
}}
Please try this
If you are using ListView - override the following methods.
#Override
public int getViewTypeCount() {
return getCount();
}
#Override
public int getItemViewType(int position) {
return position;
}
If you are using RecyclerView - override only getItemViewType() method.
#Override
public int getItemViewType(int position) {
return position;
}
Add setHasStableIds(true); in your adapter constructor and Override these two methods in adapter. It also worked if anyone using a RecyclerView inside a ViewPager which is also inside a NestedScrollView.
#Override
public long getItemId(int position) {
return position;
}
#Override
public int getItemViewType(int position) {
return position;
}
As the name implies, the views in a RecyclerView are recycled as you scroll down. This means that you need to keep the state of each item in your backing model, which in this case would be a Historyitem, and restore it in your onBindViewHolder.
1) Create position, max, and whatever other variables you need to save the state of the ProgressBar in your model.
2) Set the state of your ProgressBar based on the data in your backing model; on click, pass the position of the item to your FileDownload/StartMediaPlayer methods.
public void onBindViewHolder(final RecyclerView.ViewHolder viewHolder, int position) {
final Historyitem dataItem = stethitems.get(position);
final MyViewHolder myViewHolder = (MyViewHolder) viewHolder;
myViewHolder.progressplay.setMax(dataItem.getMax());
myViewHolder.progressplay.setProgress(dataItem.getPosition());
...
myViewHolder.stethstreamplay.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
FileDownload(dataItem.getmsg(), position);
}
});
3) Update the progress bar by updating the backing model and notifying that it was changed.
stethitems.get(position).setPosition(mPlayer.getCurrentPosition());
notifyItemChanged(position);
I have faced the same problem while I was trying to implement a recyclerview that contains a edittex and a checkbox as a row elements. I solved the scrolling value changing problem just by adding the following two lines in the adapter class.
#Override
public long getItemId(int position) {
return position;
}
#Override
public int getItemViewType(int position) {
return position;
}
I hope it will be a possible solution. Thanks
recyclerview.setItemViewCacheSize(YourList.size());
If your recyclerview ViewHolder has more logic or has a different different view then you should try:
**order_recyclerView.setItemViewCacheSize(x);**
where x is the size of the list. The above works for me, I hope it works for you too.
When we are changing RecyclerView items dynamically (i.e. when changing background color of a specific RecyclerView item), it could change appearance of the items in unexpected ways when scrolling due to the nature of how RecyclerView reuse its items.
However to avoid that it is possible to use android.support.v4.widget.NestedScrollView wrapped around the RecyclerView and letting the NestedScrollView handle the scrolling.
<android.support.v4.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="#+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
</android.support.v4.widget.NestedScrollView>
And then in the code you can disable nested scrolling for the RecyclerView to smooth out scrolling by letting only the NestedScrollView to handle scrolling.
ViewCompat.setNestedScrollingEnabled(recyclerView, false);
Just put you recylerView in a NestedScroll View in your xml and add the property nestedScrollingEnabled = false.
And on your adapter onBindViewHolder add this line
final MyViewHolder viewHolder = (MyViewHolder)holder;
Use this viewHolder object with your views to setText or do any kind of Click events.
e.g viewHolder.txtSubject.setText("Example");
Override the method getItemViewType in adapter. in kotlin use
override fun getItemViewType(position: Int): Int {
return position
}
I had the same problem while handle a lot of data , it works with 5 because it renders the five elements that are visible on the screen but that gives prob with more elements. The thing is ..
Sometimes RecyclerView and listView just skips Populating Data. In case of RecyclerView binding function is skipped while scrolling but when you try and debug the recyclerView adapter it will work fine as it will call onBind every time , you can also see the official google developer's view The World of listView. Around 20 min -30 min they will explain that you can never assume the getView by position will be called every time.
so, I will suggest to use
RecyclerView DataBinder created by satorufujiwara.
or
RecyclerView MultipleViewTypes Binder created by yqritc.
These are other Binders available if you find those easy to work around .
This is the way to deal with MultipleView Types or if you are using large amount of data . These binders can help you
just read the documentation carefully that will fix it, peace!!
Why don't you try like this,
HashMap<String, Integer> progressHashMap = new HashMap<>();
//...
if(!progressHashMap.containsKey(downloadpath)){
progressHashMap.put(downloadpath, mPlayer.getCurrentPosition());
}
progressbar.setProgress(progressHashMap.get(downloadpath));
try this
#Override public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state,
int position) { LinearSmoothScroller linearSmoothScroller =
new LinearSmoothScroller(recyclerView.getContext()) {
#Override
public PointF computeScrollVectorForPosition(int targetPosition) {
return LinearLayoutManager.this
.computeScrollVectorForPosition(targetPosition);
}
}; linearSmoothScroller.setTargetPosition(position); startSmoothScroll(linearSmoothScroller); }
see this also
This line changes progress to 0 on each bind
myViewHolder.progressplay.setProgress(0);
Save its state somewhere then load it in this same line.
I had the similar issue and searched alot for the right answer. Basically it is more of a design of recycler view that it updates the view on the scroll because it refreshes the view.
So all you need to do is at the bind time tell it not to refresh it.
This is how your onBindViewHolder should look like
#Override
#SuppressWarnings("unchecked")
public void onBindViewHolder(final BaseViewHolder holder, final int position) {
holder.bind(mList.get(position));
// This is the mighty fix of the issue i was having
// where recycler view was updating the items on scroll.
holder.setIsRecyclable(false);
}
This is the expected behaviour of recyclerView. Since the view is recycled your items may get into random views. To overcome this you have to specify which item is put into which kind of view by yourself. This information can be kept in a SparseBooleanArray. what you can do is create a SparseBooleanArray in your adapter like this
SparseBooleanArray selectedItems = new SparseBooleanArray();
whenever your view changes, do:
selectedItems.put(viewItemIndex,true);
Now in your onBindViewHolder do
if(selectedItems.get(position, false)){
//set progress bar of related to the view to desired position
}
else {
//do the default
}
This is the basic to solve your problem. You can adjust this logic to any kind of similar problem in recyclerView.

Android: HowTO delete last item of a list and the list

I have an activity which extends ListActivity. It has many things but amongst them it shows the articles the user has purchased with an adapter. Well I have a method that the user can delete the items from the list. The problem is when there is only one item. If I try to delete the last one the app crashes. Here is a it of my code:
public class Ventas extends ListActivity {
......
lv = getListView();
......
protected void confirmRemoval(final int arg2) {
// TODO Auto-generated method stub
AlertDialog alertDialog = new AlertDialog.Builder(this).create();
alertDialog.setTitle(getResources().getString(R.string.ventas));
alertDialog.setMessage(getResources().getString(R.string.confirmacion2));
alertDialog.setButton("Si",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
if(adapter2.mEvents.size()>=1){
adapter2.mEvents.remove(arg2);
} else {
//doesn't work
/*adapter2=null;
adapter2.notifyDataSetInvalidated();
lv.setVisibility(View.GONE);*/
}
}
});
alertDialog.setButton2("No", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
// TODO Auto-generated method stub
dialog.dismiss();
}
});
alertDialog.show();
}
here is the adapter and wrapper:
private class EventAdapter2 extends BaseAdapter {
public ArrayList<Articulo> mEvents = null;
public EventAdapter2(Context c, ArrayList<Articulo> clientes) {
mContext = c;
mEvents = clientes;
}
public int getCount() {
return mEvents.size();
}
public Object getItem(int position) {
return position;
}
public long getItemId(int position) {
return position;
}
public View getView(int position, View convertView, ViewGroup parent) {
EventEntryView2 btv;
if (convertView == null) {
btv = new EventEntryView2(mContext, mEvents.get(position));
} else {
btv = (EventEntryView2) convertView;
String title1 = mEvents.get(position).getCantidad() + "";
if (title1 != null) {
btv.setText1Title(title1);
}
String title2 = mEvents.get(position).getDescripcion();
if (title2 != null) {
btv.setText2Title(title2);
}
String title3 = mEvents.get(position).getpVenta() + "0";
if (title3 != null) {
btv.setText3Title(title3);
}
String title4 = (mEvents.get(position).getCantidad() * mEvents
.get(position).getpVenta()) + "0";
if (title4 != null) {
btv.setText4Title(title4);
}
}
return btv;
}
private Context mContext;
}
private class EventEntryView2 extends LinearLayout {
private TextView text1;
private TextView text2;
private TextView text3;
private TextView text4;
private View inflatedView;
public EventEntryView2(Context context, Articulo resp) {
super(context);
this.setOrientation(VERTICAL);
inflatedView = View.inflate(context, R.layout.results, null);
text1 = (TextView) inflatedView.findViewById(R.id.textView1);
text2 = (TextView) inflatedView.findViewById(R.id.textView2);
text3 = (TextView) inflatedView.findViewById(R.id.textView3);
text4 = (TextView) inflatedView.findViewById(R.id.textView4);
String t = resp.getCantidad() + "";
text1.setText(t);
String t1 = resp.getDescripcion();
text2.setText(t1);
String t2 = resp.getpVenta() + "0";
text3.setText(t2);
String t3 = (resp.getCantidad() * resp.getpVenta()) + "0";
text4.setText(t3);
addView(inflatedView, new LinearLayout.LayoutParams(
LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
}
public void setText4Title(String title4) {
text4.setText(title4);
}
public void setText3Title(String title3) {
text3.setText(title3);
}
public void setText2Title(String title2) {
text2.setText(title2);
}
public void setText1Title(String title1) {
text1.setText(title1);
}
}
as you can see when I have only one item left I have tried to set adapter to null or adapter.notifyDataSetInvaliadted or even making the listview invisible, nothing works. What happens is when I click ok nothing changes then when I click a second time it all crashes
What I would like is the listView to disappear when the adapter is empty but I am now out of ideas, is it even possible?
Any ideas?
EDIT:
Thank you all for the answers but the problem was I was modifying the list from inside an inner anonymous class. It is actually pretty simple, create a method and call it from inside the dialog, once the array is empty the list disappears automatically:
protected void removeFromList(int arg2) {
adapter2.mEvents.remove(arg2);
adapter2.notifyDataSetChanged();
}
remove item from the arraylist which you add into the adapter and then call this method.
youradapter.notifyDataSetChanged();
and whatever you do for single item that was
adapter2 = null;
adapter2.notifyDataSetInavlidated();
this will obviously crash it because adapter2 object was null so how null object notify its data
Try calling lv.invalidate() after the remove() and see whether that makes any difference.
You should check in your adapter class if it is null then you should not fetch value from it......that's the main reason why you are getting exception as you are fetching the value from null variable.Put check there.
For setVisibility to Work:
You create your main.xml
Add to it a ListView
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res/sherif.android.deedz"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<ListView android:layout_width="match_parent"
android:layout_height="match_parent" android:id="#+id/myListView"
android:divider="#ffa500" android:dividerHeight="1px"
android:background="#drawable/somedrawable_xml"
android:choiceMode="singleChoice"></ListView>
</ListView>
Now you can make it GONE
If you want the whole details of this :
Check my answer

Categories

Resources