#android #listview #android-mediaplayer #audio-recording #android-mediarecorder
#Android #listview #android-медиаплеер #аудиозапись #android-mediarecorder
Вопрос:
Я работал над этим приложением для чата в Android в течение нескольких месяцев, используя firebase, как и большинство людей. Недавно я работал над добавлением голосовых записей, и у меня нет проблем с этим. Проблема возникает, когда я пытаюсь раздуть представление списка с помощью макета для медиаплеера для воспроизведения / приостановки и отображения хода записи аудио. В макете есть две кнопки: воспроизведение и пауза с возможностью изменения видимости при нажатии на них. Проблема возникает, когда я нажимаю на кнопки, видимость кнопок различных записанных элементов представления списка обновляется вместо изменения соответствующего элемента представления списка. Я не думаю, что мой адаптер реализует шаблон view holder, но я видел, что подобные проекты отлично работают без него. Я не знаю, в чем может быть проблема. Кроме того, чтобы сделать кнопку просмотра списка доступной для просмотра, я добавил следующую строку (android: descendantFocusability=»blocksDescendants») в XML-файл раздутого макета, который отлично работал в другом проекте, который я сделал. Мой код адаптера для представления списка записанного аудио:
else if(map.get("TYPE").toString().contains("RECORDING")){
if (map.get("FROM").toString().contains(mAuth.getUid())) {
convertView = inflater.inflate(R.layout.recording_user_list, null);
}
else {
convertView = inflater.inflate(R.layout.message_image_layout_other, null);
}
TextView mTime = convertView.findViewById(R.id.list_recording_received_time);
mTime.setText(time);
finalRecorderPath = Environment.getExternalStorageDirectory().getAbsolutePath()
"/" map.get("MESSAGE").toString();
playButton = convertView.findViewById(R.id.list_view_recording_play);
pauseButton = convertView.findViewById(R.id.list_view_recording_pause);
pauseButton.setVisibility(View.INVISIBLE);
if(mediaPlayer != null){
mediaPlayer.release();
}
mediaPlayer = new MediaPlayer();
try {
mediaPlayer.setDataSource(map.get("MESSAGE").toString());
mediaPlayer.prepare();
} catch (IOException e) {
e.printStackTrace();
}
playButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
playButton.setVisibility(View.INVISIBLE);
pauseButton.setVisibility(View.VISIBLE);
mediaPlayer.start();
if(recordingFlag){
mediaPlayer.seekTo(audioPosition);
Toast.makeText(activity, "Hey", Toast.LENGTH_SHORT).show();
}
}
});
pauseButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
playButton.setVisibility(View.VISIBLE);
pauseButton.setVisibility(View.INVISIBLE);
audioPosition = mediaPlayer.getCurrentPosition();
recordingFlag = true;
}
});
Log.e(TAG, "setRecording: Path " finalRecorderPath );
Log.e(TAG, "onClick: Playing");
mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mp) {
mediaPlayer.stop();
audioPosition = 0;
recordingFlag = false;
mediaPlayer.release();
Log.e(TAG, "onCompletion: Completed playing audio");
}
});
}
Мой раздутый XML-макет:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:descendantFocusability="blocksDescendants"
android:layout_width="match_parent" android:layout_height="match_parent">
<RelativeLayout
android:layout_margin="5dp"
android:layout_alignParentEnd="true"
android:background="@drawable/text_box_sender"
android:layout_width="300dp"
android:layout_height="80dp">
<ImageButton
android:focusable="false"
android:id="@ id/list_view_recording_play"
android:layout_marginStart="20dp"
android:layout_centerVertical="true"
android:background="@color/colorTransparent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_baseline_play_arrow_24"/>
<ImageButton
android:focusable="false"
android:id="@ id/list_view_recording_pause"
android:layout_marginStart="20dp"
android:layout_centerVertical="true"
android:background="@color/colorTransparent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_baseline_pause_24"/>
<ProgressBar
android:id="@ id/list_recording_progress_bar"
style="@style/Widget.AppCompat.ProgressBar.Horizontal"
android:layout_toEndOf="@ id/list_view_recording_play"
android:layout_centerVertical="true"
android:layout_marginStart="30dp"
android:layout_marginEnd="30dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<TextView
android:layout_alignParentEnd="true"
android:layout_marginEnd="13dp"
android:layout_marginBottom="7dp"
android:textSize="12sp"
android:textColor="@color/colorWhite"
android:layout_below="@id/list_view_recording_pause"
android:id="@ id/list_recording_received_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</RelativeLayout>
</RelativeLayout>
Полный код моих адаптеров просмотра списка приведен ниже:
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.media.MediaPlayer;
import android.os.AsyncTask;
import android.os.Environment;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import com.example.chatbox.R;
import com.google.android.gms.tasks.OnSuccessListener;
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.storage.FirebaseStorage;
import com.google.firebase.storage.StorageReference;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.UUID;
public class ChatAdapter extends BaseAdapter {
String TAG = "Chat Adapter";
FirebaseStorage storage;
private ArrayList<HashMap> chatList;
StorageReference mDataRef;
private Activity activity;
FirebaseAuth mAuth = FirebaseAuth.getInstance();
private MediaPlayer mediaPlayer;
private String finalRecorderPath;
private ImageButton playButton, pauseButton;
int audioPosition;
private boolean recordingFlag = false;
public ChatAdapter(Activity activity, ArrayList<HashMap> chatList){
this.chatList = chatList;
this.activity = activity;
storage = FirebaseStorage.getInstance();
mDataRef = storage.getReferenceFromUrl("gs://chat-box-v2.appspot.com");
}
@Override
public int getCount() {
return chatList.size();
}
@Override
public Object getItem(int position) {
return chatList.get(position);
}
@Override
public long getItemId(int position) {
return 0;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
final HashMap map = chatList.get(position);
LayoutInflater inflater = activity.getLayoutInflater();
String time = map.get("TIME").toString();
try {
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date = format.parse(time);
Date currentTime = Calendar.getInstance().getTime();
format = new SimpleDateFormat("yyyy-MM-dd");
String chatDate = format.format(date);
String curDate = format.format(currentTime);
if (chatDate.contains(curDate)) {
format = new SimpleDateFormat("hh:mm aa");
time = format.format(date);
Log.e(TAG, "Adapter Time Matches");
} else {
format = new SimpleDateFormat("dd-MM-yyyy HH:mm aa");
time = format.format(date);
Log.e(TAG, "Time doesnt Match");
}
} catch (Exception e) {
Log.e(TAG, "Chat Adapter Time Exception: " e.toString());
}
if(map.get("TYPE").toString().contains("MESSAGE")) {
if (map.get("FROM").toString().contains(mAuth.getUid()))
convertView = inflater.inflate(R.layout.sender, null);
else
convertView = inflater.inflate(R.layout.reciever, null);
TextView mName = convertView.findViewById(R.id.user_name_list);
TextView mMessage = convertView.findViewById(R.id.chat_text_list);
TextView mTime = convertView.findViewById(R.id.text_time_list);
/***Date And Time Formatter For List View Chat**/
try {
mName.setText(map.get("NAME").toString());
} catch (Exception e) {
Log.e(TAG, "getView: Name" e.toString());
}
try {
mMessage.setText(map.get("MESSAGE").toString());
mTime.setText(time);
} catch (Exception e) {
}
}
else if(map.get("TYPE").toString().contains("IMAGE")){
if (map.get("FROM").toString().contains(mAuth.getUid()))
convertView = inflater.inflate(R.layout.message_image_layout_user, null);
else
convertView = inflater.inflate(R.layout.message_image_layout_other, null);
ImageView imageView = convertView.findViewById(R.id.message_image_view);
ProgressBar progressBar = convertView.findViewById(R.id.progress_circular_bar_image);
GetImageBitmap(map.get("MESSAGE").toString(), imageView, progressBar);
}
else if(map.get("TYPE").toString().contains("RECORDING")){
if (map.get("FROM").toString().contains(mAuth.getUid())) {
convertView = inflater.inflate(R.layout.recording_user_list, null);
}
else {
convertView = inflater.inflate(R.layout.message_image_layout_other, null);
}
TextView mTime = convertView.findViewById(R.id.list_recording_received_time);
mTime.setText(time);
finalRecorderPath = Environment.getExternalStorageDirectory().getAbsolutePath()
"/" map.get("MESSAGE").toString();
playButton = convertView.findViewById(R.id.list_view_recording_play);
pauseButton = convertView.findViewById(R.id.list_view_recording_pause);
pauseButton.setVisibility(View.INVISIBLE);
if(mediaPlayer != null){
mediaPlayer.release();
}
mediaPlayer = new MediaPlayer();
try {
mediaPlayer.setDataSource(map.get("MESSAGE").toString());
mediaPlayer.prepare();
} catch (IOException e) {
e.printStackTrace();
}
playButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
playButton.setVisibility(View.INVISIBLE);
pauseButton.setVisibility(View.VISIBLE);
mediaPlayer.start();
if(recordingFlag){
mediaPlayer.seekTo(audioPosition);
Toast.makeText(activity, "Hey", Toast.LENGTH_SHORT).show();
}
}
});
pauseButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
playButton.setVisibility(View.VISIBLE);
pauseButton.setVisibility(View.INVISIBLE);
audioPosition = mediaPlayer.getCurrentPosition();
recordingFlag = true;
}
});
Log.e(TAG, "setRecording: Path " finalRecorderPath );
Log.e(TAG, "onClick: Playing");
mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mp) {
mediaPlayer.stop();
audioPosition = 0;
recordingFlag = false;
mediaPlayer.release();
Log.e(TAG, "onCompletion: Completed playing audio");
}
});
}
return convertView;
}
void GetImageBitmap(final String url, final ImageView imageView, final ProgressBar progressBar){
Log.e(TAG, "GetImageBitmap: " url );
final Handler handler = new Handler(Looper.getMainLooper());
AsyncTask.execute(new Runnable() {
@Override
public void run() {
FileInputStream fileInputStream;
Bitmap bitmap = null;
try {
fileInputStream = activity.openFileInput(url);
bitmap = BitmapFactory.decodeStream(fileInputStream);
final Bitmap finalBitmap = bitmap;
handler.post(new Runnable() {
@Override
public void run() {
try {
progressBar.setVisibility(View.GONE);
Drawable drawable = new BitmapDrawable(finalBitmap);
imageView.setImageDrawable(drawable);
imageView.setDrawingCacheEnabled(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
Log.e(TAG, "GetImageBitmap: Bitmap");
} catch (FileNotFoundException e) {
e.printStackTrace();
final StorageReference ref = storage.getReference().child("images/message/" url);
ref.getBytes(1020*1024*7).addOnSuccessListener(new OnSuccessListener<byte[]>() {
@Override
public void onSuccess(byte[] bytes) {
Log.e("TestData", "onSuccess: " "successfully downloaded image" );
Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
try {
Drawable drawable = new BitmapDrawable(bitmap);
imageView.setImageDrawable(drawable);
imageView.setDrawingCacheEnabled(true);
} catch (Exception e) {
e.printStackTrace();
}
saveImage(activity, bitmap, url);
}
});
}
}
});
}
void saveImage(Context context, Bitmap bitmap, String name){
try {
FileOutputStream fileOutputStream = context.openFileOutput(name, Context.MODE_PRIVATE);
bitmap.compress(Bitmap.CompressFormat.JPEG, 90, fileOutputStream);
fileOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Есть ли что-то, что я делаю неправильно или что-то упускаю? Я все еще новичок в этом:/ Я буду благодарен всем, кто поможет мне разобраться, что не так с моим кодом. Заранее спасибо 🙂
Ответ №1:
Я получил решение, по-видимому, причиной этого была не реализация шаблона view holder. Я сделал это, и это работает как шарм 🙂 Примечание для людей из будущего: -Никогда не используйте просмотр списка, просмотр с помощью recycler более продвинутый и надежный. -Всегда внедряйте шаблон держателя представления.