我想为具有更新进度的在线流媒体网址制作循环进度条,如下图所示。
这是在线网址流代码,但在此自定义进度轮中未使用流数据进行更新。
package com.gametech.stream;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import android.content.Context;
import android.media.MediaPlayer;
import android.os.Handler;
import android.util.Log;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.ProgressBar;
import android.widget.TextView;
public class StreamingMediaPlayer
{
private static final int INTIAL_KB_BUFFER = 96 * 10 / 8;// assume
// 96kbps*10secs/8bits
// per byte
//private static final int INTIAL_KB_BUFFER = 15 * 10 / 8;// assume
private TextView textStreamed;
private ImageButton playButton;
//private ProgressBar progressBar;
private ProgressWheel stream_progress;
// Track for display by progressBar
private long mediaLengthInKb, mediaLengthInSeconds;
private int totalKbRead = 0;
// Create Handler to call View updates on the main UI thread.
private final Handler handler = new Handler();
private MediaPlayer mediaPlayer;
private File downloadingMediaFile;
private boolean isInterrupted;
private Context context;
private int counter = 0;
/*public StreamingMediaPlayer(Context context, TextView textStreamed,ImageButton playButton, Button streamButton, ProgressBar progressBar)
{
this.context = context;
this.textStreamed = textStreamed;
this.playButton = playButton;
this.progressBar = progressBar;
}*/
/*public StreamingMediaPlayer(Context context, TextView textStreamed,ImageButton playButton, Button streamButton, ProgressBar progressBar)
{
this.context = context;
this.textStreamed = textStreamed;
this.playButton = playButton;
this.progressBar = progressBar;
}*/
public StreamingMediaPlayer(Context context, TextView textStreamed,ImageButton playButton, Button streamButton, ProgressWheel progressBar)
{
this.context = context;
this.textStreamed = textStreamed;
this.playButton = playButton;
stream_progress = progressBar;
}
/**
* Progressivly download the media to a temporary location and update the
* MediaPlayer as new content becomes available.
*/
public void startStreaming(final String mediaUrl, long mediaLengthInKb,long mediaLengthInSeconds) throws IOException
{
this.mediaLengthInKb = mediaLengthInKb;
this.mediaLengthInSeconds = mediaLengthInSeconds;
Runnable r = new Runnable()
{
public void run()
{
try
{
downloadAudioIncrement(mediaUrl);
}
catch (IOException e)
{
Log.e(getClass().getName(),
"Unable to initialize the MediaPlayer for fileUrl="
+ mediaUrl, e);
return;
}
}
};
new Thread(r).start();
}
/**
* Download the url stream to a temporary location and then call the
* setDataSource for that local file
*/
@SuppressWarnings("resource")
public void downloadAudioIncrement(String mediaUrl) throws IOException
{
URLConnection cn = new URL(mediaUrl).openConnection();
cn.connect();
InputStream stream = cn.getInputStream();
if (stream == null)
{
Log.e(getClass().getName(),
"Unable to create InputStream for mediaUrl:" + mediaUrl);
}
downloadingMediaFile = new File(context.getCacheDir(),"downloadingMedia.dat");
// Just in case a prior deletion failed because our code crashed or
// something, we also delete any previously
// downloaded file to ensure we start fresh. If you use this code,
// always delete
// no longer used downloads else you'll quickly fill up your hard disk
// memory. Of course, you can also
// store any previously downloaded file in a separate data cache for
// instant replay if you wanted as well.
if (downloadingMediaFile.exists())
{
downloadingMediaFile.delete();
}
FileOutputStream out = new FileOutputStream(downloadingMediaFile);
byte buf[] = new byte[16384];
@SuppressWarnings("unused")
int totalBytesRead = 0, incrementalBytesRead = 0;
do
{
int numread = stream.read(buf);
if (numread <= 0)
break;
out.write(buf, 0, numread);
totalBytesRead += numread;
incrementalBytesRead += numread;
totalKbRead = totalBytesRead / 1000;
testMediaBuffer();
fireDataLoadUpdate();
}
while (validateNotInterrupted());
stream.close();
if (validateNotInterrupted())
{
fireDataFullyLoaded();
}
}
private boolean validateNotInterrupted()
{
if (isInterrupted)
{
if (mediaPlayer != null)
{
mediaPlayer.pause();
// mediaPlayer.release();
/*Log.e(getClass().getName(), "Ring Completed...");
playButton.setImageResource(R.drawable.audio_play_new);*/
}
return false;
}
else
{
return true;
}
}
/**
* Test whether we need to transfer buffered data to the MediaPlayer.
* Interacting with MediaPlayer on non-main UI thread can causes crashes to
* so perform this using a Handler.
*/
private void testMediaBuffer()
{
Runnable updater = new Runnable()
{
public void run()
{
if (mediaPlayer == null)
{
// Only create the MediaPlayer once we have the minimum
// buffered data
if (totalKbRead >= INTIAL_KB_BUFFER)
{
try
{
startMediaPlayer();
}
catch (Exception e)
{
Log.e(getClass().getName(),
"Error copying buffered conent.", e);
}
}
}
else if (mediaPlayer.getDuration() - mediaPlayer.getCurrentPosition() <= 1000)
{
// NOTE: The media player has stopped at the end so transfer
// any existing buffered data
// We test for < 1second of data because the media player
// can stop when there is still
// a few milliseconds of data left to play
transferBufferToMediaPlayer();
}
}
};
handler.post(updater);
}
private void startMediaPlayer()
{
try
{
File bufferedFile = new File(context.getCacheDir(), "playingMedia"
+ (counter++) + ".dat");
// We double buffer the data to avoid potential read/write errors
// that could happen if the
// download thread attempted to write at the same time the
// MediaPlayer was trying to read.
// For example, we can't guarantee that the MediaPlayer won't open a
// file for playing and leave it locked while
// the media is playing. This would permanently deadlock the file
// download. To avoid such a deadloack,
// we move the currently loaded data to a temporary buffer file that
// we start playing while the remaining
// data downloads.
moveFile(downloadingMediaFile, bufferedFile);
Log.e(getClass().getName(),
"Buffered File path: " + bufferedFile.getAbsolutePath());
Log.e(getClass().getName(),
"Buffered File length: " + bufferedFile.length() + "");
mediaPlayer = createMediaPlayer(bufferedFile);
// We have pre-loaded enough content and started the MediaPlayer so
// update the buttons & progress meters.
mediaPlayer.start();
startPlayProgressUpdater();
//playButton.setEnabled(true);
playButton.setBackgroundResource(R.drawable.icon_pause);
//playButton.setImageResource(R.drawable.icon_pause);
}
catch (IOException e)
{
Log.e(getClass().getName(), "Error initializing the MediaPlayer.",
e);
return;
}
}
@SuppressWarnings("resource")
private MediaPlayer createMediaPlayer(File mediaFile) throws IOException
{
MediaPlayer mPlayer = new MediaPlayer();
mPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener()
{
public boolean onError(MediaPlayer mp, int what, int extra)
{
Log.e(getClass().getName(), "Error in MediaPlayer: (" + what
+ ") with extra (" + extra + ")");
return false;
}
});
// It appears that for security/permission reasons, it is better to pass
// a FileDescriptor rather than a direct path to the File.
// Also I have seen errors such as "PVMFErrNotSupported" and
// "Prepare failed.: status=0x1" if a file path String is passed to
// setDataSource(). So unless otherwise noted, we use a FileDescriptor
// here.
FileInputStream fis = new FileInputStream(mediaFile);
mPlayer.setDataSource(fis.getFD());
mPlayer.prepare();
return mPlayer;
}
/**
* Transfer buffered data to the MediaPlayer. NOTE: Interacting with a
* MediaPlayer on a non-main UI thread can cause thread-lock and crashes so
* this method should always be called using a Handler.
*/
private void transferBufferToMediaPlayer()
{
try
{
// First determine if we need to restart the player after
// transferring data...e.g. perhaps the user pressed pause
boolean wasPlaying = mediaPlayer.isPlaying();
int curPosition = mediaPlayer.getCurrentPosition();
// Copy the currently downloaded content to a new buffered File.
// Store the old File for deleting later.
File oldBufferedFile = new File(context.getCacheDir(),
"playingMedia" + counter + ".dat");
File bufferedFile = new File(context.getCacheDir(), "playingMedia"
+ (counter++) + ".dat");
// This may be the last buffered File so ask that it be delete on
// exit. If it's already deleted, then this won't mean anything. If
// you want to
// keep and track fully downloaded files for later use, write
// caching code and please send me a copy.
bufferedFile.deleteOnExit();
moveFile(downloadingMediaFile, bufferedFile);
// Pause the current player now as we are about to create and start
// a new one. So far (Android v1.5),
// this always happens so quickly that the user never realized we've
// stopped the player and started a new one
mediaPlayer.pause();
// Create a new MediaPlayer rather than try to re-prepare the prior
// one.
mediaPlayer = createMediaPlayer(bufferedFile);
mediaPlayer.seekTo(curPosition);
// Restart if at end of prior buffered content or mediaPlayer was
// previously playing.
// NOTE: We test for < 1second of data because the media player can
// stop when there is still
// a few milliseconds of data left to play
boolean atEndOfFile = mediaPlayer.getDuration() - mediaPlayer.getCurrentPosition() <= 1000;
if (wasPlaying || atEndOfFile)
{
mediaPlayer.start();
}
// Lastly delete the previously playing buffered File as it's no
// longer needed.
oldBufferedFile.delete();
}
catch (Exception e)
{
Log.e(getClass().getName(),
"Error updating to newly loaded content.", e);
}
}
private void fireDataLoadUpdate()
{
Runnable updater = new Runnable()
{
public void run()
{
textStreamed.setText((totalKbRead + " Kb"));
float loadProgress = ((float) totalKbRead / (float) mediaLengthInKb);
stream_progress.setProgress((int) (loadProgress * 100));
Log.e("Progress Update::", Math.round(((float) loadProgress / 360) * 100) + "%");
//progressBar.setSecondaryProgress((int) (loadProgress * 100));
//Log.e(getClass().getName(), String.valueOf(progressBar.getProgress()));
}
};
handler.post(updater);
}
private void fireDataFullyLoaded()
{
Runnable updater = new Runnable()
{
public void run()
{
transferBufferToMediaPlayer();
// Delete the downloaded File as it's now been transferred to
// the currently playing buffer file.
downloadingMediaFile.delete();
textStreamed.setText(("Audio Loaded: " + totalKbRead + " Kb"));
/*if(mediaPlayer.getDuration() >= mediaLengthInSeconds)
{
Log.e(getClass().getName(), "Ring Completed...");
//playButton.setImageResource(R.drawable.audio_play_new);
}*/
}
};
handler.post(updater);
}
public MediaPlayer getMediaPlayer()
{
return mediaPlayer;
}
public void startPlayProgressUpdater()
{
float progress = (((float) mediaPlayer.getCurrentPosition() / 1000) / mediaLengthInSeconds);
//stream_progress.setProgress((int) (progress * 200));
//progressBar.setProgress((int) (progress * 100));
//Log.e(getClass().getName(), String.valueOf(progress * 100));
if (mediaPlayer.isPlaying())
{
Runnable notification = new Runnable()
{
public void run()
{
startPlayProgressUpdater();
}
};
handler.postDelayed(notification, 1000);
}
else
{
Log.e(getClass().getName(), "Ring Completed...");
playButton.setBackgroundResource(R.drawable.icon_play);
//playButton.setImageResource(R.drawable.icon_play);
//PlayDialogActivity.img_streamAniumation.setVisibility(View.INVISIBLE);
//CustomizeDialog.img_streamAniumation.setImageResource(R.drawable.anim_white);
}
/*if(progress >= mediaLengthInSeconds)
{
Log.e(getClass().getName(), "Ring Completed...");
//playButton.setImageResource(R.drawable.audio_play_new);
}*/
}
public void interrupt()
{
//playButton.setEnabled(false);
playButton.setBackgroundResource(R.drawable.icon_play);
//playButton.setImageResource(R.drawable.icon_play);
isInterrupted = true;
validateNotInterrupted();
}
/**
* Move the file in oldLocation to newLocation.
*/
public void moveFile(File oldLocation, File newLocation) throws IOException
{
if (oldLocation.exists())
{
BufferedInputStream reader = new BufferedInputStream(
new FileInputStream(oldLocation));
BufferedOutputStream writer = new BufferedOutputStream(
new FileOutputStream(newLocation, false));
try
{
// byte[] buff = new byte[8192];
/* changing the size of the buffer */
byte[] buff = new byte[16384];
int numChars;
while ((numChars = reader.read(buff, 0, buff.length)) != -1)
{
writer.write(buff, 0, numChars);
}
}
catch (IOException ex)
{
throw new IOException("IOException when transferring "
+ oldLocation.getPath() + " to "
+ newLocation.getPath());
}
finally
{
try
{
if (reader != null)
{
writer.close();
reader.close();
}
}
catch (IOException ex)
{
Log.e(getClass().getName(),
"Error closing files when transferring "
+ oldLocation.getPath() + " to "
+ newLocation.getPath());
}
}
}
else
{
throw new IOException(
"Old location does not exist when transferring "
+ oldLocation.getPath() + " to "
+ newLocation.getPath());
}
}
}
答案 0 :(得分:1)
此链接可能对您有用:custom circular progress bar
答案 1 :(得分:0)
您可以制作此类圆形ProgressBar,但更新进度取决于几个参数。
如果1)你使用了实时流式传输,那么进度时间取决于流式传输器在这种情况下流式传输的时间长短是不可能的。
2)如果您从服务器传输存储的文件,那么您可以测量文件的长度&amp;取决于您将能够设置每个字节的进度。
问题如何制作这种类型的ProgressBar? 答:可以分享想法,但这并不容易,因为它似乎
完全有可能创建这个并且像素完美且不使用一系列图像。 但问题是它有点难以解释,它完全是关于层和矩形 - 严重。
-Layer 1,背景,用于显示进度的深蓝色圆圈的图像
-Layer 2,矩形相同的高度和覆盖图像左侧的第1层的50%,将锚点更改为0.5,图像是未显示的阴影白色空视图
-Layer 3,矩形相同的高度和覆盖图像右侧的第1层的50%,将锚点更改为0,0.5,图像是无遮盖的阴影白色空视图
最初;
第1层=可见,永不移动
第2层=可见,永不移动
第3层=可见,移动
过程;
- 将层3从0度旋转到360度,表示0到100%。
- 180度设置第2层=隐藏,第4层=可见
逻辑; 这些图层在旋转时用作遮盖图像的遮罩,当百分比达到50%时,您可以交换显示哪些遮罩以管理正确的遮挡。
使用这种技术,您可以获得非常平滑的旋转和非常精确的位置,但可能需要一些时间来理解逻辑。