Im working on music player for Android and I need to get static time to start playing music. Acutally command context.player.start() take random time from range <2;20> [ms] but I need to get static time of accomplishing method. My code is below. I mean that time difference between "before call method time" and "just after method accomplished time" need to be static (method should take static time)
public class SpeakerActivity extends AppCompatActivity {
MusicPlayer player;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_speaker);
player = new MusicPlayer(SpeakerActivity.this);
run();
}
private void run() {
AsyncTask.execute(new Runnable() {
#Override
public void run() {
ClientTask ct = new ClientTask(SpeakerActivity.this);
try {
ct.run();
} catch (IOException e1) {
e1.printStackTrace();
}
}
});
}
}
public class ClientTask extends Listener {
ClientTask(Context context) { this.context = context);}
...
//I'm only going to implement this method from Listener.class because I only need to use this one.
public void received(Connection c, Object p){
//Is the received packet the same class as PacketMessage.class?
if(p instanceof PacketMessage){
//Cast it, so we can access the message within.
PacketMessage packet = (PacketMessage) p;
if(packet.message.charAt(0) == 'p') {
String latencyString = packet.message.replace('p','0');
int latency = Integer.parseInt(latencyString);
try {
Thread.sleep(latency);
context.player.start(); <---- THIS LINE TAKE RANDOM AMOUNT OF TIME
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
public class MusicPlayer {
private MediaPlayer player;
private Context context;
public MusicPlayer(Context context) {
this.context = context;
player = MediaPlayer.create(context, R.raw.zero);
}
public void start() {
player.start();
}
public void stop() {
player.stop();
}
}
Does anybody know whats wrong?
Related
I am working on a game project. I want to associate each view of my game to its respective thread and then update the view according to the logic running in that thread.
To simplify, I am posting a sample:
This is Main Activity class, which will implement the UI:
public class Main extends Activity{
private View root;
private boolean ready = false;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
init();
}
private void init() {
setContentView(R.layout.s_main);
root = findViewById(R.id.root);
ViewTreeObserver vto = root.getViewTreeObserver();
vto.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
#Override
public boolean onPreDraw() {
root.getViewTreeObserver().removeOnPreDrawListener(this);
ready = true;
return true;
}
});
}
public void start(View view) {
try {
if (ready && !Threads.run) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
new AsyncTasks(this, R.id.txv1).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
new AsyncTasks(this, R.id.txv2).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
} else {
new AsyncTasks(this, R.id.txv1).execute();
new AsyncTasks(this, R.id.txv2).execute();
}
} else {
Threads.run = false;
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
This is AsyncTask extended class to update View:
public class AsyncTasks extends AsyncTask<Void, Void, String> {
private TextView view;
private boolean breakMove;
private String updateError;
public AsyncTasks(Activity activity, int viewId) {
breakMove = false;
updateError = null;
view = activity.findViewById(viewId);
}
#Override
protected String doInBackground(Void... voids) {
String message;
Threads.run = true;
try {
while (!breakMove) {
publishProgress();
Thread.sleep(100);
}
message = updateError != null ? updateError : "Thread Ends";
} catch (Exception ex) {
ex.printStackTrace();
message = ex.getMessage();
}
return message;
}
#Override
protected void onProgressUpdate(Void... values) {
super.onProgressUpdate(values);
try {
breakMove = !Threads.run;
if (view != null)
view.setText(String.valueOf(Math.random() * 100));
} catch (Exception ex) {
breakMove = true;
ex.printStackTrace();
updateError = ex.getMessage();
}
}
#Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
Threads.run = false;
}
}
This works good. But there are limitations:
AsyncTask is recommended for short duration threads, not for Game or Long Running Thread projects.
In latest android frameworks, only 5 AsyncTask threads can run simultaneously and rest will be in waiting queue. So it will not work if my project requires more than 5 views to update simultaneously.
What I have tried:
Rest of other Thread implementations like Runnable, Handler, Service etc. don't allow to update views. Please keep in mind that my threads are coded in separate external files or classes.
runOnUiThread is not recommended since it runs on UI thread so it will make Main thread busy all time and also it's output is noticeable after the thread which called it, ends.
I am looking for a simple clean solution like I have coded above to implement Updation of Multiple Views through Multiple Threads.
Thanks in advance
I found a solution. Simple and clean:
public class Main extends Activity{
private View root;
private Runs runs;
private boolean ready = false;
private final Context context = this;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
init();
}
private void init() {
setContentView(R.layout.s_main);
runs = new Runs(this);
root = findViewById(R.id.root);
//
ViewTreeObserver vto = root.getViewTreeObserver();
vto.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
#Override
public boolean onPreDraw() {
root.getViewTreeObserver().removeOnPreDrawListener(this);
ready = true;
return true;
}
});
}
private void startRuns() {
try {
runs.run();
Threads.run = true;
} catch (Exception ex) {
Alerts.alert(context, ex.getMessage());
}
}
public void start(View view) {
try {
if (ready && !Threads.run) {
startRuns();
} else {
Threads.pause = !Threads.pause;
}
} catch (Exception ex) {
ex.printStackTrace();
Alerts.alert(context, ex.getMessage());
}
}
}
public class Runs implements Runnable {
private int count;
private Handler handler;
private TextView view1, view2;
public Runs(Activity activity) {
count = 0;
handler = new Handler();
view1 = activity.findViewById(R.id.txv1);
view2 = activity.findViewById(R.id.txv2);
}
#Override
public void run() {
if (!Threads.pause) {
update();
}
handler.postDelayed(this, Threads.sleep);
}
private void update() {
view1.setText(String.valueOf(count++));
view2.setText(String.valueOf(Math.random() * 100));
}
}
I'm creating a music player app in Android and I'm trying to set up the MediaPlayer as a service so that it persists across all Activities/Fragments. The service code:
public class PlayerService extends Service {
MediaPlayer mediaPlayer;
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
mediaPlayer = new MediaPlayer();
}
public void LoadUrl(String url){
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
try {
mediaPlayer.setDataSource(url);
} catch (IOException e) {
e.printStackTrace();
}
try {
mediaPlayer.prepare();
} catch (IOException e) {
e.printStackTrace();
}
//mediaPlayer.start();
Play(mediaPlayer);
}
public void Play(MediaPlayer player) {
player.start();
}
public void Pause(MediaPlayer player) {
player.pause();
}
}
and the MainActivity:
public class MainActivity extends AppCompatActivity {
PlayerService playerService;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if(savedInstanceState != null){
} else {
playerService = new PlayerService();
Intent startPlayer = new Intent(this, PlayerService.class);
startService(startPlayer);
....
When MainActivity is started, it launches the service, however, when I try to load a Url into the MediaPlayer with:
playerService.LoadUrl(feedItem.getAudioUrl());
I get an exception saying that mediaPlayer in the Service is null. How can I make sure that the mediaPlayer is retained?
You are trying to start the service using startService without onStartCommand in service, without which the sevice won't start. So your media player won't get initialized
I'm developing a tracking app. and i have problem with GPS module. The app must record a route. App work fine, but sometimes when the device is not moving, GPS still receive
continuous coordinate that don't indicate my position, error is within a radius of 20 meter, and when I'm moving again work fine.
Please give me some tips that can help me to fix this problem. Thanks a lot.
I have 3 calsses
1 - GPSReceiver here is method for get location
public void getMyLoction(){
_locationManager = (LocationManager) _context.getSystemService(LOCATION_SERVICE);
_isGPSEnabled =_locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
if (_isGPSEnabled) {
if (_location == null) {
_locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,0,0, this);
if (_locationManager != null) {
_location = _locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
setLocation(_location);
}
}
}
}
2 RecordingActivity (take coordonates form services and processes then) work fine, a comment in method what they do.
public class RecordingActivity extends FragmentActivity {
public final static String BROADCAST_ACTION = "map.trackv";
public BroadcastReceiver receiver;
private GoogleMap map;
private TextView _messageToUser;
private Coordinate _pointFromService;
private long _timeWhenStartButtonWasPressed;
private List<Coordinate> _unprocessedCoords;
private List<Coordinate> _processedCoords;
private Button _stopButton;
private Button _startButton;
private String _startRecordingDate;
private String _stopRecordingDate;
private GPSReceiver _gps;
private DataBaseOperations _dataSource;
private boolean _recording;
private boolean _gpsStatus;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_recording_route);
initActvity();
checkIfGPSisOn();
try {
Runtime.getRuntime().exec("logcat -f" + " /sdcard/Logcat.txt");
} catch (IOException e) {
// TODO Auto-generated catch block
Log.d("nu pot", "DDDDD");
e.printStackTrace();
}
receveirWork();
IntentFilter intentFilt = new IntentFilter(BROADCAST_ACTION);
registerReceiver(receiver, intentFilt);
}
public void checkIfGPSisOn() {
//check on start
}
public void receveirWork() {
receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// request points and process then,
}
};
}
#Override
protected void onDestroy() {
super.onDestroy();
if (_stopButton.isEnabled())
{
stopService(new Intent(this, RecordingService.class));
_unprocessedCoords = null;
_processedCoords = null;
}
unregisterReceiver(receiver);
}
#Override
protected void onResume() {
if (!_stopButton.isEnabled()) {
_startButton.setEnabled(true);
_messageToUser.setText(Constants.PRESS_START_BUTTON);
map.clear();
}
super.onResume();
}
// actiune buton start;
public void startButtonEvent(View V) {
buttonsStateAndMessageToShow(false, true, Constants.MESSAGE_TO_WAIT);
_timeWhenStartButtonWasPressed = System.currentTimeMillis();
startService(new Intent(this, RecordingService.class));
// start service to get position
}
public void stopButtonEvent(View V) {
stopService(new Intent(this, RecordingService.class));
// stop service
// save route in BD
// resetData;
}
public void initActvity() {
// init date
}
#Override
protected void onSaveInstanceState(Bundle outState) {
// save state
}
}
3 RecordingServices class, ii think here is the problem.
public class RecordingService extends Service {
private Thread _backgroundWork;
private boolean _threadCanRun;
private GPSReceiver _gps;
private Coordinate _pointToSent;
public void onCreate() {
super.onCreate();
_threadCanRun = true;
_backgroundWork = new Thread(new Runnable() {
#Override
public void run() {
Looper.prepare();
getLocationFromGPS();
Looper.loop();
}
});
}
public int onStartCommand(Intent intent, int flags, int startId) {//
_backgroundWork.start();
return super.onStartCommand(intent, flags, startId);
}
public void onDestroy() {
_threadCanRun = false;
super.onDestroy();
}
public IBinder onBind(Intent intent) {
return null;
}
public void getLocationFromGPS() {
while (_threadCanRun) {
Intent _intent = new Intent(RecordingActivity.BROADCAST_ACTION);
_gps = new GPSReceiver(this);
_gps.getMyLoction();
if (_gps.getIsGPSEnabled()) {
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {}
sentPoint(_intent);
} else {
try {
TimeUnit.MILLISECONDS.sleep(500);
} catch (InterruptedException e) {}
_intent.putExtra("latitude", 0);
_intent.putExtra("longitude", 0);
_intent.putExtra("time", 0);
_intent.putExtra("GPSstatus", false);
sendBroadcast(_intent);
}
}
}
private void sentPoint(Intent _intent) {
_pointToSent = new Coordinate(_gps.getLatitude(), _gps.getLongitude(), _gps.getTime());
_intent.putExtra("latitude", _pointToSent.getLatitude());
_intent.putExtra("longitude", _pointToSent.getlongitude());
_intent.putExtra("time", _pointToSent.getTime());
_intent.putExtra("GPSstatus", _gps.getIsGPSEnabled());
sendBroadcast(_intent);
_pointToSent = null;
}
}
repeating the Location update request depends on how u implemented your tracking system
but in general(which is not recommended , just change your request update rate to save client Battery usage) you can find the distance between your locations by location1.distanceTo(location2) so if the distance is smaller than 30m then put the new location away
I have 4 activities in my android app.When the first activity is created, it starts music in the background. Now when the user goes from 1st activity to the 2nd activity I want the song to continue without any interruption. The song should stop only when the user is out of the app.
Right now the music stops when I am going out of one activity and starts from the beginning in the next activity.
Keep the player in the background as a static reference. Then let it know if you are moving within the app or out of it. Here is how I would do it. I am using a class named DJ for this purpose.
public class DJ {
private static MediaPlayer player;
private static boolean keepMusicOn;
public static void iAmIn(Context context){
if (player == null){
player = MediaPlayer.create(context, R.raw.music1);
player.setLooping(true);
try{
player.prepare();
}
catch (IllegalStateException e){}
catch (IOException e){}
}
if(!player.isPlaying()){
player.start();
}
keepMusicOn= false;
}
public static void keepMusicOn(){
keepMusicOn= true;
}
public static void iAmLeaving(){
if(!keepMusicOn){
player.pause();
}
}
}
Now from your Activity call the DJ like this.(Let him know if you would like to keep the music on)
public void onPause() {
super.onPause();
DJ.iAmLeaving();
}
public void onResume(){
super.onResume();
DJ.iAmIn(this);
}
public void buttonOnClick(View view){
DJ.keepMusicOn();
Intent intent = new Intent(this, TheOtherActivity.class);
startActivity(intent);
}
I did it this way and I'm pleased with the result:
1st create the service:
public class LocalService extends Service
{
// This is the object that receives interactions from clients. See RemoteService for a more complete example.
private final IBinder mBinder = new LocalBinder();
private MediaPlayer player;
/**
* Class for clients to access. Because we know this service always runs in
* the same process as its clients, we don't need to deal with IPC.
*/
public class LocalBinder extends Binder
{
LocalService getService()
{
return LocalService.this;
}
}
#Override
public void onCreate()
{
}
#Override
public int onStartCommand(Intent intent, int flags, int startId)
{
// We want this service to continue running until it is explicitly stopped, so return sticky.
return START_STICKY;
}
#Override
public void onDestroy()
{
destroy();
}
#Override
public IBinder onBind(Intent intent)
{
return mBinder;
}
public void play(int res)
{
try
{
player = MediaPlayer.create(this, res);
player.setLooping(true);
player.setVolume(0.1f, 0.1f);
player.start();
}
catch(Exception e)
{
e.printStackTrace();
}
}
public void pause()
{
if(null != player && player.isPlaying())
{
player.pause();
player.seekTo(0);
}
}
public void resume()
{
try
{
if(null != player && !player.isPlaying())
{
player.start();
}
}
catch(Exception e)
{
e.printStackTrace();
}
}
public void destroy()
{
if(null != player)
{
if(player.isPlaying())
{
player.stop();
}
player.release();
player = null;
}
}
}
2nd, create a base activity and extend all your activities in witch you wish to play the background music from it:
public class ActivityBase extends Activity
{
private Context context = ActivityBase.this;
private final int [] background_sound = { R.raw.azilum_2, R.raw.bg_sound_5 };
private LocalService mBoundService;
private boolean mIsBound = false;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
doBindService();
}
#Override
protected void onStart()
{
super.onStart();
try
{
if(null != mBoundService)
{
Random rand = new Random();
int what = background_sound[rand.nextInt(background_sound.length)];
mBoundService.play(what);
}
}
catch(Exception e)
{
e.printStackTrace();
}
}
#Override
protected void onStop()
{
super.onStop();
basePause();
}
protected void baseResume()
{
try
{
if(null != mBoundService)
{
mBoundService.resume();
}
}
catch(Exception e)
{
e.printStackTrace();
}
}
protected void basePause()
{
try
{
if(null != mBoundService)
{
mBoundService.pause();
}
}
catch(Exception e)
{
e.printStackTrace();
}
}
private ServiceConnection mConnection = new ServiceConnection()
{
public void onServiceConnected(ComponentName className, IBinder service)
{
// This is called when the connection with the service has been
// established, giving us the service object we can use to
// interact with the service. Because we have bound to a explicit
// service that we know is running in our own process, we can
// cast its IBinder to a concrete class and directly access it.
mBoundService = ((LocalService.LocalBinder) service).getService();
if(null != mBoundService)
{
Random rand = new Random();
int what = background_sound[rand.nextInt(background_sound.length)];
mBoundService.play(what);
}
}
public void onServiceDisconnected(ComponentName className)
{
// This is called when the connection with the service has been
// unexpectedly disconnected -- that is, its process crashed.
// Because it is running in our same process, we should never
// see this happen.
mBoundService = null;
if(null != mBoundService)
{
mBoundService.destroy();
}
}
};
private void doBindService()
{
// Establish a connection with the service. We use an explicit
// class name because we want a specific service implementation that
// we know will be running in our own process (and thus won't be
// supporting component replacement by other applications).
Intent i = new Intent(getApplicationContext(), LocalService.class);
bindService(i, mConnection, Context.BIND_AUTO_CREATE);
mIsBound = true;
}
private void doUnbindService()
{
if (mIsBound)
{
// Detach our existing connection.
unbindService(mConnection);
mIsBound = false;
}
}
#Override
protected void onDestroy()
{
super.onDestroy();
doUnbindService();
}
}
And that's it, now you have background sound in all the activities that are extended from ActivityBase.
You can even control the pause / resume functionality by calling basePause() / baseResume().
Don't forget to declare the service in manifest:
<service android:name="com.gga.screaming.speech.LocalService" />
The idea is that you should not play music from the activity itself. On Android, Activities, and other contexts, have life cycles. It means they will live...and die. And when dead, they can't do anything any more.
So you gotta find something with a lifecycle that lasts more than a single activity if you want the music to live longer.
The easiest solution is an Android service. You can find a good thread here : Android background music service
I know there are already quite a number of discussions about this, but none of what I found could clear my confusion.
I'm using the Android SDK for the first time and my Java Skills are rather average.
I have the following Problem:
From my MainActivity - OnCreate() fct. I start a thread (Receiver), receiving data from a SocketStream. This thread shall refresh a TextView-Element on the GUI when new data was read from the stream.
What is a simple but proper way to do so? I read something about ASyncTask, but did not understand how to implement it.
public class MainActivity extends Activity
{
ExecutorService myExecutor;
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
System.out.println("this is a test"); System.out.flush();
try
{
myExecutor = Executors.newCachedThreadPool();
myExecutor.execute(Receiver.getInstance());
}
catch (IOException e)
{
e.printStackTrace();
}
}
...
public class Receiver implements Runnable
{
[...]
public void run()
{
while (true)
{
//blocking system-io-call to read data from socket..
//extract information
// *** update textView *** ??
}
}
}
You can implement handler in GUI thread to change GUI (in MainActivity in your case):
public Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
//refresh textview
}
};
and than call it from another threads
activity.handler.sendEmptyMessage(what);
You can write your own constructor for Receiver:
public class Receiver implements Runnable
{
[...]
MainActivity activity;
public Receiver(MainActivity activity){
this.activity = activity;
}
public void run()
{
while (true)
{
//blocking system-io-call to read data from socket..
//extract information
// *** update textView *** ??
activity.handler.sendEmptyMessage(0);
}
}
}
You can use runOnUiThread
public class Receiver implements Runnable
{
[...]
public void run()
{
while (true)
{
//blocking system-io-call to read data from socket..
//extract information
runOnUiThread(new Runnable() {
public void run() {
// *** update textView *** ??
}
});
}
}
}
this is a example:
create Counter class :
public class Counter implements Runnable
{
private ICounterEvents listener;
public static Thread OBJ_THREAD = null;
public Counter()
{
OBJ_THREAD = new Thread(this);
}
public void setCountListener(ICounterEvents listener)
{
this.listener = listener;
}
public void start()
{
OBJ_THREAD.start();
}
#Override
public void run()
{
for(int i = 0; i < 100; i++)
{
try
{
Thread.sleep(1000);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
Message msg = Message.obtain();
msg.obj = i;
this.handler.sendMessage(msg);
}
}
private Handler handler =
new Handler()
{
#Override
public void handleMessage(Message msg)
{
if(Counter.this.listener != null)
{
int value = (Integer)msg.obj;
Counter.this.listener.countChanged(value);
}
}
};
}
and create a interface class:
public interface ICounterEvents
{
public void countChanged(int value);
}
and than in your main layout create a textview and a button,
and use this code in onCreate method in MainActivity:
public class MainActivity extends Activity implements ICounterEvents, OnClickListener
{
private TextView txtCounter;
private Button btnStart;
private Counter counter;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
this.setupViews();
}
private void setupViews()
{
this.counter = new Counter();
this.counter.setCountListener(this);
this.txtCounter = (TextView)findViewById(R.id.txtCount);
this.btnStart = (Button)findViewById(R.id.btnStart);
this.btnStart.setOnClickListener(this);
}
#Override
public void onClick(View v)
{
this.counter.start();
}
public void countChanged(int value)
{
try
{
this.txtCounter.setText(value + "");
}
catch (Exception e)
{
}
}
}