我正在创建一个下载歌曲的应用程序。在我的应用程序中,有一个RecyclerView
有一个歌曲列表,每首歌曲下面都有一个SeekBar
,显示了下载进度。当我点击下载按钮时,它工作正常,但它更新了错误的SeekBar
。我想更新特定位置的特定SeekBar
。这是RecyclerView
的适配器:
@Override
public SongListAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
itemViewLayout = LayoutInflater.from(parent.getContext()).inflate(R.layout.song_list_single_list, null);
holder = new ViewHolder(itemViewLayout);
return holder;
}
@Override
public void onBindViewHolder(SongListAdapter.ViewHolder holder, final int position) {
mSongListModel = mSongListArray.get(position);
holder.downloadLink.setText(mSongListModel.getDownloadLink());
holder.downloadButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new DownloadFileAsync().execute(String.valueOf(position));
}
});
}
@Override
public int getItemCount() {
return mSongListArray.size();
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
System.out.println("Permission: " + permissions[0] + "was " + grantResults[0]);
//resume tasks needing this permission
//downloadStreamingAudio();
}
}
public class ViewHolder extends RecyclerView.ViewHolder {
private TextView downloadLink;
private SeekBar downloadProgress;
private TextView downloadButton;
public ViewHolder(View itemView) {
super(itemView);
downloadLink = (TextView) itemView.findViewById(R.id.downloadLink);
downloadButton = (TextView) itemView.findViewById(R.id.downloadButton);
downloadProgress = (SeekBar) itemViewLayout.findViewById(R.id.downloadProgress);
}
}
class DownloadFileAsync extends AsyncTask<String, String, String> {
ProgressDialog pDialog;
Uri uri;
String timeStamp;
@Override
protected void onPreExecute() {
super.onPreExecute();
pDialog = new ProgressDialog(c);
pDialog.setMessage("Downlaoding Audio...");
pDialog.setCancelable(true);
pDialog.show();
}
@Override
protected String doInBackground(String... params) {
try {
if (isStoragePermissionGranted()) {
File root = Environment.getExternalStorageDirectory();
File dir = new File(root.getAbsolutePath() + "/AppDownloads/");
timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
System.out.println("Time Stamp::----" + timeStamp);
try {
if (dir.exists() == false) {
dir.mkdirs();
}
RootFile = new File(dir, timeStamp + ".mp3");
} catch (Exception e) {
e.printStackTrace();
}
}
InputStream input = null;
OutputStream output = null;
HttpURLConnection connection = null;
int count;
System.out.println("DownloadUrl::::----"+mSongListArray.get(Integer.parseInt(params[0])).getDownloadLink());
URL url = new URL(mSongListArray.get(Integer.parseInt(params[0])).getDownloadLink());
connection = (HttpURLConnection) url.openConnection();
connection.connect();
// this will be useful so that you can show a tipical 0-100% progress bar
int lenghtOfFile = connection.getContentLength();
// downlod the file
input = new BufferedInputStream(url.openStream());
output = new FileOutputStream(RootFile);
byte data[] = new byte[1024];
long total = 0;
while ((count = input.read(data)) != -1) {
total += count;
// publishing the progress....
//publishProgress((int)(total*100/lenghtOfFile));
updateDownloadProgress((int) (total * 100 / lenghtOfFile));
output.write(data, 0, count);
}
output.flush();
output.close();
input.close();
} catch (Exception e)
{
Log.d("Error....", e.toString());
}
return null;
}
@Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
if (pDialog.isShowing())
pDialog.dismiss();
Toast.makeText(c, "Download Complete", Toast.LENGTH_LONG).show();
}
}
public boolean isStoragePermissionGranted() {
if (Build.VERSION.SDK_INT >= 23) {
if (c.checkSelfPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE)
== PackageManager.PERMISSION_GRANTED) {
System.out.println("Permission is granted");
return true;
} else {
System.out.println("Permission is revoked");
ActivityCompat.requestPermissions((Activity) c, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
return false;
}
} else {
System.out.println("Permission is granted");
return true;
}
}
private void updateDownloadProgress(int progress) {
holder.downloadProgress.setProgress(progress);
}
这是RecyclerView
的布局文件:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:padding="10dp">
<LinearLayout
android:id="@+id/LinearLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/downloadLink"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:padding="10dp" />
<TextView
android:id="@+id/downloadButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/custom_button"
android:text="DOWNLOAD"
android:textSize="15sp" />
<TextView
android:id="@+id/playButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:background="@drawable/custom_button"
android:text="PLAY"
android:textSize="15sp"
android:visibility="gone" />
</LinearLayout>
<SeekBar
android:id="@+id/downloadProgress"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/LinearLayout"
android:layout_marginTop="10dp" />
</RelativeLayout>
有关如何实现这一目标的任何建议吗?
答案 0 :(得分:1)
你的程序是紧密耦合的。我建议你将程序拆分为3个和平。
并在notifyItemChanged
onProgressUpdated
下面是代码示例。
RecyclerView.Adapter是这样的:
public class SongListAdapter extends RecyclerView.Adapter<SongListAdapter.ViewHolder> {
...
private final Listener mListener;
private final Map<Integer, Integer> progressMap = new HashMap<>();
...
interface Listener {
void onClickDownload(int position, SongListModel songListModel);
}
public SongListAdapter(Listener listener) {
mListener = listener;
}
@Override
public void onBindViewHolder(SongListAdapter.ViewHolder holder, final int position) {
...
int progress = progressMap.containsKey(position) ? progressMap.get(position) : 0;
holder.downloadProgress.setProgress(progress);
holder.downloadButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
SongListModel songListModel = mSongListArray.get(position);
mListener.onClickDownload(position, songListModel);
}
});
}
...
public void setProgress(int position, int progress) {
progressMap.put(position, progress);
}
...
}
像这样下载文件同步:
public class DownloadFileAsync extends AsyncTask<String, String, String> {
...
private final Callback mCallback;
private final int mPosition;
private final SongListModel mSongListModel;
interface Callback {
void onDownloadStarting();
void onProgressUpdated(int progress, int position, SongListModel songListModel);
void onDownloadCompleted();
}
public DownloadFileAsync(Callback callback, int position, SongListModel songListModel) {
mCallback = callback;
mPosition = position;
mSongListModel = songListModel;
}
@Override
protected void onPreExecute() {
mCallback.onDownloadStarting();
}
@Override
protected String doInBackground(String... params) {
try {
...
while ((count = input.read(data)) != -1) {
...
mCallback.onProgressUpdated((int) (total * 100 / lenghtOfFile), mPosition, mSongListModel);
...
if (isCancelled()) {
break;
}
}
...
}
return null;
}
...
@Override
protected void onPostExecute(String s) {
mCallback.onDownloadCompleted(s);
}
}
这样的活动:
public class MainActivity extends AppCompatActivity
implements SongListAdapter.Listener, DownloadFileAsync.Callback {
...
private RecyclerView mRecyclerView;
private SongListAdapter mAdapter;
private DownloadFileAsync mDownloadFileAsync;
private ProgressDialog pDialog;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
mRecyclerView = (RecyclerView)findViewById(...);
mAdapter = new SongListAdapter(this);
mRecyclerView.setAdapter(adapter);
...
}
@Override
public void onClickDownload(int position, SongListModel songListModel) {
if (mDownloadFileAsync != null) {
//TODO currentry downloading. Insert error handing.
return;
}
mDownloadFileAsync = new DownloadFileAsync(this, position, songListModel);
mDownloadFileAsync.execute();
}
@Override
public void onDownloadStarting() {
pDialog = new ProgressDialog(this);
pDialog.setMessage("Downlaoding Audio...");
pDialog.setCancelable(true);
pDialog.show();
}
@Override
public void onProgressUpdated(int progress, int position, SongListModel songListModel) {
mAdapter.setProgress(position, progress);
SongListAdapter.ViewHolder holder = mRecyclerView.findViewHolderForAdapterPosition(position);
if (holder != null) {
holder.downloadProgress.setProgress(progress);
}
}
@Override
public void onDownloadCompleted(String s) {
mDownloadFileAsync = null;
if (pDialog.isShowing()) {
pDialog.dismiss();
}
Toast.makeText(this, "Download Complete", Toast.LENGTH_LONG).show();
}
@Override
protected void onDestroy() {
super.onDestroy();
// If you want to stop downloading when activity is closing, call cancel method.
if (mDownloadFileAsync != null) {
mDownloadFileAsync.cancel(true);
}
}
...
}
答案 1 :(得分:0)
holder = new ViewHolder(itemViewLayout);
您将最后创建的持有者指定为您正在更新进度的持有者。不要使用全局变量作为持有者,而是:
使持有人onBindViewHolder()最终。
你的AsyncTask也应该获得对这个持有者的引用。也许在AsyncTask中创建一个Holder变量,并将该holder设置为绑定onBindViewHolder()的那个。
您的执行代码应如下所示。
DownloadFileAsync task = new DownloadFileAsync(String.valueOf(position));
task.setHolder(holder);
task.execute();
祝你好运。