2017-01-28 13 views
9

Piszę aplikację timera, z usługą i sygnałem dźwiękowym co 30 sekund (w rzeczywistości jest to dropdown, który zmienia ten czas).ToneGenerator spowalnia aplikację bardzo mocno

Jednak po wygenerowaniu sygnału dźwiękowego aplikacji sygnał dźwiękowy trwa bardzo długo i powoduje zatrzymanie aplikacji, ostatecznie (po około 5 sekundach) kończy się, a następnie odliczanie czasu. Dlaczego to się dzieje? Jak to naprawić? Tu jest mój kodu:

MainActivity.java:

package com.example.servicetimer; 

import android.content.BroadcastReceiver; 
import android.content.Context; 
import android.content.Intent; 
import android.content.IntentFilter; 
import android.media.AudioManager; 
import android.media.MediaPlayer; 
import android.media.Ringtone; 
import android.media.RingtoneManager; 
import android.media.ToneGenerator; 
import android.net.Uri; 
import android.os.Vibrator; 
import android.support.v7.app.AppCompatActivity; 
import android.os.Bundle; 
import android.view.View; 
import android.widget.AdapterView; 
import android.widget.ArrayAdapter; 
import android.widget.Button; 
import android.widget.Spinner; 
import android.widget.TextView; 

public class MainActivity extends AppCompatActivity { 
    private Button startButton; 
    private Button pauseButton; 
    private Button resetButton; 

    private TextView timerValue; 
    private TextView timerValueMils; 

    private long miliTime; 

    private int beepTime = 0; 

    private boolean running = false; 
    private boolean beep = false; 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_main); 
     miliTime = 0L; 
     timerValue = (TextView) findViewById(R.id.timerValue); 
     timerValueMils = (TextView) findViewById(R.id.timerValueMils); 

     registerReceiver(uiUpdated, new IntentFilter("TIMER_UPDATED")); 

     startButton = (Button) findViewById(R.id.startButton); 

     startButton.setOnClickListener(new View.OnClickListener() { 

      public void onClick(View view) { 
       if (running){ 
        return; 
       } 
       Intent i = new Intent(MainActivity.this,LocalService.class); 
       i.putExtra("timer",miliTime); 

       startService(i); 
       running = true; 
       resetButton.setVisibility(View.GONE); 
      } 
     }); 

     pauseButton = (Button) findViewById(R.id.pauseButton); 

     pauseButton.setOnClickListener(new View.OnClickListener() { 

      public void onClick(View view) { 
       if(!running){ 
        return; 
       } 
       running = false; 
       stopService(new Intent(MainActivity.this, LocalService.class)); 
       resetButton.setVisibility(View.VISIBLE); 
      } 
     }); 

     resetButton = (Button) findViewById(R.id.resetButton); 

     resetButton.setOnClickListener(new View.OnClickListener() { 

      public void onClick(View view) { 
       stopService(new Intent(MainActivity.this, LocalService.class)); 
       running = false; 
       miliTime = 0L; 
       ((TextView) findViewById(R.id.timerValue)).setText(R.string.timerVal); 
       ((TextView) findViewById(R.id.timerValueMils)).setText(R.string.timerValMils); 
       beep = false; 
      } 
     }); 

     Spinner dropdown = (Spinner)findViewById(R.id.spinner1); 
     ArrayAdapter<CharSequence> adapter = ArrayAdapter 
       .createFromResource(this, R.array.times, 
         android.R.layout.simple_spinner_item); 
     dropdown.setAdapter(adapter); 
     dropdown.setSelection(1); 

     adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); 

     dropdown.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { 

      @Override 
      public void onItemSelected(AdapterView<?> parent, View view, 
             int position, long id) { 
       // On selecting a spinner item 
       String label = parent.getItemAtPosition(position).toString(); 
       beepTime = Integer.parseInt(label); 
      } 

      public void onNothingSelected(AdapterView<?> parent) { 
       beepTime = 30; 
      } 
     }); 

    } 

    private BroadcastReceiver uiUpdated = new BroadcastReceiver() { 

     @Override 
     public void onReceive(Context context, Intent intent) { 
      //This is the part where I get the timer value from the service and I update it every second, because I send the data from the service every second. The coundtdownTimer is a MenuItem 
      miliTime = intent.getExtras().getLong("timer"); 
      long secs = miliTime/1000; 
      int mins = (int) (secs/60); 
      secs = secs % 60; 
      if (secs > 0) 
       beep = true; 
      if ((secs % beepTime == 0) && beep) 
       beep(); 
      int millis = (int) (miliTime % 1000); 

      timerValue.setText("" + mins + " " 
        + String.format("%02d", secs)); 
      timerValueMils.setText(String.format("%02d", millis/10)); 


     } 

     public void beep(){ 
      /*try { 
       Uri notification = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION); 
       Ringtone r = RingtoneManager.getRingtone(getApplicationContext(), notification); 
       r.play(); 
      } catch (Exception e) { 
       e.printStackTrace(); 
      }*/ 

      final ToneGenerator tg = new ToneGenerator(AudioManager.STREAM_NOTIFICATION, 100); 
      tg.startTone(ToneGenerator.TONE_PROP_BEEP,100); 
      tg.stopTone(); 
      tg.release(); 
      /*ToneGenerator toneG = new ToneGenerator(AudioManager.STREAM_ALARM, 100); 
      toneG.startTone(ToneGenerator.TONE_CDMA_ALERT_CALL_GUARD, 200);*/ 
      Vibrator v = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE); 
      // Vibrate for 500 milliseconds 
      v.vibrate(500); 
     } 
    }; 


} 

