-->

How to set Service/StartForeground to work CountDo

2019-03-04 15:42发布

问题:

I am not sure where/how I can run this service to work in background. I develop application which use a CountDownTimer. I found that I should create a CountDownTimer in Service.class and run a Service.class in MainActivity.class.

  1. Why TextView doesn't show on my screen? I put this in OnCreate and onStartCommand. Next I try run this in MainActivity but without success.

  2. I still try to implement my code to work this CountDownTimer properly in a background. On official Android website I see that they use a "Log.i" command to run this Foreground method. How can I use this in my code? Should I add this in Service.class?

Below is my code:

MainActivity:

Button btnStart, btnStop;
TextView textViewTime;


@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
}

public void startService(View view)
{
    Intent intent = new Intent(this,MyService.class);
    startService(intent);
}

public void stopService(View view)
{
    Intent intent = new Intent(this,MyService.class);
    stopService(intent);
}

MyService:

Button btnStart, btnStop;
TextView textViewTime;
public String hms;

@Override
public void onCreate() { 

    btnStart = (Button) btnStart.findViewById(R.id.btnStart);
    btnStop = (Button) btnStop.findViewById(R.id.btnStop);
    textViewTime = (TextView) textViewTime.findViewById(R.id.textViewTime);

    textViewTime.setText("00:01:30");

    final CounterClass timer = new CounterClass(90000, 1000);


    btnStart.setOnClickListener(new View.OnClickListener() {
              @Override
             public void onClick(View v) {
                //startService(v);
                timer.start();
                                         }
                                                            });

    super.onCreate();
}


@Override
public int onStartCommand(Intent intent, int flags, int startId) {  // create start a service

    textViewTime.setText("00:01:30");

    Toast.makeText(this, "Service Started...", Toast.LENGTH_LONG).show();
   // timer.start();




    //return START_STICKY; // return integer value
    return super.onStartCommand(intent, flags, startId);
}

@Override
public void onDestroy() {  // stop a service

    Toast.makeText(this, "Service Destroyed...", Toast.LENGTH_LONG).show();

    super.onDestroy();
}

@Nullable
@Override
public IBinder onBind(Intent intent) {  // it's not needed but we must override this method
    return null;
}


public class CounterClass extends CountDownTimer {

    public CounterClass(long millisInFuture, long countDownInterval) {
        super(millisInFuture, countDownInterval);
    }

    @Override
    public void onTick(long millisUntilFinished) {
        long millis = millisUntilFinished;
         hms = String.format("%02d:%02d:%02d", TimeUnit.MILLISECONDS.toHours(millis),
                TimeUnit.MILLISECONDS.toMinutes(millis) - TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS.toHours(millis)),
                TimeUnit.MILLISECONDS.toSeconds(millis) - TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(millis)));
        System.out.println(hms);
        textViewTime.setText(hms);

    }

    @Override
    public void onFinish() {
        textViewTime.setText("Completed.");
    }
}

回答1:

Here is your solution was easy though :)

activity xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="in.ashish29agre.stackoverflow.sample.servicetimer.ServiceTimerActivity">

    <TextView
        android:id="@+id/status_tv"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:padding="16dp"
        android:text="TImer will start here" />

    <Button
        android:id="@+id/start_btn"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:onClick="startService"
        android:text="Start" />

    <Button
        android:id="@+id/stop_btn"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:onClick="stopService"
        android:text="Stop" />
</LinearLayout>

Java code

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.support.v4.content.LocalBroadcastManager;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.TextView;

import in.ashish29agre.stackoverflow.R;

public class ServiceTimerActivity extends AppCompatActivity {

    TextView textViewTime;
    private TimerStatusReceiver receiver;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_service_timer);
        textViewTime = (TextView) findViewById(R.id.status_tv);
        receiver = new TimerStatusReceiver();
    }


    @Override
    protected void onResume() {
        super.onResume();
        LocalBroadcastManager.getInstance(this).registerReceiver(receiver, new IntentFilter(CountdownTimerService.TIME_INFO));
    }

    @Override
    protected void onPause() {
        super.onPause();
        LocalBroadcastManager.getInstance(this).unregisterReceiver(receiver);
    }

    public void startService(View view) {
        Intent intent = new Intent(this, CountdownTimerService.class);
        startService(intent);
    }

    public void stopService(View view) {
        Intent intent = new Intent(this, CountdownTimerService.class);
        stopService(intent);
    }


    private class TimerStatusReceiver extends BroadcastReceiver {

        @Override
        public void onReceive(Context context, Intent intent) {
            if (intent != null && intent.getAction().equals(CountdownTimerService.TIME_INFO)) {
                if (intent.hasExtra("VALUE")) {
                    textViewTime.setText(intent.getStringExtra("VALUE"));
                }
            }
        }
    }
}

service code

import android.app.Notification;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.os.CountDownTimer;
import android.os.IBinder;
import android.support.annotation.Nullable;
import android.support.v4.content.LocalBroadcastManager;
import android.support.v7.app.NotificationCompat;

import java.util.concurrent.TimeUnit;

import in.ashish29agre.stackoverflow.R;

public class CountdownTimerService extends Service {
    public static final String TIME_INFO = "time_info";

    private CounterClass timer;

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

    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        timer = new CounterClass(90000, 1000);
        timer.start();
        Intent notificationIntent = new Intent(this, ServiceTimerActivity.class);
        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
                notificationIntent, Intent.FLAG_ACTIVITY_NEW_TASK);

        Notification notification = new NotificationCompat.Builder(this)
                .setSmallIcon(R.drawable.ic_launcher)
                .setContentText("Counter down service")
                .setContentIntent(pendingIntent).build();

        startForeground(101, notification);

        return START_NOT_STICKY;
    }

    @Override
    public void onDestroy() {
        timer.cancel();
        super.onDestroy();
        Intent timerInfoIntent = new Intent(TIME_INFO);
        timerInfoIntent.putExtra("VALUE", "Stopped");
        LocalBroadcastManager.getInstance(CountdownTimerService.this).sendBroadcast(timerInfoIntent);
    }

    public class CounterClass extends CountDownTimer {

        public CounterClass(long millisInFuture, long countDownInterval) {
            super(millisInFuture, countDownInterval);
        }

        @Override
        public void onTick(long millisUntilFinished) {
            long millis = millisUntilFinished;
            String hms = String.format("%02d:%02d:%02d", TimeUnit.MILLISECONDS.toHours(millis),
                    TimeUnit.MILLISECONDS.toMinutes(millis) - TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS.toHours(millis)),
                    TimeUnit.MILLISECONDS.toSeconds(millis) - TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(millis)));
            System.out.println(hms);
            Intent timerInfoIntent = new Intent(TIME_INFO);
            timerInfoIntent.putExtra("VALUE", hms);
            LocalBroadcastManager.getInstance(CountdownTimerService.this).sendBroadcast(timerInfoIntent);
        }

        @Override
        public void onFinish() {
            Intent timerInfoIntent = new Intent(TIME_INFO);
            timerInfoIntent.putExtra("VALUE", "Completed");
            LocalBroadcastManager.getInstance(CountdownTimerService.this).sendBroadcast(timerInfoIntent);
        }
    }
}

Forget to mention need to add service in manifest

 <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">


        <service android:name=".sample.servicetimer.CountdownTimerService" />
    </application>


回答2:

Firstly:

You have to write Broadcast Receiver in MainActivity.java and register it in oncreate() and unregister in onDetstroy().

Secondly

In Service in onTick() method you have to sendbroadcast() which will invoke onReceive() in MainActivity.java and then in onReceive method you can chage text of Textview of activity.