Android Studio 编码约定和可能的上下文错误?

Android Studio Coding Convention & Possible Context Error?

现在我正在尝试更加熟悉 Android 开发。当然,我正在使用 Android Studio 来执行此操作。作为一个项目,我正在编写一个应用程序来处理来自 URL 和 MediaPlayer class.

的流式传输

我得到了这个功能,并且完全按照我的需要去做。但是,我不希望我的 MainActivity 被可以存储在它们自己的 classes 中的方法和变量弄得乱七八糟。

我对此有几个问题:

我对这种开发还很陌生,所以随时欢迎提示、良好习惯和有用的提示。

这是我的 MainActivity,它调用了我在 Streaming class:

中放入的方法
public class MainActivity extends AppCompatActivity {

    Streaming stream = new Streaming(this);
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    stream.updateSeekBar();
    stream.onPlayClick();
    stream.onDrag();

}

你可以在这里看到我调用的所有这些方法:

public class Streaming extends AppCompatActivity {

private SeekBar musicSeek;
private TextView currentTime;
private TextView totalTime;
private ImageButton play_pause;
private Handler seekHandler = new Handler();
private MediaPlayer mp = new MediaPlayer();
Context context;
Utilities util = new Utilities();

//Default Constructor
public Streaming(){}
//Contructor
public Streaming(Context context){
    this.context = context;
}
//Method to run the runnable to update the seekbar
public void updateSeekBar(){
    seekHandler.postDelayed(mUpdateTimeTask, 100);
}

public void prepareStreaming() throws IOException {
    mp.setAudioStreamType(AudioManager.STREAM_MUSIC);
    mp.setDataSource("http://tricountynaz.net/media/audio/2017-11-08-The%20Compassion%20of%20the%20Christ.mp3");
    mp.prepare();
}

public void startStreaming(){
    mp.start();
}

public void pauseStreaming(){
    mp.pause();
}

//Runnable to update the seekbar with the current position.
private Runnable mUpdateTimeTask = new Runnable() {
    public void run() {
        int totalDuration = mp.getDuration();
        int currentPosition = (mp.getCurrentPosition());


        //Displaying Total Duration time
        totalTime = (TextView)((Activity)context).findViewById(R.id.totalTime);
        totalTime.setText(util.milliSecondsToTimer(totalDuration));
        // Displaying time completed playing
        currentTime = (TextView)((Activity)context).findViewById(R.id.currentTime);
        currentTime.setText(util.milliSecondsToTimer(currentPosition));
        //Set the bars total duration, based on the song duration (converted to seconds)
        musicSeek = (SeekBar)((Activity)context).findViewById(R.id.music_seek);
        musicSeek.setMax(totalDuration/1000);
        // Updating progress bar
        musicSeek.setProgress(mp.getCurrentPosition()/1000);

        // Running this thread after 100 milliseconds
        seekHandler.postDelayed(this, 100);
    }
};

//What happens when the user interacts with the button
public void onPlayClick (){
    play_pause = (ImageButton)((Activity)context).findViewById(R.id.playButton);
    play_pause.setOnClickListener(new View.OnClickListener() {

        @Override
        public void onClick(View view) {
            play_pause.setImageResource(R.drawable.ic_pause_name);

            try {
                prepareStreaming();
            } catch (IOException e) {
                e.printStackTrace();
            }

            if (mp.isPlaying()) {
                pauseStreaming();
                play_pause.setImageResource(R.drawable.ic_play_name);


            } else {
                //mediaPlayer.start();
                startStreaming();
            }
        }
    });
}

//Handles when the user interacts with the seekbar
public void onDrag(){
    musicSeek.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
        @Override
        public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
            if(b) {
                //seeks to the current position of the slider when the user (b) interacts.
                mp.seekTo(i*1000);
                musicSeek.setProgress(i);
            }
        }

        @Override
        public void onStartTrackingTouch(SeekBar seekBar) {

        }

        @Override
        public void onStopTrackingTouch(SeekBar seekBar) {

        }
    });}

您会注意到 Utilities class。目前,这仅包含一种转换为秒的方法,因此我可以更新正在播放的 MP3 当前进度的 TextView 项。

我收到的具体错误是 NullPointerException 来自 onDrag 方法。我似乎无法理解为什么。

抱歉,如果这是重复的,我似乎无法在其他地方找到它。

编辑 我确实稍微改变了我的 onDrag 方法:

//Handles when the user interacts with the seekbar
public void onDrag(){
    musicSeek = (SeekBar)((Activity)context).findViewById(R.id.music_seek);
    musicSeek.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
        @Override
        public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
            if(b) {
                //seeks to the current position of the slider when the user (b) interacts.
                mp.seekTo(i*1000);
                musicSeek.setProgress(i);
            }
        }

这确实修复了 nullPointerException,只是现在我在日志中收到了这个错误:

E/MediaPlayerNative: Attempt to call getDuration in wrong state: mPlayer=0x0, mCurrentState=0

编辑 2 我想我已经解决了我的问题。在研究我最近的错误后,我开始意识到我从未在我的 MainActivity 中调用我的 MediaPlayer,因此没有加载任何内容也没有流式传输。 Here 是我找到部分解决方案的地方。

仍然 运行 遇到问题,我的 playbutton 无法正常工作并自动开始流式传输,但这是一个小问题,我认为可以轻松解决。但是,我仍然想知道我的代码中是否有 "wrong"。

Is it conventional to do this? Or should I keep all code and methods inside of their respective Activities, or is it conventional to move them to their own class, and access them from whichever Activity needs it?

绝对使用通用软件工程原则和最佳实践。设计 class 有针对性并服务于特定目的的内容。您应该查看新的 Architecture Components 库。这具有允许您创建 "life cycle aware" classes 的工具。这些 classes 可以负责处理它们自己资源的生命周期事件,而不是通过管理资源来污染 Activity。

评论

通常,您不应在 activity 生命周期之外初始化 Activity class 的字段。当您依赖仅在生命周期中特定时间可用的资源(例如视图)时,这可能会导致问题。在这种情况下,初始化 Streaming 对象与其声明内联可能不会导致任何问题。仍然最好养成将 onCreate() 视为 "constructor" 的习惯,并改为在此方法中进行所有初始化。