Ошибка службы Android для пользовательского интерфейса - PullRequest
0 голосов
/ 29 января 2012

Я получаю ошибки / исключения на своем сервисе, которые я использую для потоковой передачи shoutcast. Я хотел бы показать ошибку в потоке пользовательского интерфейса, если генерируется какое-либо исключение, например, если музыкальный поток не работает.

Как это можно сделать, вот мой текущий код.

Класс пользовательского интерфейса:

private OnClickListener btnStopListener = new OnClickListener() {
    public void onClick(View v) {

        if (MyService.isRunning()) {

            doUnbindService();
            stopService(new Intent(MainActivity.this, MyService.class));

            btnStop.setBackgroundResource(R.drawable.player_play);

            barLoader.setVisibility(View.GONE);

        } else {

            Intent intent = new Intent(MainActivity.this, MyService.class);

            intent.putExtra("streamUrl", strLinkUrl);

            startService(intent);

            doBindService();

        }

    }
};

void doBindService() {
    bindService(new Intent(this, MyService.class), mConnection,
            Context.BIND_AUTO_CREATE);
    mIsBound = true;

}

void doUnbindService() {
    if (mIsBound) {
        // If we have received the service, and hence registered with it,
        // then now is the time to unregister.
        if (mService != null) {
            try {
                Message msg = Message.obtain(null,
                        MyService.MSG_UNREGISTER_CLIENT);
                msg.replyTo = mMessenger;
                mService.send(msg);
            } catch (RemoteException e) {
                // There is nothing special we need to do if the service has
                // crashed.
            }
        }
        // Detach our existing connection.
        unbindService(mConnection);
        mIsBound = false;

    }
}

Класс обслуживания:

public class MyService extends Service implements