LocalService.java:

package com.example.servicetimer; 

import android.app.Service; 
import android.content.Context; 
import android.content.Intent; 
import android.os.IBinder; 
import android.widget.Toast; 

import java.util.Timer; 
import java.util.TimerTask; 

public class LocalService extends Service 
{ 
    private static Timer timer; 
    private Context ctx; 
    private static long miliTime = 0; 

    public IBinder onBind(Intent arg0) 
    { 
     return null; 
    } 

    public void onCreate() 
    { 
     timer = new Timer(); 
     super.onCreate(); 
     ctx = this; 
     miliTime = 0; 
    } 

    @Override 
    public int onStartCommand(Intent intent, int flags, int startId) { 
     miliTime = intent.getExtras().getLong("timer"); 
     timer = new Timer(); 
     timer.scheduleAtFixedRate(new mainTask(), 0, 10); 
     return START_STICKY; 
    } 

    private class mainTask extends TimerTask 
    { 
     public void run() 
     { 
      miliTime += 10; 
      Intent i = new Intent("TIMER_UPDATED"); 
      i.putExtra("timer",miliTime); 

      sendBroadcast(i); 
     } 
    } 

    public void onDestroy() { 
     super.onDestroy(); 
     timer.cancel(); 
     miliTime = 0L; 
    } 
} 

activity_main.xml:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    xmlns:tools="http://schemas.android.com/tools" 
    android:layout_width="match_parent" 
    android:background="@drawable/silver" 
    android:layout_height="match_parent" > 

    <TextView 
     android:id="@+id/timerValue" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:layout_above="@+id/pauseButton" 
     android:layout_centerHorizontal="true" 
     android:layout_marginBottom="37dp" 
     android:textSize="40sp" 
     android:textColor="#000000" 
     android:text="@string/timerVal" /> 

    <TextView 
     android:id="@+id/timerValueMils" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:layout_toRightOf="@+id/timerValue" 
     android:layout_toEndOf="@+id/timerValue" 
     android:layout_above="@+id/pauseButton" 
     android:layout_centerHorizontal="true" 
     android:layout_marginBottom="45dp" 
     android:layout_marginLeft="10dp" 
     android:layout_marginStart="10dp" 
     android:textSize="20sp" 
     android:textColor="#000000" 
     android:text="@string/timerValMils" /> 

    <Button 
     android:id="@+id/startButton" 
     android:layout_width="90dp" 
     android:layout_height="45dp" 
     android:layout_alignParentLeft="true" 
     android:layout_alignParentStart="true" 
     android:layout_centerVertical="true" 
     android:layout_marginLeft="38dp" 
     android:layout_marginStart="38dp" 
     android:text="@string/startButtonLabel" /> 

    <Button 
     android:id="@+id/pauseButton" 
     android:layout_width="90dp" 
     android:layout_height="45dp" 
     android:layout_alignBaseline="@+id/startButton" 
     android:layout_alignBottom="@+id/startButton" 
     android:layout_alignParentRight="true" 
     android:layout_alignParentEnd="true" 
     android:layout_marginRight="38dp" 
     android:layout_marginEnd="38dp" 
     android:text="@string/pauseButtonLabel" /> 

    <RelativeLayout android:id="@+id/dropdown" 
     android:layout_width="match_parent" 
     android:layout_height="wrap_content" 
     android:layout_below="@id/pauseButton" 
     android:layout_marginTop="37dp"> 

     <TextView 
      android:id="@+id/secondsToBeep" 
      android:layout_width="wrap_content" 
      android:layout_height="wrap_content" 
      android:layout_marginLeft="37dp" 
      android:layout_marginStart="37dp" 
      android:layout_marginEnd="20dp" 
      android:layout_marginRight="20dp" 
      android:textSize="30sp" 
      android:textColor="#000000" 
      android:text="@string/beeps" /> 

     <Spinner 
      android:id="@+id/spinner1" 
      android:dropDownWidth="80dp" 
      android:layout_width="wrap_content" 
      android:layout_height="wrap_content" 
      android:layout_weight="1" 
      android:background="@android:drawable/btn_dropdown" 
      android:layout_alignParentRight="true" 
      android:layout_alignParentEnd="true" 
      android:layout_marginEnd="40dp" 
      android:layout_marginRight="40dp" 
      android:layout_marginLeft="40dp" 
      android:layout_marginStart="40dp" 
      android:spinnerMode="dropdown" 
      android:popupBackground="@drawable/silver"/> 
    </RelativeLayout> 

    <Button 
     android:id="@+id/resetButton" 
     android:layout_width="match_parent" 
     android:layout_height="60dp" 
     android:layout_below="@id/dropdown" 
     android:layout_alignParentRight="true" 
     android:layout_alignParentEnd="true" 
     android:layout_marginTop="50dp" 
     android:text="@string/resetButtonLabel" 
     android:visibility="gone"/> 

