Let's assume I have a service like that,and I have a TextView to update in every tick,TextView is located in MainActivity. How can I update the TextView in every tick?
public class CountDownTimerService extends Service {
public CountDownTimerService() {
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
CountDownTimer.start();
return START_STICKY;
}
private CountDownTimer countDownTimer = new CountDownTimerWithPause(300000, 1) {
#Override
public void onTick(long millisUntilFinished) {
/*
In this part i need to update text on MainActivity
*/
}
#Override
public void onFinish() {
Log.i("Timer","Timer finished");
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
}
You have to use an IntentService to pass messages between your Activity and your Service. You can do it yourself but there is some known libraries which are very efficient and simple to use and do this stuff for you, like EventBus.
This is a very helpful tutorial for EventBus, it is very clean and simple to understand, hope it'll help!
https://guides.codepath.com/android/Communicating-with-an-Event-Bus
Related
I want to play music in the background of my application:
public class BackgroundSoundService extends Service {
MediaPlayer mediaPlayer;
#Override
public void onCreate() {
super.onCreate();
mediaPlayer = MediaPlayer.create(this, R.raw.airport_lounge);
mediaPlayer.setLooping(true);
mediaPlayer.setVolume(100,100);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
mediaPlayer.start();
return START_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
mediaPlayer.stop();
mediaPlayer.release();
}
#Override
public void onLowMemory() {
super.onLowMemory();
}
#Override
public boolean onUnbind(Intent intent) {
return super.onUnbind(intent);
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
}
Then in my MainActivity :
public static Intent musicIntent;
//Start music service
musicIntent = new Intent(this, BackgroundSoundService.class);
startService(musicIntent);
#Override
protected void onPause() {
super.onPause();
stopService(musicIntent);
}
#Override
protected void onResume() {
super.onResume();
startService(musicIntent);
}
I stop it in my onPause the service because if the user switches the Application and doesn't close it the music would continue to play. The problem is that when we change Activity the onPaused is also called but I want the music to continue playing through the entire application.
So in my another Activity :
//start music
startService(MainActivity.musicIntent);
But the music restarts and it's not very good to hear. Any solutions?
You can use ActivityLifecycleCallbacks in your application class.
public class MusicApplication extends Application implements ActivityLifecycleCallbacks {
int activitiesOnTop = 0;
#Override
public void onCreate() {
super.onCreate();
registerActivityLifecycleCallbacks(this);
}
#Override
public void onActivityResumed(Activity activity) {
// one of application activities is visible
activitiesOnTop ++;
}
#Override
public void onActivityStopped(Activity activity) {
activitiesOnTop --;
if(activitiesOnTop == 0){
// none of activities are on foreground
}
}
}
There are other solutions mentioned in the How to check if activity is in foreground or in visible background?.
It depends on the application structure, for example, if you build some tab or navigationDrawer based navigation, you will likely build some fragments and your MainActivity will be your only activity, so it's onPause method will only be called if user closes your application. But this scenario won't hold as your application grows (unless it's quite simple).
So another approach is to launch your service in your application instance, in case you use it.
I am newbie so please forgive me for anything wrong that I am doing or if I am asking the question in the wrong way.
I recently created a simple media player on android studio and used Java Service to play the media when I closed the app and it works fine. Now I have created a simple web browser app using WebView and I want to use the same "Java Service" to keep my web browser app running even when it is minimized but I have no idea how to convert the media player code to use on the web browser app. I have researched a lot and nobody else seems to want to create a browser that keeps running in the background. Please can you assist me in solving this?
Because I am new to Java, it is difficult for me to try and convert the code from media player to web browser
So here is my media player code:
MainActivity.java
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private Button start, stop;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
start = (Button) findViewById(R.id.buttonStartService);
stop = (Button) findViewById(R.id.buttonStopService);
start.setOnClickListener(this);
stop.setOnClickListener(this);
}
#Override
public void onClick(View view) {
if (view == start){
startService(new Intent(this, MyService.class));
}else if(view == stop){
stopService(new Intent(this, MyService.class));
}
}
}
MyService.java
public class MyService extends Service {
private MediaPlayer player;
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
player = MediaPlayer.create(this, Settings.System.DEFAULT_RINGTONE_URI);
player.setLooping(true);
player.start();
return START_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
player.stop();
}
}
Here is my MainActivity for the Webbrowser that I have created:
public class MainActivity extends AppCompatActivity {
WebView browser;
EditText link;
Button btn_visit;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
browser = (WebView) findViewById(R.id.webview);
link = (EditText) findViewById(R.id.editTextLink);
btn_visit = (Button) findViewById(R.id.btn_view);
browser.setWebViewClient(new myWebViewClient());
btn_visit.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
String url = link.getText().toString();
browser.getSettings().setLoadsImagesAutomatically(true);
browser.getSettings().setJavaScriptEnabled(true);
browser.loadUrl(url);
}
});
}
private class myWebViewClient extends WebViewClient {
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);
return true;
}
}
}
```
So now I need to create another MyService that will allow the webbrowser to run in the
background but dont know how to go about it:
```
public class MyService extends Service {
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
}
#Override
public void onDestroy() {
}
}
As I said, there no errors that I am getting on the media player app. I just want to be able to use the same code on the internet browser app but don't know how to convert it.
I have a Service (Bound) which I am trying to start from my MainActivity.java. The below is my Main Activity code:
public class MainActivity extends AppCompatActivity {
Handler m_handler;
Runnable m_handlerTask ;
private static ServiceConnection sConnection;
static boolean serviceBound = false;
#Override
protected void onStart() {
super.onStart();
// Bind to LocalService
Intent intent = new Intent(this, DataDownloaderService.class);
bindService(intent, sConnection, Context.BIND_AUTO_CREATE);
}
#Override
protected void onCreate(Bundle savedInstanceState) {
setTheme(R.style.NoActionBar);
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
try {
if (!Global.isMyServiceRunning(DataDownloaderService.class, this)) {
sConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName className, IBinder service) {
// We've bound to LocalService, cast the IBinder and get LocalService instance
DataDownloaderService.LocalBinder binder = (DataDownloaderService.LocalBinder) service;
Global.dService = binder.getService();
serviceBound = true;
}
#Override
public void onServiceDisconnected(ComponentName arg0) {
serviceBound = false;
}
};
}
}
catch(Exception ex ){
String p="";
}
}
#Override
protected void onResume(){
super.onResume();
m_handler = new Handler();
m_handlerTask = new Runnable()
{
#Override
public void run() {
RefreshNowPlaying();
m_handler.postDelayed(m_handlerTask, 1000);
}
};
m_handlerTask.run();
}
}
void RefreshNowPlaying(){
//Do something
}
}
The service code is as shown below:
public class DataDownloaderService extends Service {
private final IBinder dBinder = new LocalBinder();
public class LocalBinder extends Binder {
DataDownloaderService getService() {
// Return this instance of LocalService so clients can call public methods
return DataDownloaderService.this;
}
}
#Override
public IBinder onBind(Intent intent) {
return dBinder;
}
#Override
public void onCreate(){
}
#Override
public void onStart(Intent intent, int startid){
super.onStart(intent,startid);
Global.DataDownloaderServiceStatus = "STARTED";
}
#Override
public void onDestroy(){
Global.DataDownloaderServiceStatus = "STOPPED";
super.onDestroy();
}
}
I have also added the service to the AndroidManifest.xml under the Application element. However, I see that the service's onStart is never fired or the override onServiceConnected in the MainActivity is never called. I am new to Anrdoid development and Java. Can someone give me some pointers, please? I have noticed that the service's onCreate is getting hit, by putting breakpoints, but not onStart.
onStart() will be called only if the service was started via context.startService(), see here.
I want to use my sound on all my activities not only main activity. I put this lines
MediaPlayer ring = MediaPlayer.create(MainActivity.this, R.raw.song);
ring.start();
but that works only in main Activity.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
MediaPlayer ring = MediaPlayer.create(MainActivity.this, R.raw.song);
ring.start();
you can try something like this
1. add this code in your all activity
MediaPlayer ring = MediaPlayer.create(MainActivity.this,
R.raw.song);
ring.start();
2. create one method like this and call this msg from your activity in which you want to play music
public void Playmusic(Context context){
MediaPlayer ring = MediaPlayer.create(context, R.raw.song);
ring.start();
}
now just call this method like this
Playmusic(MainActivity.this);
play your songs in service and initialize the media player object there only
Intent svc=new Intent(this, BackgroundSoundService.class);
startService(svc);
public class BackgroundSoundService extends Service {
private static final String TAG = null;
MediaPlayer player;
public IBinder onBind(Intent arg0) {
return null;
}
#Override
public void onCreate() {
super.onCreate();
player = MediaPlayer.create(this, R.raw.idil);
player.setLooping(true); // Set looping
player.setVolume(100,100);
}
public int onStartCommand(Intent intent, int flags, int startId) {
player.start();
return 1;
}
public void onStart(Intent intent, int startId) {
// TO DO
}
public IBinder onUnBind(Intent arg0) {
// TO DO Auto-generated method
return null;
}
public void onStop() {
}
public void onPause() {
}
#Override
public void onDestroy() {
player.stop();
player.release();
}
#Override
public void onLowMemory() {
}
}
Please call this service in Manifest
<service android:enabled="true" android:name=".BackgroundSoundService " />
In MainActivity I have a TextView: textV1. I also have a method in MainActivity that updates that textview:
public void updateTheTextView(final String t) {
MainActivity.this.runOnUiThread(new Runnable() {
public void run() {
TextView textV1 = (TextView) findViewById(R.id.textV1);
textV1.setText(t);
}
});
}
In a BroadcasrReceiver I need to update the text in textV1 in MainActivity.
public class NotifAlarm extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
// other things done here like notification
// NEED TO UPDATE TEXTV1 IN MAINACTIVITY HERE
}
}
How can this be done? The BroadcastReceiver is run from a service. This code I cannot change. Can I access and change textV1 in MainActivity from onReceive()? I've tried many things but all fail.
In your MainActivity initialize a variable of MainActivity class like below.
public class MainActivity extends Activity {
private static MainActivity ins;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ins = this;
}
public static MainActivity getInstace(){
return ins;
}
public void updateTheTextView(final String t) {
MainActivity.this.runOnUiThread(new Runnable() {
public void run() {
TextView textV1 = (TextView) findViewById(R.id.textV1);
textV1.setText(t);
}
});
}
}
public class NotifAlarm extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
try {
MainActivity .getInstace().updateTheTextView("String");
} catch (Exception e) {
}
}
}
#Use Interface
Another way to deal with this situation is by using an Interface. I will describe the advantage of this approach but first, let's see how it's done.
Follow these steps:
1) Create an interface
public interface MyBroadcastListener{
public void doSomething(String result);
}
2) Initialize the listener in BroadCastReceiver
public class NotifAlarm extends BroadcastReceiver {
private MyBroadcastListener listener;
#Override
public void onReceive(Context context, Intent intent) {
listener = (MyBroadcastListener)context;
// other things done here like notification
// NUPDATE TEXTV1 IN MAINACTIVITY HERE
listener.doSomething("Some Result");
}
}
3) Implement the interface in Activity and override the method
public YourActivity extends AppCompatActivity implements MyBroadcastListener{
// Your Activity code
public void updateTheTextView(String t) {
TextView textV1 = (TextView) findViewById(R.id.textV1);
textV1.setText(t);
}
#Override
public void doSomething(String result){
updateTheTextView(result); // Calling method from Interface
}
}
##Advantages of using the interface?
When you have BroadcastReceiver in a different file
Decoupled BroadcastReceiver
Using an interface makes BroadcastReceiver independent of any
Activity. Let's say in future you want to use this BroadCastReceiver
with another Activity which takes the result from BroadcastReceiver
and start a DetailActivity. This is completely a
different task but you will use the same BroadcastReceiver without even
a single code change inside BroadcastReceiver.
How to do that?
Implement the interface in the Activity and Override the method. That's it!
public ListActivity extends AppCompatActivity implements MyBroadcastListener{
// Your Activity code
public void startDetailActivity(String title) {
Intent i = new Intent(ListActivity,this, DetailActivity.class);
i.putExtra("Title", title);
startActivity(i);
}
#Override
public void doSomething(String result){
startDetailActivity(String title); // Calling method from Interface
}
}
create an instance of the class and then pass the value to the function that changes TextView value follow these steps please :
in your BroadcastReceiver overRide onReceive method and paste These lines or changes theme as you wish
private Handler handler = new Handler(); // Handler used to execute code on the UI thread
// Post the UI updating code to our Handler
handler.post(new Runnable() {
#Override
public void run() {
//Toast.makeText(context, "Toast from broadcast receiver", Toast.LENGTH_SHORT).show();
YourActivityToUpdate.updateTheTextView(message);
YourActivityToUpdateinst = YourActivityToUpdate.instance();
if(inst != null) { // your activity can be seen, and you can update it's context
inst.updateTheTextView(message);
}
}
});
now we explain the updateTheTextView and inst
in YourActivityToUpdate class Paste these Lines please
private static SignUpVerify mInst;
public static SignUpVerify instance() {
return mInst;
}
#Override
public void onStart() {
super.onStart();
mInst = this;
}
#Override
public void onStop() {
super.onStop();
mInst = null;
}
and this is the updateTheTextView method that should be placed in YourActivityToUpdate class
public void updateTheTextView(final String verifyCodeValue) {
Log.i("verifyCodeValue", verifyCodeValue);
YourTextViewToUpdate.setText(verifyCodeValue);
}
i think this is a better way thanks to "kevin-lynx"
If someone is searching this exact solution, but in Kotlin, do the following:
class MainActivity : AppCompatActivity() {
companion object {
var ins: MainActivity? = null
fun getInstance(): MainActivity? {
return ins
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
ins = this
}
fun updateTheTextView(t: String) {
this#MainActivity.runOnUiThread {
val textV1 = findViewById<TextView>(R.id.textV1)
textV1.text = t
}
}
}
class NotifAlarm : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
try {
MainActivity.getInstance()?.updateTheTextView("The String")
} catch (e: Exception) {
}
}
}
In your broadcastreceiver class send broadcast
public class mybroadcaster extends BroadcastReceiver{
#Override
public void onReceive(Context context, Intent intent) {
context.sendBroadcast(new Intent("updatetext"));
}
}
In your activity register your broadcastreceiver and call it, do your work at onReceive and unregister the broadcaster in onDestroy()
public class MyActivity extends Activity{
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
registerReceiver(broadcastReceiver, new IntentFilter("updatetext"));
}
BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// do your work here
}
};
#Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(broadcastReceiver);
}
}