MediaPlayer inside an adapter playing the wrong track - android-mediaplayer

I'm fairly new to Android development, and I added a MediaPlayer in a list of items so that the pronunciation is played for each word listed.
However, the wrong track is playing, I can't figure out how to link the right track to each item in the list view.
The ID changes when I'm scrolling for example as I can see in logs, so I think there's something I misunderstood.
What I fail to understand is why it works for the ImageView for example, but not for the audio file.
public class WordsAdapter extends ArrayAdapter<Words>{
private int colorview;
private View listItemView;
private Words currentWords;
public WordsAdapter(Context context, ArrayList<Words> words, int color){
super(context, 0, words);
colorview = color;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
listItemView = convertView;
if(listItemView == null) {
listItemView = LayoutInflater.from(getContext()).inflate(
R.layout.list_view_black, parent, false);
}
currentWords = getItem(position);
ImageView image = (ImageView) listItemView.findViewById(R.id.imageicon);
if(currentWords.hasImage()) {
image.setImageResource((currentWords.getImageID()));
image.setVisibility(View.VISIBLE);
}else image.setVisibility(View.GONE);
TextView defaultTextView = (TextView) listItemView.findViewById(R.id.text_default);
defaultTextView.setText(currentWords.getDefaultWord());
TextView miwokTextView = (TextView) listItemView.findViewById(R.id.text_miwok);
miwokTextView.setText(currentWords.getMiwokWord());
View linearWords = listItemView.findViewById(R.id.linear_words);
linearWords.setBackgroundResource(colorview);
Button ButtonPlay = (Button) listItemView.findViewById(R.id.playButton);
ButtonPlay.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View v){
MediaPlayer player = MediaPlayer.create(v.getContext(), currentWords.getAudioFile());
Log.v("Audio id : ", player.getTrackInfo().toString());
player.start();
}
});
return listItemView;
}
}

I found the solution.
The variable currentWords needs to be declared inside the method and set to final.
public View getView(int position, View convertView, ViewGroup parent) {
[...]
final Words currentWords = getItem(position);
[...]
}

Related

change item color on click in recyclerview android

I am trying to change the color of the items on click when the action mode is active. The problem is that e.g if there are five items in a recyclerview and you click one, scroll down and select sixth item and destroy the action mode. The next time you start selecting, that sixth item has automatically changed its color without you selecting it. I don't know why it is happening.
public static List<ModelClass> items = new ArrayList<>();
boolean isSelectMode = false;
boolean isActionModeEnabled = false;
public static List<ModelClass> selectList = new ArrayList<>();
#Override
public void onBindViewHolder(#NonNull MyAdapter.MyViewHolder holder, int
position) {
holder.bind(items.get(position));
ModelClass modelClass = items.get(position);
if (modelClass.isChecked() && isActionModeEnabled){
holder.row.setBackgroundColor(Color.GREEN);
modelClass.setChecked(true);
} else {
holder.row.setBackgroundColor(Color.TRANSPARENT);
modelClass.setChecked(false);
}
}
public class MyViewHolder extends RecyclerView.ViewHolder{
public MyViewHolder(#NonNull View itemView) {
super(itemView);
row = itemView.findViewById(R.id.row);
public void bind(ModelClass model) {
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (isActionModeEnabled) {
isSelectMode = true;
s = items.get(getAdapterPosition());
if (!selectList.contains(s)){
selectList.add(s);
row.setBackgroundColor(Color.GREEN);
model.setChecked(true);
} else {
selectList.remove(s);
row.setBackgroundColor(Color.TRANSPARENT);
model.setChecked(false);
}
}
});
}
The problem is going to be in your view holder binding:
if (modelClass.isChecked() && isActionModeEnabled){
holder.row.setBackgroundColor(Color.GREEN);
modelClass.setChecked(true);
} else {
holder.row.setBackgroundColor(Color.TRANSPARENT);
modelClass.setChecked(false);
}
Remember that view holders are reused. That means that they will retain their internal state unless you change them. Your item list will also remember its state. Make sure you cover all the possible states of the item list and the reused view holders in the code above: You are probably missing a combination.
I recommend that you set a break point in the code above to make sure it is doing what you want. It should become obvious to you once you take a closer look.

Trouble getting recyclerview to load elements

