我目前正在开发第三个用于批量发布的Android项目。与我目前的应用程序相比,我的前两个是相对基础的,这是迄今为止我最复杂的工作。因此,我已经习惯了处理更多的听众。
具体来说,我的应用程序中涉及在MediaPlayer中播放Web流的部分已经使用了三个侦听器。
微调器的监听器:
stationSpinner.setOnItemSelectedListener(new OnItemSelectedListener() {
String newStreamUrl;
@Override
public void onItemSelected(AdapterView<?> parentView, View selectedItemView, int position, long id) {
switch (position) {
// Based on the user's selection, change the URL to match the appropriate station and stream quality.
case 0:
// 128kb 89.7 stream
// Default case, always executed on activity creation.
newStreamUrl = "defaultStreamUrl";
changeStream(newStreamUrl);
break;
case 1:
// 320kb stream
newStreamUrl = "URL1";
changeStream(newStreamUrl);
break;
case 2:
// 128kb Stream 2
newStreamUrl = "URL2";
changeStream(newStreamUrl);
break;
case 3:
// 320kb Steam 2
newStreamUrl = "URL3";
changeStream(newStreamUrl);
}
}
@Override
public void onNothingSelected(AdapterView<?> parentView) {
}
});
progressDialog的监听器:
pd = ProgressDialog.show(this, "Loading...", "Buffering Stream", true, true, new DialogInterface.OnCancelListener() {
@Override
public void onCancel(DialogInterface dialog) {
pd.dismiss();
mp.reset();
}
});
在缓冲完成时触发播放的监听器:
mp.setOnPreparedListener(new OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mp) {
// When the stream is buffered, kill prompt and start playing automatically.
pd.dismiss();
mp.start();
Log.i(TAG, "Stream playback started.");
}
});
......我甚至还没有完成实施听众来处理所有可能的情况。
根据我目前的知识,必须匿名定义一个监听器(如上所述),或者将其作为一个单独的类来编写,该类实现监听器然后在所需的类中实例化。也许这只是我,但我认为匿名定义会使我的代码混乱并掩盖活动背后的逻辑。但是,因为我真的只在这个类中使用这些监听器,所以将它们移动到它们自己的单独文件似乎是一种浪费,因为它会占用我的包的命名空间。
我想知道这种情况的最佳做法是什么。是否有关于听众的明确规则,还是仅仅取决于开发者的偏好?我正努力使这个项目尽可能接近最佳编码实践,因为我刚开始编写Android应用程序,所以希望我能从中学到一些东西。有什么想法吗?
如有必要,我的完整代码代码:
public class StreamActivity extends Activity {
static private MediaPlayer mp;
static ProgressDialog pd;
static String streamUrl = "defaultStreamURL"; // Default value is 128kb/s stream.
private static final String TAG = StreamActivity.class.getName(); // Tag constant for logging purposes
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.stream, menu);
return true;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.stream_layout);
// Build selection spinner
Spinner stationSpinner = (Spinner)findViewById(R.id.station_spinner);
ArrayAdapter<CharSequence> stationAdapter = ArrayAdapter.createFromResource(this, R.array.station_string_array, android.R.layout.simple_spinner_item);
stationAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
stationSpinner.setAdapter(stationAdapter);
// Set spinner decision logic
stationSpinner.setOnItemSelectedListener(new OnItemSelectedListener() {
String newStreamUrl;
@Override
public void onItemSelected(AdapterView<?> parentView, View selectedItemView, int position, long id) {
switch (position) {
// Based on the user's selection, change the URL to match the appropriate station and stream quality.
case 0:
// 128kb 89.7 stream
// Default case, always executed on activity creation.
newStreamUrl = "defaultStreamUrl";
changeStream(newStreamUrl);
break;
case 1:
// 320kb stream
newStreamUrl = "URL1";
changeStream(newStreamUrl);
break;
case 2:
// 128kb Stream 2
newStreamUrl = "URL2";
changeStream(newStreamUrl);
break;
case 3:
// 320kb Steam 2
newStreamUrl = "URL3";
changeStream(newStreamUrl);
}
}
@Override
public void onNothingSelected(AdapterView<?> parentView) {
}
});
// Build audio player using default settings.
mp = buildAudioPlayer();
}
/**
* Builds and returns a configured, unprepared MediaPlayer.
*/
public MediaPlayer buildAudioPlayer() {
// Build MediaPlayer
mp = new MediaPlayer();
try {
mp.reset();
mp.setAudioStreamType(AudioManager.STREAM_MUSIC);
mp.setDataSource(streamUrl);
} catch (IllegalArgumentException e) {
Log.e(TAG, "Caught IllegalArgumentException: ");
e.printStackTrace();
} catch (IllegalStateException e) {
Log.e(TAG, "Caught IllegalStateException: ");
e.printStackTrace();
} catch (SecurityException e) {
Log.e(TAG, "Caught SecurityException: ");
e.printStackTrace();
} catch (IOException e) {
Log.e(TAG, "Caught IOException: ");
e.printStackTrace();
}
pd = new ProgressDialog(this);
return mp;
}
protected void changeStream(String newStreamUrl) {
streamUrl = newStreamUrl;
// Stop stream if it is currently playing to prevent state exceptions
if (mp.isPlaying()) {
Log.i(TAG, "Stream source changed by user. Rebuilding stream.");
Log.i(TAG, "Stream playback stopped.");
mp.stop();
}
// Rebuild player with new stream URL.
mp.reset();
mp = buildAudioPlayer();
}
/**
* Stops audio, drops connection to stream, and returns Media Player to an unprepared state. Called by a button onClick event.
* @param v Button pressed by user.
*/
public void stopAudio(View v) {
mp.stop();
Log.i(TAG, "Stream playback stopped.");
}
/**
* Pauses audio with no change to connection or Media Player. Called by a button onClick event.
* @param v Button pressed by user.
*/
public void pauseAudio(View v) {
mp.pause();
Log.i(TAG, "Stream playback paused.");
}
/**
* Prepares Media Player asynchronously. Displays prompt while buffering and automatically starts when finished.
* @param v Button pressed by user.
*/
public void playAudio(View v) {
// If we are paused, resume playback without rebuffering.
if (mp.isPlaying()) {
mp.start();
} else {
// If audio is NOT playing, we need to prepare and buffer.
try {
mp.setOnPreparedListener(new OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mp) {
// When the stream is buffered, kill prompt and start playing automatically.
pd.dismiss();
mp.start();
Log.i(TAG, "Stream playback started.");
}
});
// Prepares stream without blocking UI Thread
mp.prepareAsync();
} catch (IllegalStateException e) {
Log.e(TAG, "Caught IllegalStateException when preparing: ");
e.printStackTrace();
}
// Stop user input while buffering by displaying ProgressDialog
pd.setCancelable(true);
pd.setCanceledOnTouchOutside(false);
pd = ProgressDialog.show(this, "Loading!", "Buffering...", true, true, new DialogInterface.OnCancelListener() {
@Override
public void onCancel(DialogInterface dialog) {
pd.dismiss();
mp.reset();
}
});
}
}
}
答案 0 :(得分:1)
它使您的代码混乱,因为您将它们制作得太久了。最多将它们减少到两行或三行,并且它将更具可读性。例如:
stationSpinner.setOnItemSelectedListener(new OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parentView,
View selectedItemView,
int position,
long id) {
changeUrl(position);
}
@Override
public void onNothingSelected(AdapterView<?> parentView) {
}
};
...
private void changeUrl(int spinnerPosition) {
String newStreamUrl;
switch (position) {
case 0:
// 128kb 89.7 stream
// Default case, always executed on activity creation.
newStreamUrl = "defaultStreamUrl";
changeStream(newStreamUrl);
break;
case 1:
// 320kb stream
newStreamUrl = "URL1";
changeStream(newStreamUrl);
break;
case 2:
// 128kb Stream 2
newStreamUrl = "URL2";
changeStream(newStreamUrl);
break;
case 3:
// 320kb Steam 2
newStreamUrl = "URL3";
changeStream(newStreamUrl);
}
}
}
或者,如果它仍然太长,您可以将它们实现为非匿名内部类。例如:
stationSpinner.setOnItemSelectedListener(new StationSpinnerListener());
...
private class StationSpinnerListener implements OnItemSelectedListener {
@Override
public void onItemSelected(AdapterView<?> parentView,
View selectedItemView,
int position,
long id) {
String newStreamUrl;
switch (position) {
case 0:
// 128kb 89.7 stream
// Default case, always executed on activity creation.
newStreamUrl = "defaultStreamUrl";
changeStream(newStreamUrl);
break;
case 1:
// 320kb stream
newStreamUrl = "URL1";
changeStream(newStreamUrl);
break;
case 2:
// 128kb Stream 2
newStreamUrl = "URL2";
changeStream(newStreamUrl);
break;
case 3:
// 320kb Steam 2
newStreamUrl = "URL3";
changeStream(newStreamUrl);
}
}
}
@Override
public void onNothingSelected(AdapterView<?> parentView) {
}
}