Saving objects on Android - java

I'm trying to save a serialized timer object, and retrieve it. The timer needs to be restored exactly how it was when it was created.
The timer works beautifully, but when the app is destroyed so is my timer with all its data.
EDIT: debug log says FileNotFoundException: open failed (Read only File system)
I have the uses-permission in my manifest
I'm not attempting to write to an SD card, I want to create the file on the user's android locally.
.......
My timer class implements serialized
And OnCreate My app try to connect to a objectinputstream, and a fileinputstream; retrieve the object, cast it to a Timer and assign it.
The timer is stored every time it's updated.
TIMER CLASS CODE
package com.example.theworkingbutton;
import java.io.Serializable;
import java.util.concurrent.TimeUnit;
import android.widget.Button;
public class Timer implements Serializable {
private static final long serialVersionUID = 1L;
public Timer(int timerState){
this.timerState = timerState;
}
public int timerState = 0;
public long timerStart = 0;
public long timerEnd = 0;
public long timeAccumulated = 0;
public long totalSeconds = 0;
public long hours = 0;
public long minutes = 0;
public long seconds = 0;
public String realTimeSeconds = "null";
public String realTimeMinutes = "null";
public String realTimeHours = "null";
public String timeString = "No time avalible";
Button button;
public void preform(){
if(timerState == 0){
timerStart = System.nanoTime();
timerState = 1;
} else if (timerState == 1) {
timerEnd = System.nanoTime();
timeAccumulated = timerEnd - timerStart + timeAccumulated;
totalSeconds = TimeUnit.SECONDS.convert(timeAccumulated, TimeUnit.NANOSECONDS);
hours = (totalSeconds / 3600);
minutes = (totalSeconds % 3600) / 60;
seconds = (totalSeconds % 60);
realTimeHours = Long.toString(hours);
realTimeSeconds = Long.toString(seconds);
realTimeMinutes = Long.toString(minutes);
timeString = "Hours: " + realTimeHours + " Minutes: " + realTimeMinutes + " Seconds: " + realTimeSeconds;
timerState = 0;
}
}
}
End Timer class code
ONCREATE Code
#Override
protected void onCreate(Bundle savedInstanceState){
//make screen
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
locManager =(LocationManager)getSystemService(Context.LOCATION_SERVICE);
locManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000L,
500.0f, locationListener);
//get buttons / turn them red
workingButton = (Button) findViewById(R.id.timer_button);
officeButton = (Button) findViewById(R.id.office_button);
drivingButton = (Button) findViewById(R.id.drive_button);
showingButton = (Button) findViewById(R.id.showing_button);
prospectingButton = (Button) findViewById(R.id.prospect_button);
listingButton = (Button) findViewById(R.id.listing_button);
listingButton.getBackground().setColorFilter(0xffffff00, PorterDuff.Mode.MULTIPLY);
workingButton.getBackground().setColorFilter(0xFFFF0000, PorterDuff.Mode.MULTIPLY);
drivingButton.getBackground().setColorFilter(0xFFFF0000, PorterDuff.Mode.MULTIPLY);
officeButton.getBackground().setColorFilter(0xFFFF0000, PorterDuff.Mode.MULTIPLY);
showingButton.getBackground().setColorFilter(0xFFFF0000, PorterDuff.Mode.MULTIPLY);
prospectingButton.getBackground().setColorFilter(0xFFFF0000, PorterDuff.Mode.MULTIPLY);
//set up our map
GoogleMap monthlyMap = ((MapFragment) getFragmentManager().findFragmentById(R.id.map)).getMap();
Location location = locManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
if (location != null) {
location.getLatitude();
location.getLongitude();
}
monthlyMap.setMapType(GoogleMap.MAP_TYPE_HYBRID);
monthlyMap.setMyLocationEnabled(true);
monthlyMap.animateCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(location.getLatitude(),location.getLongitude()), 15 ));
try{
#SuppressWarnings("resource")
ObjectInputStream is = new ObjectInputStream(new FileInputStream("TheWorkingButtonSaves.txt"));
Timer timerOne = (Timer) is.readObject();
workingTimer = timerOne;}
catch (Exception e){
e.printStackTrace();
}
}
END ON CREATE CODE
How im trying to save
Timer workingTimer;
public void startWorking(View view){
if (workingTimer == null){
workingTimer = new Timer(working);}
//Layout Views
workingButton = (Button) findViewById(R.id.timer_button);
TextView amountOfTime = (TextView) findViewById(R.id.time_spent);
if(drivingTimer.timerState == 1){
drivingSomewhere(findViewById(R.id.drive_button));
}
workingTimer.preform();
// Button Colors
if (workingTimer.timerState == 0 ){ //(TIMERS OFF)
workingButton = (Button) findViewById(R.id.timer_button);
workingButton.getBackground().setColorFilter(0xFFFF0000, PorterDuff.Mode.MULTIPLY);
}
else { //(TIMERS ON)
workingButton.getBackground().setColorFilter(0xFF00FF00, PorterDuff.Mode.MULTIPLY);
}
//save
try {
FileOutputStream fs = new FileOutputStream ("TheWorkingButtonSaves.txt");
ObjectOutputStream os = new ObjectOutputStream(fs);
os.writeObject(workingTimer);
os.close();
} catch (Exception e) {
e.printStackTrace();
}
//Display Time to user
amountOfTime.setText(workingTimer.timeString);
}
END HOW IM TRYING TO SAVE