I am making a networking app's chat section from this tutorial: https://blog.sendbird.com/android-chat-tutorial-building-a-messaging-ui.
I have everything hooked up so that I know that the messages are coming in from the database. It seems to be an issue with how the adapter or recyclerview are set up. I can't see any messages on my activity even though I can see them if I poke in my async/background worker.
This is the adapter class with inner view holders from the tutorial, adapted to my needs:
public class MessageListAdapter extends RecyclerView.Adapter {
private static final int VIEW_TYPE_MESSAGE_SENT = 1;
private static final int VIEW_TYPE_MESSAGE_RECEIVED = 2;
private Activity mContext;
private ArrayList<Message> mMessageList;
public MessageListAdapter(Activity context, ArrayList<Message> messageList) {
mContext = context;
mMessageList = messageList;
}
#Override
public int getItemCount() {
return mMessageList.size();
}
// Determines the appropriate ViewType according to the sender of the message.
#Override
public int getItemViewType(int position) {
Message message = (Message) mMessageList.get(position);
if (message.isOther() == "2") {
// If the current user is the sender of the message
return VIEW_TYPE_MESSAGE_SENT;
} else {
// If some other user sent the message
return VIEW_TYPE_MESSAGE_RECEIVED;
}
}
// Inflates the appropriate layout according to the ViewType.
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view;
if (viewType == VIEW_TYPE_MESSAGE_SENT) {
view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_message_sent, parent, false);
return new SentMessageHolder(view);
} else if (viewType == VIEW_TYPE_MESSAGE_RECEIVED) {
view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_message_received, parent, false);
return new ReceivedMessageHolder(view);
}
return null;
}
// Passes the message object to a ViewHolder so that the contents can be bound to UI.
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
Message message = mMessageList.get(position);
switch (holder.getItemViewType()) {
case VIEW_TYPE_MESSAGE_SENT:
((SentMessageHolder) holder).bind(message);
break;
case VIEW_TYPE_MESSAGE_RECEIVED:
((ReceivedMessageHolder) holder).bind(message);
}
}
private class SentMessageHolder extends RecyclerView.ViewHolder {
TextView messageText, timeText;
SentMessageHolder(View itemView) {
super(itemView);
messageText = (TextView) itemView.findViewById(R.id.text_message_body);
timeText = (TextView) itemView.findViewById(R.id.text_message_time);
}
void bind(Message message) {
messageText.setText(message.getMessage());
// Format the stored timestamp into a readable String using method.
timeText.setText(message.getCreatedAt());
}
}
private class ReceivedMessageHolder extends RecyclerView.ViewHolder {
TextView messageText, timeText, nameText;
ImageView profileImage;
ReceivedMessageHolder(View itemView) {
super(itemView);
messageText = (TextView) itemView.findViewById(R.id.text_message_body);
timeText = (TextView) itemView.findViewById(R.id.text_message_time);
nameText = (TextView) itemView.findViewById(R.id.text_message_name);
profileImage = (ImageView) itemView.findViewById(R.id.image_message_profile);
}
void bind(Message message) {
messageText.setText(message.getMessage());
// Format the stored timestamp into a readable String using method.
timeText.setText(message.getCreatedAt());
nameText.setText(message.getSender());
Picasso.get().load(message.getProfile())
.transform(new RoundedCornersTransformation(150, 0)).into(profileImage);
// Insert the profile image from the URL into the ImageView.
// Utils.displayRoundImageFromUrl(mContext, message.getSender().getProfileUrl(), profileImage);
}
}
}
I create the adapter and pair it to the recyclerview in a background worker during postExecute()
try {
JSONArray messages = new JSONArray(s);
ArrayList<Message> messageList = new ArrayList<Message>();
for (int i = 0; i < messages.length(); i++) {
String currentMessage = (String) messages.get(i);
String[] fields = currentMessage.split(",", 0);
if (fields.length == 5) {
String isOther = fields[0];
String messageText = fields[1];
String dateTime = fields[2];
String author = fields[3];
String pictureLocation = fields[4];
Message newMessage = new Message(isOther, messageText, dateTime, author, pictureLocation);
messageList.add(newMessage);
}
}
mMessageRecycler = (RecyclerView) ha.findViewById(R.id.reyclerview_message_list);
mMessageRecycler.setLayoutManager(new LinearLayoutManager(ha.getApplicationContext()));
mMessageAdapter = new MessageListAdapter(ha, messageList);
mMessageRecycler.setAdapter(mMessageAdapter);
}
I've tried adding alert dialogs to debug within the OnCreateViewHolder, but can't get them to appear. I've tried using ha, ha.getApplicationContext() on every field. There must be something that's just staring me in the face. I've used this pattern before and it works for another section of my app.
It turns out that the tutorial's recyclerview information is just barely off, so I used the one I had in a previous part of the app:
<android.support.v7.widget.RecyclerView
android:id="#+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#FFFFFF" />

