调用服务时Android UI冻结

时间:2016-02-16 04:28:25

标签: android android-asynctask android-service android-mediaplayer shoutcast

我开发了在线广播应用。我通过服务打电话给shoutcast无线电服务器。当我调用服务时,所有UI控件都被冻结,因此我使用了ProgressDialog但仍然冻结并且没有显示进度对话框。我使用过AsyncTask但没有工作。

HomeFragment.java
在按钮onClick事件中,执行CallingStreamServer AsyncTask。

public class CallingStreamServer extends AsyncTask<Void, Void, Void>{

    @Override
    protected void onPreExecute() {
        // TODO Auto-generated method stub
        super.onPreExecute();
        progressDialog = new ProgressDialog(getActivity());
        progressDialog.setTitle("Please Wait");
        progressDialog.setMessage("Connecting Radio Station ...");
        progressDialog.setIndeterminate(true);
        progressDialog.setCancelable(false);
        progressDialog.show();
        //progressDialog = ProgressDialog.show(getActivity(), "Please Wait", "Connecting Radio Station ...");

    }

    @Override
    protected Void doInBackground(Void... params) {
        // TODO Auto-generated method stub          
        getActivity().startService(new Intent(getActivity(), StreamService.class));
        return null;
    }

    @Override
    protected void onPostExecute(Void result) {
        // TODO Auto-generated method stub
        progressDialog.dismiss();
        super.onPostExecute(result);
    }
}

StreamService.java
StreamService创建媒体播放器并连接shoutcast无线电服务器。

@Override
public void onCreate() {
    // TODO Auto-generated method stub
    super.onCreate();
    Log.d(TAG, "onCreate");     
    try {
        prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
        sharedPreEditor = prefs.edit();

        notiManager = (NotificationManager)getApplicationContext().getSystemService(NOTIFICATION_SERVICE);
        Context context = getApplicationContext();

        String notiTitle = context.getResources().getString(R.string.app_name);
        String notiMsg = "Connecting ... ";

        Intent mainActivity = new Intent(context, MainActivity.class);
        PendingIntent pIntent = PendingIntent.getActivity(context, 0, mainActivity, 0);

        noti = new Notification.Builder(context)
                .setContentTitle(notiTitle)
                .setContentText(notiMsg)    
                .setSmallIcon(R.drawable.ic_launcher)
                .setContentIntent(pIntent)
                .build();

        notiManager.notify(notiID, noti);

        String url = prefs.getString("streamURL", "");
        mediaPlayer = new MediaPlayer();
        mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
        mediaPlayer.setDataSource(url);
        mediaPlayer.prepare();

    } catch (Exception e) {
        // TODO: handle exception
        Log.e(TAG, "onCreate Method : " + e.getMessage());          


    }
}

@Override
@Deprecated
public void onStart(Intent intent, int startId) {
    // TODO Auto-generated method stub

    super.onStart(intent, startId);
    Log.d(TAG, "onStart");

    try {

        mediaPlayer.start();
        sharedPreEditor.putBoolean("isPlaying", true);
        sharedPreEditor.commit();

        Context context = getApplicationContext();
        String notiTitle = context.getResources().getString(R.string.app_name);
        String notiMsg = prefs.getString("displayStation", "") + " radio is now playing.";

        Intent _intent = new Intent(context, MainActivity.class);
        PendingIntent pIntent = PendingIntent.getActivity(context, 0, _intent, 0);

        noti = new Notification.Builder(context)                
                .setContentTitle(notiTitle)
                .setContentText(notiMsg)
                .setSmallIcon(R.drawable.ic_launcher)   
                .setContentIntent(pIntent)              
                .build();

        noti.flags = Notification.FLAG_NO_CLEAR;

        notiManager.notify(notiID, noti);

    } catch (Exception e) {
        Log.e(TAG, "onStart Method : " + e.getMessage());
    }
}

@Override
public void onDestroy() {
    // TODO Auto-generated method stub
    Log.d(TAG, "onDestroy");
    mediaPlayer.stop();
    mediaPlayer.release();
    mediaPlayer = null;
    sharedPreEditor.putBoolean("isPlaying", false);
    sharedPreEditor.commit();       
    notiManager.cancel(notiID);
    stopSelf();
}

3 个答案:

答案 0 :(得分:2)

我为我的问题做了一些伎俩。在服务onCreate事件中,mediaPlayer.prepare()被冻结用于从@Doug Stevenson识别出的点。因此我在服务中为mediaPlayer.prepare()和mediaPlayer.start()创建了1 线程。我使用 BroadcastReceiver 进行服务调用和结果。 :)

<强> HomeFragment.java
注册BroadcastReceiver和按钮onClick事件发送到BroadcastReceiver进行服务调用