OnPreparedListener, OnErrorListener { public String txtBTitle, txtBChannel, txtBDescription, txtBTitleNow, txtBImageUrl, txtBLinkUrl; частный NotificationManager nm;

private static boolean isRunning = false;

private Timer timer1 = new Timer();

String strTitle,strArtist;

MediaPlayer mediaPlayer = new MediaPlayer();


ArrayList<Messenger> mClients = new ArrayList<Messenger>(); // Keeps track of all current registered clients.

int mValue = 0; // Holds last value set by a client.
static final int MSG_REGISTER_CLIENT = 1;
static final int MSG_UNREGISTER_CLIENT = 2;
static final int MSG_SET_INT_VALUE = 3;
static final int MSG_SET_STRING_VALUE = 4;

String strUrl;

final Messenger mMessenger = new Messenger(new IncomingHandler()); // Target we publish for clients to send messages to IncomingHandler.


@Override
public IBinder onBind(Intent intent) {
    return mMessenger.getBinder();
}


class IncomingHandler extends Handler { // Handler of incoming messages from clients.
    @Override
    public void handleMessage(Message msg) {
        switch (msg.what) {
        case MSG_REGISTER_CLIENT:
            mClients.add(msg.replyTo);
            break;
        case MSG_UNREGISTER_CLIENT:
            mClients.remove(msg.replyTo);
            break;
        case MSG_SET_INT_VALUE:
           // incrementby = msg.arg1;
            break;
        default:
            super.handleMessage(msg);
        }
    }
}


private void sendMessageToUI(int intvaluetosend) {
    for (int i=mClients.size()-1; i>=0; i--) {
        try {
            // Send data as an Integer
            mClients.get(i).send(Message.obtain(null, MSG_SET_INT_VALUE, intvaluetosend, 0));

            //Send data as a String
            Bundle b = new Bundle();
            b.putString("str1",strTitle+"\n"+strArtist);

            b.putString("strUrl", strUrl);


            Message msg = Message.obtain(null, MSG_SET_STRING_VALUE);
            msg.setData(b);
            mClients.get(i).send(msg);

        } catch (RemoteException e) {
            // The client is dead. Remove it from the list; we are going through the list from back to front so this is safe to do inside the loop.
            mClients.remove(i);
        }
    }
}


@Override
public void onCreate() {
    super.onCreate();
    Log.i("MyService", "Service Started.");
    showNotification();

    isRunning = true;
}
private void showNotification() {
    nm = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
    // In this sample, we'll use the same text for the ticker and the expanded notification
    CharSequence text = getText(R.string.service_started);
    // Set the icon, scrolling text and timestamp
    Notification notification = new Notification(R.drawable.icon, text, System.currentTimeMillis());
    // The PendingIntent to launch our activity if the user selects this notification
    PendingIntent contentIntent = PendingIntent.getActivity(this, 0, new Intent(this, MainActivity.class).putExtra("fromWhere", "fromService"), 0);
    // Set the info for the views that show in the notification panel.
    notification.setLatestEventInfo(this, getText(R.string.service_label), text, contentIntent);
    // Send the notification.
    // We use a layout id because it is a unique number.  We use it later to cancel.
    nm.notify(R.string.service_started, notification);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {



    strUrl = intent.getExtras().getString("streamUrl");

    Log.i("ZealDeveloper", strUrl);


    if(!mediaPlayer.isPlaying()){   

    mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
    try {
        mediaPlayer.setDataSource(strUrl);
        mediaPlayer.setOnPreparedListener(this);

    } catch (IllegalArgumentException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (IllegalStateException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    mediaPlayer.prepareAsync(); // might take long! (for buffering, etc)
    // mediaPlayer.start();

    }

    timer1.scheduleAtFixedRate(new TimerTask(){ public void run() {onMetaParser();}

    }, 0, 100000L);

    Log.i("MyService", "Received start id " + startId + ": " + intent);


    return START_STICKY; // run until explicitly stopped.
}

public static boolean isRunning()
{
    return isRunning;
}




//Meta Parser
private void onMetaParser() {
    // TODO Auto-generated method stub

    URL url;

    try {
        url = new URL(strUrl);
        IcyStreamMeta icy = new IcyStreamMeta(url);

        try{
        strTitle = icy.getTitle();
        }
        catch (NullPointerException e) {
            strTitle="";
        }
        try{
        strArtist = icy.getArtist();
        }
        catch (NullPointerException e) {
            strArtist = "";
        }
        System.out.println("Title : " + strTitle + strUrl);


        System.gc();

    //  txtTitleNow.setText(T);

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

}


@Override
public void onDestroy() {
    super.onDestroy();

    if (mediaPlayer.isPlaying()) {
        mediaPlayer.release();      
    }


    if (timer1 != null) {timer1.cancel();

    Log.i("ZealDeveloper", "Timer 1 Cancled");}

    nm.cancel(R.string.service_started); // Cancel the persistent notification.


    Log.i("MyService", "Service Stopped.");
    isRunning = false;


    try {

        timer1.cancel();
        mediaPlayer.release();
        mediaPlayer = null;

    } catch (Exception e) {

        e.printStackTrace();


    }

}

@Override
public void onPrepared(MediaPlayer mp) {
    // TODO Auto-generated method stub
    mp.start();

    sendMessageToUI(0);

}


@Override
public boolean onError(MediaPlayer mp, int what, int extra) {
    // TODO Auto-generated method stub

    mediaPlayer.release();
    timer1.cancel();    
    return false;}}

Трассировка стека:

01-30 11:03:32.470: W/System.err(311): java.io.FileNotFoundException: http://xxxxxstream
01-30 11:03:32.480: E/MediaPlayer(311): error (1, -1004)
01-30 11:03:32.490: W/System.err(311):  at org.apache.harmony.luni.internal.net.www.protocol.http.HttpURLConnectionImpl.getInputStream(HttpURLConnectionImpl.java:1162)
01-30 11:03:32.500: W/System.err(311):  at com.sikhnetRadio.test.IcyStreamMeta.retreiveMetadata(IcyStreamMeta.java:91)
01-30 11:03:32.500: W/System.err(311):  at com.sikhnetRadio.test.IcyStreamMeta.refreshMeta(IcyStreamMeta.java:79)
01-30 11:03:32.500: W/System.err(311):  at com.sikhnetRadio.test.IcyStreamMeta.getMetadata(IcyStreamMeta.java:72)
01-30 11:03:32.500: W/System.err(311):  at com.sikhnetRadio.test.IcyStreamMeta.getTitle(IcyStreamMeta.java:60)
01-30 11:03:32.500: W/System.err(311):  at com.sikhnetRadio.test.MyService.onMetaParser(MyService.java:192)
01-30 11:03:32.510: W/System.err(311):  at com.sikhnetRadio.test.MyService.access$0(MyService.java:182)
01-30 11:03:32.510: W/System.err(311):  at com.sikhnetRadio.test.MyService$1.run(MyService.java:163)
01-30 11:03:32.510: W/System.err(311):  at java.util.Timer$TimerImpl.run(Timer.java:289)
01-30 11:03:32.610: E/MediaPlayer(311): Error (1,-1004)

Ответы [ 2 ]

5 голосов
/ 29 января 2012

Два варианта

1) Вы можете создать традиционный приемник типа Java (интерфейс, который будет переопределять ваша активность) и передать его в службу через интерфейс Ibinder.

2) Реализовать приемник вещания вваша деятельность похожа на this (здесь это сделано для Intentservice, надеюсь, вам не составит труда сделать то же самое для servie).

1 голос
/ 31 января 2012

Таймер не является потокобезопасным в пользовательском интерфейсе.Вместо этого вы должны использовать Handler.

В качестве примера я бы предложил свой класс утилит Clock.Я использую это сам в работе.Это богато прокомментировано.

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import android.os.Handler;
import android.widget.TextView;
/**
 * The class for creating and refreshing many different fields on different layouts,
 * that can hold actual time and/or date in different formats 
 * The formats should be as in http://developer.android.com/reference/java/text/SimpleDateFormat.html. 
 * Only present and visible fields are being actualized, so there is no need to clean the clock list after closing an activity
 * 
 * Examples of use:
 * 
 *      Clock.registerClock((TextView) findViewById(R.id.TimeField), "HH:mm");
 *      Clock.registerClock((TextView) findViewById(R.id.DateField), "d.M.yyyy EEE");
 *      Clock.start(10000L);
 *
 * @author Petr Gangnus
 */
public final class Clock {
    /**
     * the handler that works instead of timer and supports UI
     */
    static private Handler handler = new Handler();
    /**
     * the interval of the time refreshing
     */
    static private long refreshStep;

    /**
     * pairs TextView clockFace + time/date format
     */
    private TextView clockFace;
    private String format;
    private Clock(TextView clockFace, String format){
        this.clockFace=clockFace;
        this.format=format;
    }
    // here is the list of views containing the visual timers that should be held actual
    static private ArrayList<Clock> clocks=new ArrayList<Clock>();
    /**
     * fills all timer fields by actual time value, according to their formats.
     */
    static private Runnable mUpdateTimeTask = new Runnable() {
       public void run() {
           for(Clock clock:clocks){
               showActualTimeDate(clock);
           }
           handler.postDelayed(this,refreshStep);
       }
    };

    //============================================ public members ====================================================================
    /**
     * add a clock to the list of updating clocks
     * @param clockFace - the place where the time or date will be shown 
     * @param format - the format of the time/date 
     * @return
     */
    public static boolean registerClock(TextView clockFace, String format){
        if (clockFace==null) return false;
        if(clocks.contains(clockFace)){
            // old clockFace
            clocks.get(clocks.indexOf(clockFace)).format=format;
        } else {
            // new clockFace
            clocks.add(new Clock(clockFace, format));
        }
        return true;
    }
    /**
     * remove a clock from the updating list
     * @param clockFace
     * @return
     */
    public static boolean unRegisterClock(TextView clockFace){
        if (clockFace==null) return false;
        if(clocks.contains(clockFace)){
            // found clockFace
            clocks.remove(clocks.indexOf(clockFace));
        } else {
            // not found clockFace
            return false;
        }
        return true;
    }
    /**
     * put in the "place" the actual date/time in the appropriate "format"
     * @param place
     * @param format
     */
    public static void showActualTimeDate(Clock clock){
        if (clock.clockFace==null) return;
        if (clock.clockFace.getVisibility()!=TextView.VISIBLE) return;
        Date thisDate=new Date();
        SimpleDateFormat df=new SimpleDateFormat(clock.format);
        clock.clockFace.setText(df.format(thisDate));
    }
    /**
     * start the ticking for all clocks
     * @param step the tick interval
     */
    public static void start(long step) { 
        refreshStep=step;
        handler.removeCallbacks(mUpdateTimeTask);
        handler.postDelayed(mUpdateTimeTask, 0);
    }
    /**
     * Stopping ticking all clocks (not removing them)
     * the calling could be put somewhere in onStop
     */
    public static void stop() { 
        handler.removeCallbacks(mUpdateTimeTask);
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...