How to hide/show a view in the Activity by clicking a button in the Android Cardview?

I am working on a commercial app as an internship. In one of its activity, I have tab view with two fragments. In each fragment, I'm using the card view to hold the views.
The card view has one image view, two text views, and a button and in the bottom of the activity below the tab view, there is a button which has its visibility mode as "GONE".
Now What I want is, Whenever I click on the button in the card view, the button at the bottom of the activity should hide/show for respective clicks.
Cardcaptionadapter.java
public CaptionedImagesAdapterMenu.ViewHolder onCreateViewHolder(
ViewGroup parent, int viewType){
CardView cv = (CardView) LayoutInflater.from(parent.getContext())
.inflate(R.layout.card_captioned_image_menu, parent, false);
return new ViewHolder(cv);
}
#Override
public void onBindViewHolder(ViewHolder holder, final int position){
CardView cardView = holder.cardView;
ImageView imageView = (ImageView)cardView.findViewById(R.id.info_image);
Drawable drawable = ContextCompat.getDrawable(cardView.getContext(), imageIds[position]);
imageView.setImageDrawable(drawable);
imageView.setContentDescription(captions[position]);
TextView textView = (TextView)cardView.findViewById(R.id.info_text);
textView.setText(captions[position]);
TextView textView1 = cardView.findViewById(R.id.info_menu);
textView1.setText(desc[position]);
TextView textView2 = cardView.findViewById(R.id.info_price);
textView2.setText("₹ " + price[position]);
cardView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (listener != null) {
listener.onClick(position);
}
}
});
holder.button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if(holder.button.getText().equals("ADD")){
holder.button.setText("ADDED");
holder.button.setBackgroundColor(Color.parseColor("#00ff00"));
SharedPreferences sharedPref = context.getSharedPreferences("ADD",0);
SharedPreferences.Editor editor = sharedPref.edit();
editor.putInt("ADDED", 1);
editor.apply();
}
else {
holder.button.setText("ADD");
holder.button.setBackgroundColor(Color.parseColor("#ffffff"));
SharedPreferences sharedPref = context.getSharedPreferences("ADD",0);
SharedPreferences.Editor editor = sharedPref.edit();
editor.clear();
editor.apply();
}
}
});
}
MenuActivity.java
SharedPreferences preferences = getSharedPreferences("ADD",0);
int addvalue = preferences.getInt("ADDED",0);
if(addvalue==1){
orderbutton.setVisibility(View.VISIBLE);
}
else{
orderbutton.setVisibility(View.GONE);
}
orderbutton.setOnClickListener(view -> {
orderbutton.setVisibility(View.GONE);
paybutton.setVisibility(View.VISIBLE);
});
you should add MenuActivity.java code inside public void onBindViewHolder(ViewHolder holder, final int position){ } method also.

CustomView inside recycler view not showing keyboard when focus