You can save the value of the timer by using SharedPreferences.
SharedPreferences saveTimer= getSharedPreferences("saveTimer", Activity.MODE_PRIVATE);
SharedPreferences.Editor editor= timeSaved.edit();
// There's also putLong and putFloat
editor.putInt("saveTimer", INT_NAME_1);
editor.commit();
You then retrieve it using
SharedPreferences getTimer = getSharedPreferences("saveTimer", Activity.MODE_PRIVATE);
int INT_NAME_2 = getTimer.getInt("saveTimer", 0);
Now you have an int (or float or long) value that you can put back and start from where you started. (You can also use this to retrieve the values of whatever you saved in other activities)

See the below link if it helps. In my opinion it's better to let the platform handle the serializaion/deserialization instead of us doing it.
Handling runtime changes

Related

How to calculate the current millisecond provided if there is old millisecond in java

I making a timer in my android app. I have a scenario where I dont need to stop the timer even if the app is closed. If the timer is running and user closes the app and reopen it after sometime. He should see the latest time on the timer. But currently I am not able to show the latest time. I am only able to show the time when the user killed the app. I am storing the time of the timer and when the user open the app I am putting the stored time back to the timer. But I want to show the latest time. Here what I have done till now. I am using chronometer widget.
MainActivity.class:
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private static final String TAG = MainActivity.class.getSimpleName();
Chronometer tvTextView;
Button btnStart, btnStop;
private int state = 0; //0 means stop state,1 means play, 2 means pause
SharedPreferences sharedPreferences;
private boolean running = false;
private long pauseOffSet = -1;
ProgressBar progressBar;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tvTextView = findViewById(R.id.textview);
progressBar = findViewById(R.id.puzzleProgressBar);
btnStart = findViewById(R.id.button1);
btnStop = findViewById(R.id.button2);
btnStart.setOnClickListener(this);
btnStop.setOnClickListener(this);
sharedPreferences = getSharedPreferences("myprefs", MODE_PRIVATE);
state = sharedPreferences.getInt("state", 0);
tvTextView.setOnChronometerTickListener(new Chronometer.OnChronometerTickListener() {
#Override
public void onChronometerTick(Chronometer chronometer) {
long time = SystemClock.elapsedRealtime() - chronometer.getBase();
pauseOffSet=time;
Log.e(TAG,"pauseOffSet "+pauseOffSet);
if (time >= 79200000) {
tvTextView.setBase(SystemClock.elapsedRealtime());
tvTextView.stop();
running = false;
progressBar.setProgress(0);
} else {
chronometer.setText(setFormat(time));
int convertTime = (int) time;
progressBar.setProgress(convertTime);
}
}
});
if (state == 1) { // its in play mode
running = true;
tvTextView.setBase(SystemClock.elapsedRealtime() - sharedPreferences.getLong("milli", 0));
tvTextView.start();
} else if (state == 2) { //its in pause mode
running = false;
pauseOffSet = sharedPreferences.getLong("milli", -1);
long time = SystemClock.elapsedRealtime() - pauseOffSet;
tvTextView.setBase(time);
int convertTime = (int) pauseOffSet;
progressBar.setProgress(convertTime);
} else {
running = false;
tvTextView.setBase(SystemClock.elapsedRealtime());
}
}
public void onClick(View v) {
if (btnStart == v) {
if (!running) {
if (pauseOffSet != -1) {
pauseOffSet = sharedPreferences.getLong("milli", -1);
}
tvTextView.setBase(SystemClock.elapsedRealtime() - pauseOffSet);
tvTextView.start();
state = 1;
pauseOffSet = 0;
running = true;
}
} else if (btnStop == v) {
if (running) {
tvTextView.stop();
pauseOffSet = SystemClock.elapsedRealtime() - tvTextView.getBase();
state = 2;
running = false;
}
}
}
#Override
protected void onStop() {
super.onStop();
sharedPreferences.edit().putLong("milli", pauseOffSet).commit();
sharedPreferences.edit().putInt("state", state).commit();
}
#Override
protected void onDestroy() {
Log.e(TAG, "onDestroy called, state: " + state);
super.onDestroy();
}
String setFormat(long time) {
int h = (int) (time / 3600000);
int m = (int) (time - h * 3600000) / 60000;
int s = (int) (time - h * 3600000 - m * 60000) / 1000;
String hh = h < 10 ? "0" + h : h + "";
String mm = m < 10 ? "0" + m : m + "";
String ss = s < 10 ? "0" + s : s + "";
return hh + ":" + mm + ":" + ss;
}
}