</RelativeLayout> 

mogę dodać moje AndroidManifest jeśli to konieczne. Na AndroidStudio na debug daje mi następujące informacje, gdy to się dzieje:

I/Choreographer: Skipped 35 frames! The application may be doing too much work on its main thread. 
I/Choreographer: Skipped 175 frames! The application may be doing too much work on its main thread. 
I/Choreographer: Skipped 44 frames! The application may be doing too much work on its main thread. 

powinienem robić sygnału dźwiękowego w służbie, czy coś?

Dodam, że jestem przekonany, że to jest z ToneGenerator, skomentowałem wszystkie części dźwiękowe i opuściłem wibrator, a kiedy działa, nie ma problemu. Ale ToneGenerator i Ringtone zarówno spowodowany ten problem

Odpowiedz

5

I rzeczywiście odpowiedział na moje własne pytanie, Problemem (w tym przypadku) było to, że zbyt często dzwoniłem pod numer beep()sposób.

Mój kod to:

if ((secs % beepTime == 0) && beep) 
    beep(); 

ale co ja naprawdę chciałem to zrobić obliczeń na milisekund. Sposób, w jaki spowodowałem wywołanie beep() 100 razy (aktualizacja kodu co 10 ms).

0

spróbować tej metody w swojej beep() (uruchomić kod na tle gwintem):

AsyncTask.execute(new Runnable() { 
    @Override 
    public void run() { 
      final ToneGenerator tg = new ToneGenerator(AudioManager.STREAM_NOTIFICATION, 100); 
      tg.startTone(ToneGenerator.TONE_PROP_BEEP,100); 
      tg.stopTone(); 
      tg.release(); 
      /*ToneGenerator toneG = new ToneGenerator(AudioManager.STREAM_ALARM, 100); 
      toneG.startTone(ToneGenerator.TONE_CDMA_ALERT_CALL_GUARD, 200);*/ 
      Vibrator v = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE); 
      // Vibrate for 500 milliseconds 
      v.vibrate(500); 
    } 
}); 

AsyncTask umożliwia prawidłowe i łatwe korzystanie z wątku UI.

Czy powinienem wykonywać sygnał dźwiękowy w usłudze?

Jak nie masz kodu UI w beep(), lepiej byłoby to zrobić w LocalService.java jak łatwiej jest zarządzać.

0

można użyć wątku:

Thread thread = new Thread(new Runnable() { 
    public void run() { 
     // your beep method 
    }); 

Ponieważ używasz tego samego sygnału dźwiękowego, trzeba tylko użyć thread.start() zadzwonić sposób sygnał:

// make a new thread for beep only once. 
Thread beepThread = new Thread(new Runnable() { 
    public void run() { 
     // call beep() method here 
     beep(); 
    }); 


// move the beep method from BroadcastReceiver 
public void beep() { 
    // your code implementation. 
    ... 
} 


private BroadcastReceiver uiUpdated = new BroadcastReceiver() { 

     @Override 
     public void onReceive(Context context, Intent intent) { 
      //This is the part where I get the timer value from the service and I update it every second, because I send the data from the service every second. The coundtdownTimer is a MenuItem 
      miliTime = intent.getExtras().getLong("timer"); 
      long secs = miliTime/1000; 
      int mins = (int) (secs/60); 
      secs = secs % 60; 
      if (secs > 0) 
       beep = true; 
      if ((secs % beepTime == 0) && beep) 

       // Call the thread here. 
       beepThread.start(); 

      int millis = (int) (miliTime % 1000); 

      timerValue.setText("" + mins + " " 
        + String.format("%02d", secs)); 
      timerValueMils.setText(String.format("%02d", millis/10)); 


     } 
    ... 
} 
Powiązane problemy