I have created one custom view that extends constraintsalyout. Inside that view, I added EditText and Textview. When I try to add this custom view inside recycler view, Its not showing keyboard when I touch on that edittext.
Its perfectly working when added outside of recycler view
public class SVEditText extends ConstraintLayout {
private Context context;
private EditText editText;
private TextView textView;
public SVEditText(final Context context, AttributeSet attrs) {
super(context, attrs);
this.context = context;
LayoutInflater inflater = LayoutInflater.from(context);
View view = inflater.inflate(R.layout.sv_edittext, this);
editText = view.findViewById(R.id.editText);
textView = view.findViewById(R.id.textView);
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.SVEditText);
editText.setText(typedArray.getString(R.styleable.SVEditText_text));
editText.setHint(typedArray.getString(R.styleable.SVEditText_hint));
editText.setLines(typedArray.getInteger(R.styleable.SVEditText_android_lines, 1));
editText.setInputType(typedArray.getInteger(R.styleable.SVEditText_android_inputType, 0));
textView.setText(typedArray.getString(R.styleable.SVEditText_title));
setDrawablesToEditText(typedArray);
typedArray.recycle();
}
private void setDrawablesToEditText(TypedArray typedArray){
if (typedArray.getInteger(R.styleable.SVEditText_android_lines, 1) != 1){
Drawable innerDrawableLeft = typedArray.getDrawable(R.styleable.SVEditText_iconLeft);
Drawable innerDrawableRight = typedArray.getDrawable(R.styleable.SVEditText_iconRight);
GravityCompoundDrawable iconLeft = null, iconRight = null;
if (innerDrawableLeft != null) {
iconLeft = new GravityCompoundDrawable(innerDrawableLeft);
innerDrawableLeft.setBounds(0, 30, innerDrawableLeft.getIntrinsicWidth(), innerDrawableLeft.getIntrinsicHeight()+30);
iconLeft.setBounds(0, 0, innerDrawableLeft.getIntrinsicWidth(), innerDrawableLeft.getIntrinsicHeight());
iconLeft.setColorFilter(new PorterDuffColorFilter(ContextCompat.getColor(getContext(), R.color.colorPrimary), PorterDuff.Mode.SRC_IN));
}
if (innerDrawableRight != null) {
iconRight = new GravityCompoundDrawable(innerDrawableRight);
innerDrawableRight.setBounds(0, 30, innerDrawableRight.getIntrinsicWidth(), innerDrawableRight.getIntrinsicHeight()+30);
iconRight.setBounds(0, 0, innerDrawableRight.getIntrinsicWidth(), innerDrawableRight.getIntrinsicHeight());
iconRight.setColorFilter(new PorterDuffColorFilter(ContextCompat.getColor(getContext(), R.color.colorPrimary), PorterDuff.Mode.SRC_IN));
}
editText.setCompoundDrawablesWithIntrinsicBounds(iconLeft,
null, iconRight, null);
editText.setBackgroundResource(R.drawable.bg_edit_multiline);
return;
}
editText.setCompoundDrawablesWithIntrinsicBounds(typedArray.getDrawable(R.styleable.SVEditText_iconLeft),
null, typedArray.getDrawable(R.styleable.SVEditText_iconRight), null);
}
public void setText(String value){
editText.setText(value);
}
public void setHint(String hint){
editText.setHint(hint);
}
public void setTitle(String title){
textView.setText(title);
}
public void setCompoundDrawablesWithIntrinsicBounds( #DrawableRes int left, #DrawableRes int top, #DrawableRes int right, #DrawableRes int bottom){
editText.setCompoundDrawablesWithIntrinsicBounds(left, top, right, bottom);
}
public void setText(Spannable spannable) {
editText.setText(spannable);
}
}
Finally I found the mistake I made.
I missed this line in xml.
android:inputType="phone"
So it is taken as 0 default from my custom view code.
I updated that default value as 1, now it is working without adding inputtype in xml.

android carousel with animation

I want to have a animation(ex:fadeout) when I touch the selected image.
I use the carousel example here:Android 3D Carousel
my codes is
public class MainActivity extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//Animation fadeout = AnimationUtils.loadAnimation(this, R.anim.fadeout);
Carousel carousel = (Carousel)findViewById(R.id.carousel);
carousel.setOnItemClickListener(new OnItemClickListener(){
#Override
public void onItemClick(CarouselAdapter<?> parent, View view,
int position, long id) {
//Toast.makeText(MainActivity.this, "Position=" + position, Toast.LENGTH_SHORT).show();
if(position==0){
String toastMessage = String.format("RFID");
Toast.makeText(getApplicationContext(), toastMessage, Toast.LENGTH_LONG).show();
Animation anim = null;
anim = new RotateAnimation(0.0f,+360.0f);
anim.setInterpolator(new AccelerateDecelerateInterpolator());
anim.setDuration(30000);
findViewById(R.id.carousel).startAnimation(anim);
Intent i = new Intent();
i.setClass(MainActivity.this, web_rfid.class);
startActivity(i);
}
}
});
}
}
I want the selected image to be rotated, but the result is whole screen rotated.
The problem is
findViewById(R.id.carousel).startAnimation(anim);
But I don't know how to find out the selected image in my code.
Plz hlep me.
Thanks.