@Override
public void onClick(View v) {
    if (v.getId() == butBoxOfMusic.getId()) {
        Intent intent = new Intent();
        intent.setAction(ACTION_STREAM_RECEIVER);
        intent.putExtra("result", "start");
        getActivity().sendBroadcast(intent);
    }
}


public class StreamServiceReceiver extends BroadcastReceiver{

    @Override
    public void onReceive(Context context, Intent intent) {
        // TODO Auto-generated method stub

        if (intent.getStringExtra("result").equals("start")) {
            /// Calling service(call from onClick event)
            progressDialog = ProgressDialog.show(getActivity(), "Please Wait", "Connecting Radio Station ...");
            getActivity().startService(new Intent(getActivity(), StreamService.class));
        }else{
            /// Streaming playing(result from service)
            progressDialog.dismiss();
        }

    }

}

StreamService.java
StreamService创建媒体播放器并连接shoutcast无线电服务器。

    @Override
    public void onCreate() {
        // TODO Auto-generated method stub
        super.onCreate();
        Log.d(TAG, "onCreate");     
        try {
            prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
            sharedPreEditor = prefs.edit();

            notiManager = (NotificationManager)getApplicationContext().getSystemService(NOTIFICATION_SERVICE);
            Context context = getApplicationContext();

            String notiTitle = context.getResources().getString(R.string.app_name);
            String notiMsg = "Connecting ... ";

            Intent mainActivity = new Intent(context, MainActivity.class);
            PendingIntent pIntent = PendingIntent.getActivity(context, 0, mainActivity, 0);

            noti = new Notification.Builder(context)
                    .setContentTitle(notiTitle)
                    .setContentText(notiMsg)    
                    .setSmallIcon(R.drawable.ic_launcher)
                    .setContentIntent(pIntent)
                    .build();

            notiManager.notify(notiID, noti);

            String url = prefs.getString("streamURL", "");
            mediaPlayer = new MediaPlayer();
            mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
            mediaPlayer.setDataSource(url);

//          mediaPlayer.prepare();

        } catch (Exception e) {
            // TODO: handle exception
            Log.e(TAG, "onCreate Method : " + e.getMessage());          


        }
    }

    @Override
    @Deprecated
    public void onStart(Intent intent, int startId) {
        // TODO Auto-generated method stub

        super.onStart(intent, startId);
        Log.d(TAG, "onStart");

        try {

            Thread thread = new Thread("MediaPlayer" + String.valueOf(startId)){
                @Override
                public void run() {
                    // TODO Auto-generated method stub
                    super.run();
                    try {
                        mediaPlayer.prepare();
                        mediaPlayer.start();                        

                        sharedPreEditor.putBoolean("isPlaying", true);
                        sharedPreEditor.commit();

                        Context context = getApplicationContext();
                        String notiTitle = context.getResources().getString(R.string.app_name);
                        String notiMsg = prefs.getString("displayStation", "") + " radio is now playing.";

                        Intent _intent = new Intent(context, MainActivity.class);
                        PendingIntent pIntent = PendingIntent.getActivity(context, 0, _intent, 0);

                        noti = new Notification.Builder(context)                
                                .setContentTitle(notiTitle)
                                .setContentText(notiMsg)
                                .setSmallIcon(R.drawable.ic_launcher)   
                                .setContentIntent(pIntent)              
                                .build();

                        noti.flags = Notification.FLAG_NO_CLEAR;

                        notiManager.notify(notiID, noti);

                        /// Send reslt to BroadcastReceiver /// 
                        Intent intent = new Intent();
                        intent.setAction(HomeFragment.ACTION_STREAM_RECEIVER);
                        intent.putExtra("result", "Playing");
                        sendBroadcast(intent);                      

                    } catch (IllegalStateException | IOException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
            };

            thread.start();



        } catch (Exception e) {
            Log.e(TAG, "onStart Method : " + e.getMessage());
        }
    }

答案 1 :(得分:1)

Android服务onCreate总是在主线程上运行,因此它将阻止主线程上的其他内容,例如UI和动画。默认情况下,Service类不提供任何线程,因此如果您需要,您必须自己提供。

因此,您需要一种策略,将服务onCreate中的所有阻塞工作从主线程移到其他线程中。特别是,mediaPlayer.prepare()将阻塞一段未知的时间。

答案 2 :(得分:0)

MediaPlayer.prepare()可能不会立即返回,因此会阻止您的UI线程。尝试使用MediaPlayer.prepareAsync()并实现OnPreparedListerner接口,以便在MediaPlayer准备好后接收回调。

http://developer.android.com/reference/android/media/MediaPlayer.OnPreparedListener.html