I am trying to save displayed time of a chronometer by onSaveInstanceState(Bundle savedInstanceState). However, there is already an onSaveInstanceState(Bundle outState) in my code, so I see the warning of "onSaveInstanceState(Bundle) is already defined in the scope".
How can I use both Bundle savedInstanceState and Bundle outstate?
Here is the onSaveInstanceState method(s):
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt("CLICK_NUMBER", clickNumber);
outState.putBoolean(BUTTON2CORRECT_CHECKED_KEY, answer2.isChecked());
outState.putBoolean(BUTTON21_CHECKED_KEY, wrongAnswer21.isChecked());
outState.putBoolean(BUTTON22_CHECKED_KEY, wrongAnswer22.isChecked());
outState.putBoolean(BUTTON23_CHECKED_KEY, wrongAnswer23.isChecked());
outState.putBoolean(BUTTON3CORRECT_CHECKED_KEY, answer3.isChecked());
outState.putBoolean(BUTTON31_CHECKED_KEY, wrongAnswer31.isChecked());
outState.putBoolean(BUTTON32_CHECKED_KEY, wrongAnswer32.isChecked());
outState.putBoolean(BUTTON33_CHECKED_KEY, wrongAnswer33.isChecked());
outState.putBoolean(CHECKBOX41_CHECKED_KEY, answer41.isChecked());
outState.putBoolean(CHECKBOX42_CHECKED_KEY, answer42.isChecked());
outState.putBoolean(CHECKBOX43_CHECKED_KEY, answer43.isChecked());
outState.putBoolean(CHECKBOX44_CHECKED_KEY, answer44.isChecked());
outState.putBoolean(CHECKBOX45_CHECKED_KEY, answer45.isChecked());
outState.putBoolean(BUTTON5CORRECT_CHECKED_KEY, answer5.isChecked());
outState.putBoolean(BUTTON51_CHECKED_KEY, wrongAnswer51.isChecked());
outState.putBoolean(BUTTON_CLICKED_KEY, buttonIsClicked);
answer2.setTextColor(0xAA76FF03);
answer3.setTextColor(0xAA76FF03);
answer5.setTextColor(0xAA76FF03);
answer41.setTextColor(0xAA76FF03);
answer42.setTextColor(0xAA76FF03);
answer43.setTextColor(0xAA76FF03);
}
#Override
protected void onSaveInstanceState(Bundle savedInstanceState) {
super.onSaveInstanceState(savedInstanceState);
savedInstanceState.putString("myVar", myVar);
}
Here is the onCreate method:
protected void onCreate(Bundle savedInstanceState) { // TODO
Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.html_new_page);
chronometer = findViewById(R.id.chronometer);
chronometer.start();
myVar = chronometer.getText().toString();
if (savedInstanceState == null) {
myVar = chronometer.getText().toString();
} else {
myVar = savedInstanceState.getString("myVar");
}
they are actually the same thing! the name is just a dummy variable which you can easily change with no problem.
You code could be:
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt("CLICK_NUMBER", clickNumber);
...
answer43.setTextColor(0xAA76FF03);
// new code here
outState.putString("myVar", myVar);
}
or you can use
protected void onSaveInstanceState(Bundle savedInstanceState) {
super.onSaveInstanceState(outState);
savedInstanceState.putInt("CLICK_NUMBER", clickNumber);
...
answer43.setTextColor(0xAA76FF03);
// new code here
savedInstanceState.putString("myVar", myVar);
}
It will be the same thing as long as you change the name in the argument.
Related
I have an application with several Forms. Two of them are quite similar, they have features in the form of VCL objects (labels, images, etc...) in common, which I named the same.
I want to have a function in a specific class which can accept one of these two Form as a parameter in order to modify the parameters that they have in common. The solution I came around does not seem to work.
As my application is quite big and complicated, I replicated the problem using a small example.
First, below is an example of my MainForm :
And an example of one subForm (they are all arranged in a similar way)
I have an additionnal class which is used to fill in the Edits on the subForms. The code for this class is the following:
#pragma hdrstop
#include "master_class.h"
#include "sub_Form2.h"
#include "sub_Form3.h"
#include "sub_Form4.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
Master::Master(void)
{
}
Master::~Master(void)
{
}
void Master::WriteToForm(TForm* Form)
{
TForm2* curForm = static_cast<TForm2*>(Form);
TForm3* self = dynamic_cast<TForm3*>(Form);
TForm2* self2 = dynamic_cast<TForm2*>(Form);
if (self != NULL && self2 == NULL) {
TForm3* curForm = static_cast<TForm3*>(Form);
}
else if (self == NULL && self2 != NULL) {
TForm2* curForm = static_cast<TForm2*>(Form);
}
curForm -> Edit1 -> Text = "blablabla_1";
curForm -> Edit2 -> Text = "blablabla_2";
}
And in the MainForm, the code for the "Fill Form2" button is the following:
Master1 -> WriteToForm(Form2);
where Master1 is just an object of the Master class.
This works very well for Form2 :
But for Form3, which is filled up using Master1 -> WriteToForm(Form3), here is what I get, which the same pb than in my real application:
So what should go to the Edit, is misplaced. I think the main pb comes from the fact that I did not create every label, edit, etc... on the same order. I did that on purpose to mimic my real application. To verify this, I created a 3rd subForm, where this time the VCL objects were created in the same order as my first subForm, and this works:
So I would suspect that this comes from the initial cast
TForm2* curForm = static_cast<TForm2*>(Form);
When I pass Form3 as an argument, Form3 is somewhat casted into the "shape" of Form2, which is not defined in the same order. Maybe this could be corrected by modifying directly the DFM file, but it is not a realistic approach for my main app.
I do this initial cast otherwise I get a compilation error saying that curForm is not known at the first line
curForm -> Edit1 -> Text = "blablabla_1";
So, is there a better way to pass the Form as an argument to the WriteToForm function?
Just because two types are similar does not mean they are related. Your code does not work because your two Form classes are not related to each other in any way. You can't just cast one to the other arbitrarily.
To solve this, you have several options:
code for both Form classes separately, eg:
void Master::WriteToForm(TForm* Form)
{
TForm2* curForm2 = dynamic_cast<TForm2*>(Form);
TForm3* curForm3 = dynamic_cast<TForm3*>(Form);
if (curForm2)
{
curForm2->Edit1->Text = _D("blablabla_1");
curForm2->Edit2->Text = _D("blablabla_2");
}
else if (curForm3)
{
curForm3->Edit1->Text = _D("blablabla_1");
curForm3->Edit2->Text = _D("blablabla_2");
}
}
Or:
void WriteToForm(TForm2* Form);
void WriteToForm(TForm3* Form);
...
void Master::WriteToForm(TForm2* Form)
{
Form->Edit1->Text = _D("blablabla_1");
Form->Edit2->Text = _D("blablabla_2");
}
void Master::WriteToForm(TForm3* Form)
{
Form->Edit1->Text = _D("blablabla_1");
Form->Edit2->Text = _D("blablabla_2");
}
Make your function use a template (however, be aware of this: Why can templates only be implemented in the header file?):
template<typename T>
void WriteToForm(T* Form);
...
void Master::WriteToForm<T>(T* Form)
{
Form->Edit1->Text = _D("blablabla_1");
Form->Edit2->Text = _D("blablabla_2");
}
make the two Form classes derive from a common base class or interface, eg:
class TBaseForm : public TForm
{
public:
inline __fastcall TBaseForm(TComponent *Owner) : TForm(Owner) {}
virtual void SetEdit1(const String &Text) = 0;
virtual void SetEdit2(const String &Text) = 0;
};
...
class TForm2 : public TBaseForm
{
...
public:
__fastcall TForm2(TComponent *Owner);
...
void SetEdit1(const String &NewText);
void SetEdit2(const String &NewText);
};
__fastcall TForm2::TForm2(TComponent *Owner)
: TBaseForm(Owner)
{
...
}
void TForm2::SetEdit1(const String &NewText)
{
Edit1->Text = NewText;
}
void TForm2::SetEdit2(const String &NewText)
{
Edit2->Text = NewText;
}
...
repeat for TForm3...
...
void Master::WriteToForm(TBaseForm* Form)
{
Form->SetEdit1(_D("blablabla_1"));
Form->SetEdit2(_D("blablabla_2"));
}
Or:
__interface INTERFACE_UUID("{E900785E-0151-480F-A33A-1F1452A431D2}")
IMyIntf : public IInterface
{
public:
virtual void SetEdit1(const String &Text) = 0;
virtual void SetEdit2(const String &Text) = 0;
};
...
class TForm2 : public TForm, public IMyIntf
{
...
public:
__fastcall TForm2(TComponent *Owner);
...
void SetEdit1(const String &NewText);
void SetEdit2(const String &NewText);
};
__fastcall TForm2::TForm2(TComponent *Owner)
: TForm(Owner)
{
...
}
void TForm2::SetEdit1(const String &NewText)
{
Edit1->Text = NewText;
}
void TForm2::SetEdit2(const String &NewText)
{
Edit2->Text = NewText;
}
...
repeat for TForm3...
...
void Master::WriteToForm(IMyIntf* Intf)
{
Intf->SetEdit1(_D("blablabla_1"));
Intf->SetEdit2(_D("blablabla_2"));
}
use RTTI to access the fields, eg:
#include <System.Rtti.hpp>
void Master::WriteToForm(TForm* Form)
{
TRttiContext Ctx;
TRttiType *FormType = Ctx.GetType(Form->ClassType());
TRttiField *Field = FormType->GetField(_D("Edit1"));
if (Field)
{
TValue value = Field->GetValue(Form);
if( (!value.Empty) && (value.IsObject()) )
{
TObject *Obj = value.AsObject();
// Either:
static_cast<TEdit*>(Obj)->Text = _D("blablabla_1");
// Or:
TRttiProperty *Prop = Ctx.GetType(Obj->ClassType())->GetProperty(_D("Text"));
if (Prop) Prop->SetValue(Obj, String(_D("blablabla_1")));
}
}
Field = FormType->GetField(_D("Edit2"));
if (Field)
{
TValue value = Field->GetValue(Form);
if( (!value.Empty) && (value.IsObject()) )
{
TObject *Obj = value.AsObject();
// Either:
static_cast<TEdit*>(Obj)->Text = _D("blablabla_2");
// Or:
TRttiProperty *Prop = Ctx.GetType(Obj->ClassType())->GetProperty(_D("Text"));
if (Prop) Prop->SetValue(Obj, String(_D("blablabla_2")));
}
}
}
I am working on two apps, in one of my app "A" i applied retrofit 2.
This was the method i used to retrieve data.
But here in on Response the data retrieved in response body can be set to activity variables and can be used outside this method without getting null values.
public void fetch_information() {
ApiInterface = ApiClient.getApiClient().create(Api.class);
Call<List<City>> call = ApiInterface.GetCities();
call.enqueue(new Callback<List<City>>() {
#Override
public void onResponse(Call<List<City>> call, Response<List<City>> response) {
citylist = new ArrayList<City>();
citylist = response.body();
cities = new String[citylist.size()];
citiesid = new String[citylist.size()];
for (int i = 0; i < citylist.size(); i++) {
cities[i] = citylist.get(i).getCityName();
citiesid[i] = citylist.get(i).getCityId();
}
city_adapter = new ArrayAdapter<String>(Pay_Payment_X.this, android.R.layout.simple_list_item_1, cities);
city_adapter.setDropDownViewResource(R.layout.spinner_dropdown_layout);
City_Spinner.setAdapter(city_adapter);
}
#Override
public void onFailure(Call<List<City>> call, Throwable t) {
Toast.makeText(getApplicationContext(), t.getMessage(), Toast.LENGTH_SHORT).show();
}
});
}
after applying this method and on debugging this method i will retain values of varaibles "cities" and "citiesid"out side onResponse.
But applying retrofit 2 similarly on another app "B", i did the same thing for retrieving data on different URL.
ApiUtil.getServiceClass().getAllPost().enqueue(new Callback<List<ApiObject>>() {
#Override
public void onResponse(Call<List<ApiObject>> call, Response<List<ApiObject>> response) {
if (response.isSuccessful()) {
List<ApiObject> postList = response.body();
try {
for (int i = 0; i < postList.size(); i++) {
String Name = postList.get(i).getGamesName();
mGamesName.add(Name);
}
} catch (Exception e) {
}
Log.d(TAG, "Returned count " + postList.size());
NewAdapter adapter = new NewAdapter(getApplicationContext(), postList);
recyclerView.setAdapter(adapter);
}
}
#Override
public void onFailure(Call<List<ApiObject>> call, Throwable t) {
//showErrorMessage();
Log.d(TAG, "error loading from API");
}
});
the data is retrievable inside onResponse but outside it shows null.
So here variables are not retaining values.
Why is this happening?
the only thing came to mind is retrieving data can take time while your code lines are being read and finding null values as data has not been received yet.
Also to mention in app "A" the data retrieved is huge but in app "B" only 3 objects with string values.But still in app"A" data is retrievable.
In app 2 did this for resolving my issue.
public void doRequest( final ApiCallback callback){
ApiUtil.getServiceClass().getAllPost().enqueue(new Callback<List<ApiObject>>() {
#Override
public void onResponse(Call<List<ApiObject>> call, Response<List<ApiObject>> response) {
if (response.isSuccessful()) {
List<ApiObject> postList = response.body();
callback.onSuccess(postList);
// apobject =response.body();
if(response.isSuccessful()) {
try {
for (int i = 0; i < postList.size(); i++) {
String Name = postList.get(i).getGamesName().toString();
mGamesName.add(Name);
}
} catch (Exception e) {
}
}
Log.d(TAG, "Returned count " + postList.size());
NewAdapter adapter = new NewAdapter(getApplicationContext(), postList);
recyclerView.setAdapter(adapter);
}
}
#Override
public void onFailure(Call<List<ApiObject>> call, Throwable t) {
//showErrorMessage();
Log.d(TAG, "error loading from API");
}
});
}
pass an interface
public interface ApiCallback{
void onSuccess(List<ApiObject> result);
}
and in on Create view of activity i called this
doRequest(new ApiCallback(){
#Override
public void onSuccess(List<ApiObject> result){
//here i can set variable values
}
});
the only thing came to mind is retrieving data can take time while your code lines are being read and finding null values as data has not been received yet.
That's entirely correct. Your call is finishing after you check the values. I'm going to go on a limb here and say that it's just a coincidence that it works on one app and not in the other (if they are actually doing it the same way)
When you call callback.onSuccess(postList); doesn't seem to be right either, because you haven't checked yet for success. This means that response.body() might be null and response.errorBody() will contain the body of the error.
If you'd move callback.onSuccess inside the if this would be fixed:
if(response.isSuccessful()) {
callback.onSuccess(response.body());
try {
for (int i = 0; i < postList.size(); i++) {
String Name = postList.get(i).getGamesName().toString();
mGamesName.add(Name);
}
} catch (Exception e) {
}
Last but not least, inside the onSuccess method is when you can use your global variables. Maybe it's better to stop using global variables and just use the callback parameters.
After lots of research on implementing IntentServices and Alarms together, I've come up with this. I don't know exactly what happens with this code so I need help in knowing exactly what is going on.
public class MainActivity{
//....
public void onNewItemAdded(String[] _entry){
//...
Intent intent = new Intent(MainActivity.this, UpdateService.class);
startService(intent);
}
//....
}
public class AlarmReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
Intent startIntent = new Intent(context, UpdateService.class);
context.startService(startIntent);
}
public static final String ACTION_REFRESH_ALARM = "com.a.b.ACTION_REFRESH_ALARM";
}
public class UpdateService extends IntentService{
//...
#Override
public void onCreate() {
super.onCreate();
alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
String ALARM_ACTION = AlarmReceiver.ACTION_REFRESH_ALARM;
Intent intentToFire = new Intent(ALARM_ACTION);
alarmIntent = PendingIntent.getBroadcast(this, 0, intentToFire, 0);
}
#Override
protected void onHandleIntent(Intent intent) {
Context context = getApplicationContext();
SharedPreferences prefs = PreferenceManager
.getDefaultSharedPreferences(context);
int updateFreq = Integer.parseInt(prefs.getString(
PreferencesActivity.PREF_UPDATE_FREQ, "60"));
boolean autoUpdateChecked = prefs.getBoolean(
PreferencesActivity.PREF_AUTO_UPDATE, false);
if (autoUpdateChecked) {
int alarmType = AlarmManager.ELAPSED_REALTIME_WAKEUP;
long timeToRefresh = SystemClock.elapsedRealtime() + updateFreq
* 60 * 1000;
alarmManager.setInexactRepeating(alarmType, timeToRefresh,
updateFreq * 60 * 1000, alarmIntent);
}
else {
alarmManager.cancel(alarmIntent);
}
refreshKeywords();
}
}
My aim is to get the refreshKeywords() method to be called every minute. Also, what happens if the onNewItemAdded() method is called more than once?
Sorry if this question is stupid, I'm a beginner.
If you wish you to call refreshKeywords()method to be called every minutes why do you use AlarmManager like this,
private void ServiceRunningBackground() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT)
{
final int restartAlarmInterval = 6000;
final int resetAlarmTimer = 2*1000;
final Intent restartIntent = new Intent(this, MyService.class);
restartIntent.putExtra("ALARM_RESTART_SERVICE_DIED", true);
final AlarmManager alarmMgr = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
Handler restartServiceHandler = new Handler()
{
#Override
public void handleMessage(Message msg) {
PendingIntent pintent = PendingIntent.getService(getApplicationContext(), 0, restartIntent, 0);
alarmMgr.set(AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime() + restartAlarmInterval, pintent);
sendEmptyMessageDelayed(0, resetAlarmTimer);
}
};
restartServiceHandler.sendEmptyMessageDelayed(0, 0);
}
}
Just call this method where ever you want and set the time accordingly
I think my question has a straight forward answer, I just can't seem to find it.
I have a basic workflow:
private void doWorkflow() {
Promise<Boolean> result = activityClient.checkSomething();
if (result.get() == true) {
//exit
}
activityClient.doSomething();
}
The first problem is I cannot seem to get the result within the workflow. I have to go to an #asynchronous method to get the result. Secondly, if I were to use an #asynchronous method to determine if I should exit early then I'm back to square one since #asynchronous methods need to return a promise.
Thanks in advance
I would rewrite your code as:
private void doWorkflow() {
Promise<Boolean> result = activityClient.checkSomething();
doSomething(result);
}
#Asynchronous
private void doSomething(Promise<Boolean> flag) {
if (!flag.get()) {
activityClient.doSomething();
}
}
If you don't want to use #Asynchronous method you can use Task directly:
private void doWorkflow() {
final Promise<Boolean> result = activityClient.checkSomething();
new Task(result) {
public void do Execute() {
if (!result.get()) {
activityClient.doSomething();
}
}
};
}
I'm having trouble trying to use scaletempo with a playbin in Vala. I've created the playbin, and then created a bin to store the additional plugins swapping out the default audio sink. The example below I grabbed from pyTranscribe and converted to Vala but the Element.link_many is causing an error and I'm not quite sure why.
Am I going about this the right way? Does anybody have any other suggestions?
/* SoundPlayerBackend.vala */
/* Modified code from Damien Radtke's site. http://damienradtke.org/ */
using Gst;
public class SoundPlayerBackend {
//Constants
const double PLAYBACK_RATE_MODIFIER = 2.0;
const int SEEK_SECONDS = 10;
// Method delegates for notifying SoundPlayer about certain events
protected delegate void NotifyEos();
protected delegate void NotifyError(string message);
// Pointer to our EOS delegate
protected NotifyEos on_eos;
// Pointer to our Error delegate
protected NotifyError on_error;
public static void main(string[] args){
var soundplayer = new SoundPlayerBackend();
Gst.init(ref args);
soundplayer.setUri("file:///home/codenomad/Desktop/player-project/hurricane.mp3");
soundplayer.play();
string stop = stdin.read_line ();
while (stop != "stop") {
if (stop == "pause") { soundplayer.pause(); }
else if (stop == "play") { soundplayer.play(); }
stop = stdin.read_line ();
}
}
// Read-only reference to the current sound object
public dynamic Element sound { get; private set; }
// Read-only "is playing" property
public bool is_playing { get; private set; default = false; }
// Read-only "rate" property
public double rate { get; private set; default = 1; }
public void setUri(string uri) {
// Make sure any existing allocated resources are freed
if (sound != null)
sound.set_state(Gst.State.NULL);
sound = ElementFactory.make("playbin2", "playbin");
sound.uri = uri;
var audiobin = new Bin("audioline");
var scaletempo = ElementFactory.make("scaletempo", "scaletempo");
var convert = ElementFactory.make("audioconvert", "convert");
var resample = ElementFactory.make("audioresample", "resample");
var audiosink = ElementFactory.make("autoaudiosink", "audiosink");
audiobin.add_many(scaletempo, convert, resample, audiosink);
//edited based on comment below
//Element.link_many(scaletempo, convert, resample, audiosink);
scaletempo.link_many(convert, resample, audiosink);
var pad = scaletempo.get_pad("sink");
audiobin.add_pad(new GhostPad("sink", pad));
sound.set_property("audio-sink", audiobin);
sound.get_bus().add_watch(on_event);
}
// Play the sound
public void play() {
sound.set_state(State.PLAYING);
print("Playing\n");
is_playing = true;
}
// Pause it
public void pause() {
sound.set_state(State.PAUSED);
is_playing = false;
print("Paused\n");
}
// Event bus, listens for events and responds accordingly
protected bool on_event(Gst.Bus bus, Message message) {
switch (message.type) {
case MessageType.ERROR:
GLib.Error err;
string debug;
sound.set_state(Gst.State.NULL);
is_playing = false;
message.parse_error(out err, out debug);
on_error(err.message);
break;
case MessageType.EOS:
sound.set_state(Gst.State.READY);
is_playing = false;
on_eos();
break;
default:
break;
}
return true;
}
}
I tried using the same code making everything static and received the same outcome/error below:
SoundPlayerBackend.vala:121.9-121.67: error: Access to instance member `Gst.Element.link_many' denied
Element.link_many(scaletempo, convert, resample, audiosink);
Thanks in advance!
That line should read
scaletempo.link_many(convert, resample, audiosink);