play mp3 files at designated duration

I'm trying to make an app that can play mp3 files at designated duration through MediaPlayer
for example:
Start Time: 00:42
End Time: 01:23
my question is:
-is it possible to designate the start and end time via textview at MM:SS format?
Thanks!!
Yes after initiating the MediaPlayer and loading the file , you can pause or stop the player after using specific time
while(mPlayer.isPlaying()) {
if(mPlayer.getCurrentPosition() > 7254 && mPlayer.getCurrentPosition() < 7410 ){
labelTxt.setText("Stop: " + mPlayer.getCurrentPosition() );
mPlayer.stop();
break;
}
}
use This code
MediaPlayer mp;
Runnable stopPlayerTask = new Runnable(){
#Override
public void run() {
mp.pause();
}};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
EditText etStartTime = (EditText)findViewById(R.id.edittext_start_time);
EditText etEndTime = (EditText)findViewById(R.id.edittext_end_time);
String StartTime = etStartTime.getText().toString();
String EndTime = etEndTime.getText().toString();
long min = Integer.parseInt(StartTime .substring(0, 2));
long sec = Integer.parseInt(StartTime .substring(3));
long minEnd = Integer.parseInt(StartTime .substring(0, 2));
long secEnd = Integer.parseInt(StartTime .substring(3));
long startLong = (min * 60L) + sec;
long endLong = (minEnd * 60) + secEnd;
int starIntTime = (int) startLong;
int endIntTime = (int) endLong;
mp = MediaPlayer.create(this, R.raw.my_sound_file);
mp.seekTo(starIntTime);
mp.start();
Handler handler = new Handler();
handler.postDelayed(stopPlayerTask, endIntTime);
}

Multithreading using a Handler doesn't run past first pass

