Vlad Pintea Vlad Pintea - 3 months ago 8
Android Question

Why does the SharedPreferences update the TextView only once?

I've got this service, which - among other things - updates a TextView, every time it gets destroyed (the TextView is "txtCounter"). By updating it, I mean it adds a 1 (one) to the TextView, every time it ends. So, the first time I call the service, the TextView should be 1. The second time should be 2 and so on.

Unfortunately, it only works once and whenever I kill the application, even that 1 disappears. Any ideas?

MainActivity:

public class MainActivity extends AppCompatActivity {

public TextView txtCounter;

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

final Button startApp = (Button) findViewById(R.id.startApp);
final EditText timer = (EditText) findViewById(R.id.insertTimer);

assert startApp != null;
startApp.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(MainActivity.this, "Countdown, Started", Toast.LENGTH_SHORT).show();

Intent startMain = new Intent(Intent.ACTION_MAIN);
startMain.addCategory(Intent.CATEGORY_HOME);
startMain.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(startMain);

Intent intent = new Intent(MainActivity.this, MainService.class);
assert timer != null;
intent.putExtra("timer", timer.getText().toString());
startService(intent);

Settings.System.putInt(getContentResolver(), Settings.System.SCREEN_OFF_TIMEOUT, 1000);

registerReceiver(broadcastReceiver, new IntentFilter(MainService.BROADCAST_ACTION));
}
});
}

private BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) { updateUI(intent); }
};

private void updateUI(Intent intent) {
txtCounter = (TextView) findViewById(R.id.txtCounter);
String counter = intent.getStringExtra("counter");

SharedPreferences pref = getApplicationContext().getSharedPreferences("MyFile", MODE_PRIVATE);
SharedPreferences.Editor editor = pref.edit();
editor.putString(counter,String.valueOf(txtCounter));
editor.apply();

assert txtCounter != null;
txtCounter.setText(counter);
}

@Override
public void onDestroy() {
try { unregisterReceiver(broadcastReceiver); } catch (IllegalArgumentException ignored) {}

super.onDestroy();
}


MainService:

public class MainService extends Service {

static String BROADCAST_ACTION = "com.example.vladpintea.friendsbeforecents.displayevent";
Handler handler = new Handler();
int counterr = 0;
Intent intentt;

String usedTimer;
long interval;

//TimerTask that will cause the run() runnable to happen.
TimerTask myTask = new TimerTask() {
public void run() { stopSelf(); }
};
//Timer that will make the runnable run.
Timer myTimer = new Timer();

@Override
public void onCreate() {
Toast.makeText(MainService.this, "Service, Created", Toast.LENGTH_SHORT).show();

intentt = new Intent(BROADCAST_ACTION);

registerReceiver(counter, new IntentFilter(Intent.ACTION_SCREEN_ON));
}

private BroadcastReceiver counter = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
myTimer.cancel();

Toast.makeText(MainService.this, "Whoops! You've Lost.", Toast.LENGTH_SHORT).show();

Settings.System.putInt(getContentResolver(), Settings.System.SCREEN_OFF_TIMEOUT, 30000);
}
};

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Toast.makeText(MainService.this, "Service, Started", Toast.LENGTH_SHORT).show();

usedTimer = intent.getStringExtra("timer");
try {
interval = Long.parseLong(usedTimer);
} catch (NumberFormatException ignored) {
}

myTimer.schedule(myTask, interval);

handler.removeCallbacks(sendUpdatesToUI);
handler.postDelayed(sendUpdatesToUI, 1000);

return super.onStartCommand(intent, flags, startId);
}

private Runnable sendUpdatesToUI = new Runnable() {
public void run() {
handler.postDelayed(this, 1000); }
};

public void DisplayLoggingInfoPlus() {
intentt.putExtra("counter", String.valueOf(++counterr));
sendBroadcast(intentt);
}

@Override
public void onDestroy() {
unregisterReceiver(counter);

PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock wakeLock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK
| PowerManager.ACQUIRE_CAUSES_WAKEUP
| PowerManager.ON_AFTER_RELEASE, "MyWakeLock");
if ((wakeLock != null) && (!wakeLock.isHeld())) { wakeLock.acquire(); }

Settings.System.putInt(getContentResolver(), Settings.System.SCREEN_OFF_TIMEOUT, 30000);

DisplayLoggingInfoPlus();
}

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

Answer

You aren't really increasing the value. Firstly, in your broadcast intent, you are initialising counter = 0 and then while sending, you are increasing it by 1. So, you don't really need it. We can update it in the activity when we receive the broadcast. So, in your Service, your code can be:

// Get rid of counter variable elsewhere too
public void DisplayLoggingInfoPlus() { 
    sendBroadcast(intentt);
} 

Now, in your Activity, we need to update the value too, so we can modify the code as:

private void updateUI(Intent intent) {
    txtCounter = (TextView) findViewById(R.id.txtCounter);
    // String counter = intent.getStringExtra("counter");

    SharedPreferences pref = getApplicationContext().getSharedPreferences("MyFile", MODE_PRIVATE);
    int counter = pref.getInt("counter", 0); // Getting int now instead of String
    SharedPreferences.Editor editor = pref.edit();
    editor.putInt("counter", ++counter);
    editor.apply();

    assert txtCounter != null;
    txtCounter.setText(String.valueOf(counter));
} 
Comments