2013-04-10 65 views
0

我目前正在开发我的第三个Android项目以进行批量发布。与我目前的应用程序相比,我的前两个是相对基本的,这是迄今为止我最复杂的工作。因此,我一直不得不面对更多的听众,然后我习惯了。使用监听器和匿名类 - 最佳实践?

具体来说,我的应用程序中处理MediaPlayer中的网络流的部分已经使用了三个监听器。

用于微调甲听者:

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(); 

      } 

     }); 
    } 
} 

} 

回答

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) { 
    } 
} 
+0

感谢您的支持!使用这种方法更具可读性。 – aerotwelve 2013-04-10 22:29:27