I am trying to run a simple clock in my activity, the purpose of the project is to create a secondary thread to run our clock on and update our main UI thread using a handler. I thought I had it working but I guess I was looking at something wrong. Either way, here is my code
public class MainActivity extends Activity implements Runnable{
/** VARIABLES **/
private LinearLayout currView;
private TextView clock;
private Typeface icelandFace;
private Calendar cal;
// clock time values
private int clockMins;
private int clockHour;
private int timeOfDay; // am/pm
private String currTimeString;
// for alarm clock
boolean startAlarm = false;
private long alarmStartTime = -1;
private final int DESIRED_ALARM_DURATION = 5;
// clock thread handler, to communicate between our main ui and our secondary ui
// - note to self - rather unclear on the explanation for the suppression for the handler
private Handler handler = new Handler();
// runnable variable for the secondary thread to actually run on
private final Runnable clockRunnable = new Runnable(){
public void run(){
updateUI();
}
};
/** OVERRIDDEN CLASS METHODS **/
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
currView = (LinearLayout) findViewById(R.id.main_activity);
clock = (TextView) findViewById(R.id.clock_view);
clock.setTextSize(clock.getTextSize() * 2);
icelandFace = Typeface.createFromAsset(getAssets(), "font/Iceland-Regular.ttf");
clock.setTypeface(icelandFace);
cal = Calendar.getInstance();
// Create New Thread (to run our clock on)
Thread clockThread = new Thread(){
public void run() {
keepTime();
clockMins = cal.get(Calendar.MINUTE);
clockHour = cal.get(Calendar.HOUR);
timeOfDay = cal.get(Calendar.AM_PM);
// Implement the handler for the thread
// NOTE: recall, Message contains data and is passed to our handler
//Message message = handler.obtainMessage();
Bundle bundle = new Bundle();
// start with hours
String timeString = clockHour + ":";
// add minutes
if(clockMins < 10){
timeString = timeString + "0" + clockMins + " ";
}
else{
timeString = timeString + clockMins + " ";
}
// set time of day
if(timeOfDay == 0){
timeString = timeString + "am";
}
else{
timeString = timeString + "pm";
}
// Optional bundle stuff
//bundle.putString("time_string", timeString);
//message.setData(bundle);
Log.d("Runnable", "Tracking time # " + timeString);
currTimeString = timeString;
handler.post(clockRunnable);
}
private void keepTime(){
clockMins = cal.get(Calendar.MINUTE);
clockHour = cal.get(Calendar.HOUR);
timeOfDay = cal.get(Calendar.AM_PM);
checkAlarm(clockHour, clockMins, timeOfDay);
}
private void checkAlarm(int hour, int min, int timeOfDay){
SharedPreferences alarmPref = getSharedPreferences("alarm_preferences", MODE_PRIVATE);
int alarmHour = alarmPref.getInt("alarm_hour", -1);
int alarmMin = alarmPref.getInt("alarm_min", -1);
int alarmTimeOfDay = alarmPref.getInt("alarm_time_of_day", 0);
boolean alarmOn = alarmPref.getBoolean("alarm_on", true);
if(hour == alarmHour && min == alarmMin && timeOfDay == alarmTimeOfDay && alarmOn == true
&& alarmStartTime != -1){
startAlarm = true;
}
return;
}
};
clockThread.start();
}
//TODO: Setup the alarm via the menu that inflates here
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.alarm, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item)
{
switch(item.getItemId())
{
case R.id.alarm_settings:
startActivity(new Intent(this, AlarmPopup.class));
Toast.makeText(this, "Open Up Alarm Dialog", Toast.LENGTH_SHORT).show();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
#Override
public void run()
{
while (clockRunnable != null)
{
try
{
Thread.sleep(1000);
} catch (InterruptedException e) { };
handler.post(clockRunnable);
}
}
/** PRIVATE METHODS FOR SIMPLIFICATION **/
private void updateUI(){
if(startAlarm == true){
//AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
alarmStartTime = cal.get(Calendar.SECOND);
currView.setBackgroundColor(Color.RED);
}
else if((cal.get(Calendar.SECOND) - alarmStartTime) > DESIRED_ALARM_DURATION){
alarmStartTime = -1;
startAlarm = false;
currView.setBackgroundColor(Color.WHITE);
}
clock.setText(currTimeString);
}
Obviously I am missing something as far as grasping what is going on, but I can't tell what. Create a background thread, run your processes, pass it through the handler to control the variables, and send those variables through your UI update. I used http://developer.android.com/guide/faq/commontasks.html to gain that understanding.
Instead of making the activity implement Runnable, try this:
TimerTask task = new TimerTask() {
#Override
public void run() {
handler.post(clockRunnable);
}
};
Timer timer = new Timer();
timer.schedule(task, 0, 1000);
Even though I would use a different approach registering a BroadcastReceiver to receive tick actions from the system (every second).
Regards.

CountDownTimer Android issue

I'm trying to implement a CountDownTimer in an Android Application. This timer will, while running, countdown from a value, than reset, than countdown from a different value. Switching back and force between values until either a set number of rounds have elapsed or the stop button has been pressed. I can get the CountDownTimer samples to work, but I guess I'm missing something here. Below is the applicable button press code;
CounterState state = CounterState.WORKOUT;
private WorkoutTimer workoutTimer;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.workout_stopwatch);
requestWindowFeature(Window.FEATURE_NO_TITLE);
// Set up OnClickListeners
((Button) findViewById(R.id.start_button)).setOnClickListener(this);
((Button) findViewById(R.id.stop_button)).setOnClickListener(this);
((Button) findViewById(R.id.reset_button)).setOnClickListener(this);
}
#Override
public void onClick(View v) {
switch(v.getId()) {
case R.id.start_button:
if (!timer_running) {
timer_running = true;
Log.d(TAG, "clicked on Start Button");
// If the state is unknown, set it to Workout first
int State = state.getStateValue();
if (State == 0) {
state.setStateValue(1);
}
workoutTimer.start();
}
break;
case R.id.stop_button:
Log.d(TAG, "clicked on Stop Button");
if (timer_running); {
timer_running = false;
workoutTimer.cancel();
}
break;
private class WorkoutTimer extends CountDownTimer{
public WorkoutTimer(long interval) {
super(getThisTime(), interval);
Log.d(TAG, "WorkoutTimer Constructed...");
}
TextView digital_display = (TextView) findViewById(R.id.digital_display);
TextView numOfRounds = (TextView) findViewById(R.id.number_of_rounds);
public void onFinish() {
int State = state.getStateValue();
int roundsLeft = 0;
if (State == 1) {
state.setStateValue(2);
} else {
state.setStateValue(1);
}
decrementRounds();
try {
roundsLeft = Integer.parseInt(numOfRounds.getText().toString());
} catch(NumberFormatException nfe) {
roundsLeft = 999;
}
if (roundsLeft > 0 || roundsLeft != 999) {
workoutTimer.start();
}
}
public void onTick(long millisUntilFinished) {
final long minutes_left = ((millisUntilFinished / 1000) / 60);
final long seconds_left = (millisUntilFinished / 1000) - (minutes_left * 60);
final long millis_left = millisUntilFinished % 100;
String time_left = String.format("%02d:%02d.d", minutes_left, seconds_left,
millis_left);
digital_display.setText(time_left);
}
}
private long getThisTime() {
long time = 0;
TextView workout_time = (TextView) findViewById(R.id.workout_time);
TextView rest_time = (TextView) findViewById(R.id.rest_time);
switch(state) {
case WORKOUT:
try {
time = Integer.parseInt(workout_time.getText().toString());
} catch(NumberFormatException nfe) {
time = 999;
}
// time = 90;
Log.d(TAG, "Workout time = " + time);
break;
case REST:
try {
time = Integer.parseInt(rest_time.getText().toString());
} catch(NumberFormatException nfe) {
time = 999;
}
// time = 30;
Log.d(TAG, "Rest time = " + time);
break;
case UNKNOWN:
time = 0;
break;
}
return time;
}
Everything starts up okay, but crashes when I click either button. If I comment out my calls to the workoutTimer, no crash. I never see my log in the constructor of the workoutTimer class, so obviously I'm missing something here. Any help would be appreciated.
-Ian
You have not initialized your workoutTimer. You need to add the following line in your onCreate method.
workoutTimer = new WorkoutTimer(...);

dynamic spinner and sharedpreferences

in my android application I have a Button which adds a new dynamic Spinner to the Layout. All of the created Spinners are using the same Array.
What is working until now, I can save the number of created Spinners and recreate them after restarting the Application.
But I really would like to save the selectedPosition of each Spinner in the sharedPreferences and this is where I'm stucking in a ForceClose Desaster...
In my understanding, every Spinner gets an ID when created so you can save the Position bounded on this ID in the preferences.
So this is what I did:
public void addSpinner(){
LinearLayout AddLayout = (LinearLayout)findViewById(R.id.linearAddScroll);
spinner = new Spinner(this);
ArrayAdapter<?> adapt = ArrayAdapter.createFromResource(this,
R.array.Filter, android.R.layout.simple_spinner_item);
adapt.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner.setAdapter(adapt);
AddLayout.addView(spinner);
}
this creates the Spinner.
public void onClick(View v) {
addSpinner();
int ID = 1000+x;
spinner.setId(ID);
Toast.makeText(MatReporterActivity.this,"ID" + ID, 5)
.show();
x++;
}
set the ID.
This is what I do in the on Create method:
x = settings.getInt("xsave", 1);
for(y = 1; y < x; y++){
addSpinner();
int ID = 1000+y;
Spinner s = (Spinner) findViewById(ID);
String ys= Integer.toString(ID);
Toast.makeText(MatReporterActivity.this,"ID" +ys, 5)
.show();
int yf = settings.getInt(ys, 1);
s.setSelection(yf);
}
And this onStop():
SharedPreferences settings = PreferenceManager
.getDefaultSharedPreferences(this);
SharedPreferences.Editor editor = settings.edit();
editor.putInt("xsave", x);
for(y = 1; y < x; y++){
int ID = 1000+y;
Spinner s2= (Spinner) findViewById(ID);
int possS = s2.getSelectedItemPosition();
Toast.makeText(MatReporterActivity.this, "IDStop" + ID, 5)
.show();
String ys= Integer.toString(ID);
editor.putInt(ys, possS);
}
editor.commit();
}
I think there is a logical Problem in the onCreate Method, but I'm not able to find it, also I didn't find any help in the web how to populate and save dynamically created spinners.
So maybe someone has an idea.
thanks.
SharedPreferences are not a good way to store this kind of data. You should try to follow those 2 steps :
Create a class which implements Serializable to represent the data you want to store (you might use a list of Serializable objects)
public class SpinnerSave implements Serializable {
public String ID;
public int selection;
public SpinnerSave(String ID, int selection){
this.ID = ID;
this.selection = selection;
}
}
Then you should write your data into a file like so
private void saveState() {
final File cache_dir = this.getCacheDir();
final File suspend_f = new File(cache_dir.getAbsoluteFile() + File.separator + SUSPEND_FILE);
FileOutputStream fos = null;
ObjectOutputStream oos = null;
boolean keep = true;
try {
fos = new FileOutputStream(suspend_f);
oos = new ObjectOutputStream(fos);
oos.writeObject(this.gameState);
}
catch (Exception e) {
keep = false;
Log.e("MyAppName", "failed to suspend", e);
}
finally {
try {
if (oos != null) oos.close();
if (fos != null) fos.close();
if (keep == false) suspend_f.delete();
}
catch (Exception e) { /* do nothing */ }
}
}

Categories

Resources