How do I save the Custom Spinner state - java

I extended android.widget.Spinner. and added an int field to my implementation. Now I want it to save the field value on orientation change. My first thought was using Bundle object for that:
override fun onSaveInstanceState(): Parcelable {
val bundle = Bundle()
bundle.putParcelable(SUPER_STATE, super.onSaveInstanceState())
bundle.putInt(PREV_ITEM, this.prevItem) // ... save stuff
return bundle
}
override fun onRestoreInstanceState(state: Parcelable?) {
val newState: Parcelable
if (state is Bundle) {
this.prevItem = state.getInt(PREV_ITEM) // ... load stuff
newState = state.getParcelable<Parcelable>(SUPER_STATE)
super.onRestoreInstanceState(newState)
}
super.onRestoreInstanceState(state)
}
But I get an error:
java.lang.ClassCastException: android.os.Bundle cannot be cast to android.widget.Spinner$SavedState
So I found Spinner source code and figured out that I have to extend inner static class SavedState and use it to save my field value. But I wasn't able to do that. Android Studio suggests that it "Cannot resolve symbol 'Saved State'".
So what do I do to save the state of my custom Spinner?

You cannot actually extend Spinner.SavedState because it created inside Spinner class. Even if you try to override Spinner.onSaveInstanceState you cannot implement this method in your custom class, because you don't have access to private variables of Spinner class.
What you can actually do is to create new class implementing Parcelable and use value returned from base class to construct your own class.
#Override
public Parcelable onSaveInstanceState() {
final MySavedState ss = new MySavedState(super.onSaveInstanceState());
ss.myInt = 100;
return ss;
}
#Override
public void onRestoreInstanceState(Parcelable state) {
MySavedState ss = (MySavedState) state;
super.onRestoreInstanceState(ss.getSuperState());
if(ss.myInt == 100) {
Log.d("TAG", "Success!");
}
}
static class MySavedState extends Spinner.BaseSavedState {
int myInt;
public MySavedState(Parcelable superState) {
super(superState);
}
public MySavedState(Parcel source) {
super(source);
myInt = source.readInt();
}
}

Related

in PreferenceFragmentCompat Bluetooth's object open Android Java

I'm writing an app and I'm not really getting anywhere.
I have a class called SettingsFragmentForBLT that derives from PreferenceFragmentCompat. In it I handle user input from onPreferenceChange. Here you have the option of making settings for the Bluetooth device with which the smartphone is already paired when the class is called up. I rule the BLT matters in the class called DeviceControlActivity.
I need to expose THE handling object from DeviceControlActivity in the SettingsFragmentForBLT class so that I can pass the data to the BLT device at the time of input from the user. As far as I know, I have to overload the constructor of the DeviceControlActivity for this. My attempt refers to this website:
https://sciodoo.de/konstruktor-im-java-programm-ein-objekt-uebermachen/#
Here is the code from the SettingsFragmentForBLT class:
public static class SettingsFragmentForBLT extends PreferenceFragmentCompat implements
Preference.OnPreferenceChangeListener {
#Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
addPreferencesFromResource(R.xml.blt_preferences);
// A listener is used to monitor preference changes in PreferencFragmnt (BLT).
Preference preferenceFeedbackIstAn = findPreference("FeedbackIstAn");
preferenceFeedbackIstAn.setOnPreferenceChangeListener(this);
Preference preferenceSwitchfeedback = findPreference("seek_bar_key");
preferenceSwitchfeedback.setOnPreferenceChangeListener(this);
}
#Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
String preferenceKey = preference.getKey();
DeviceControlActivity deviceControlActivity = new DeviceControlActivity();
DeviceControlActivity msBluetoothLeService = new deviceControlActivity.getmBluetoothLeService(deviceControlActivity);
// BluetoothLeService mBluetoothLeService
Boolean switchOn = (boolean) newValue;
if (preferenceKey.equals("FeedbackIsAn")) {
deviceControlActivity.toggleLEDGren();
Log.w(TAG, "preferenceValue: " + newValue);
if (switchOn) {
if (msBluetoothLeService != null) {
msBluetoothLeService.writeCustomCharacteristic(53);
Log.w(TAG, "Green has been turned on");
}
...
Here is the code from DeviceControlActivity:
public class DeviceControlActivity extends AppCompatActivity{
...
public DeviceControlActivity(BluetoothLeService mBluetoothLeService) {
this.mBluetoothLeService = mBluetoothLeService;//Assignment with this
}
public void getmBluetoothLeService(DeviceControlActivity createdObject){
this.mBluetoothLeService = createdObject.mBluetoothLeService;
}
...
Thank you for your support and I wish you a pleasant time
I tried to create an object from DeviceControllActivity class in SettingsFragmentForBLT class

Is my method to update textview from a volley response the 'Android way' the right way?

I have a fragment that sets the textViews from a data object. This data object is initially null when the fragment is created but gets updated after a network request. Now to update the textviews I create a function 'updateAll' and pass the fragment to the callback function that handles the network response. And once the data is set to the data object I call 'updateAll' from the fragment reference.
Example :
class someFragment extends Fragment {
private Textview foo;
private dataObject obj;
...
public onCreate(...) {
this.obj = new dataObject();
sendRequestToVolley(..., new VolleyCallbacks(this));
}
public onCreateView(...) {
...
foo.setText(obj.someVar);
}
public void updateAll() {
foo.setText(obj.someVar);
}
}
class VolleyCallbacks implements someInterface {
public VolleyCallbacks(someFragmment fragment, dataObject obj) {
this.obj = obj;
this.fragment = fragment;
}
public onSuccess(Response r) {
obj.updateData(r);
this.fragment.updateAll();
}
}
Is this the correct way to do this? Is there a better method?
You code looks mainly good. I see one issue: you're keeping the Fragment as a strong reference. It can generate a memory leak if the fragment is destroyed (ie. the user presses back) before the network call is completed. To prevent that, you should use a WeakReference.
I also wouldn't modify your data object inside the callback class. It's better to let the fragment modify it since he is the one holding the reference to it.
I would transform your code like that:
public class SomeFragment extends Fragment {
private Textview foo;
private dataObject obj;
...
public onCreate(...) {
this.obj = new dataObject();
sendRequestToVolley(..., new VolleyCallbacks(this));
}
public onCreateView(...) {
...
refreshTextView();
}
private void refreshTextView() {
foo.setText(obj.someVar);
}
void onRequestSuccess(Response r) {
obj.updateData(r);
refreshTextView();
}
}
class VolleyCallbacks implements SomeInterface {
private WeakReference<SomeFragment> fragmentWeak;
public VolleyCallbacks(SomeFragment fragment) {
this.fragmentWeak = new WeakReference<>(fragment);
}
public onSuccess(Response r) {
SomeFragment fragment = this.fragmentWeak.get();
if (fragment != null) {
fragment.onRequestSuccess(r);
}
}
}

how to access java class in android activity from putting it in a package?

I m calling it in method by creating function with the java class from another package..
private void drawRegressionLine() {
//Toast.makeText(MainActivity.this, "Regression line view ", Toast.LENGTH_SHORT).show();
ArrayList<String> point = new ArrayList<String>();
Algorithm algorithm = new MaxLikelihood() {
point = c.KNN(point);
plot(point);
};`
package firstpackagename;
import secondpackagename.*; /*add other necessary imports*/
public class MainActivity extends Activity {#
Override public void onCreate(Bundle s) {
super.onCreate(s);
TheClassInOtherPackage X = new TheClassInOtherPackage(); /*If empty constructor used*/
Object o = X.methodInOtherpackage(params1, params2, ....); /*Replace this with X.methodInOtherpackage(...) if method returns voids. Replace object o with the proper return type*/
}
}
Note - You can also return values from the constructor by adding a return type to it just like the methods. Hope this helps. :)

Reading ArrayList in Parcelable

I have a class called SuperMedia that implements Parcelable. One of the fields of the class is an ArrayList children. When I create a Bundle and try to pass a "SuperMedia" object from one activity to another, all the fields get passed fine with the exception of the ArrayList "children" which just shows up as being empty every time.
In my first Activity I do:
Bundle a = new Bundle();
a.putParcelable("media",media); //media is an object of type "SuperMedia" and all the "children" have been initialized and added to the array
final Intent i = new Intent("com.tv.video.subcategories");
i.putExtra("subcategories", a);
On my Second Activity I do:
Intent i = getIntent();
Bundle secondBun = i.getBundleExtra("subcategories");
SuperMedia media = secondBun.getParcelable("media"); //For some reason the ArrayList"children" field shows up as empty.
Im not sure why this is happening. If anybody can guide me on the right path that would be greatly appreciated. Below is my SuperMedia class btw.
public class SuperMedia implements Parcelable{
public URI mthumb;
public String mTitle;
public ArrayList<SuperMedia> children = new ArrayList();
public SuperMedia(URI thumb, String title) {
this.mthumb = thumb;
this.mTitle = title;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
// TODO Auto-generated method stub
dest.writeString(mTitle);
dest.writeString(mthumb.toString());
dest.writeTypedList(children);
}
public static final Parcelable.Creator<SuperMedia> CREATOR = new Parcelable.Creator<SuperMedia>() {
public SuperMedia createFromParcel(Parcel in) {
return new SuperMedia(in);
}
public SuperMedia[] newArray(int size) {
return new SuperMedia[size];
}
};
private SuperMedia(Parcel in) {
mTitle = in.readString();
try {
mthumb = new URI(in.readString());
} catch (URISyntaxException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
in.readTypedList(children, SuperMedia.CREATOR);
}
public SuperMedia(){
}
}
If you want simply pass object through intent then you can make SuperMedia Serializable no need to Parcelable.
public class SuperMedia implements Serializable{...}
put it as
Bundle a = new Bundle();
a.putSerializable("media",media);
and we get it as.
Intent i = getIntent();
Bundle secondBun = i.getBundleExtra("subcategories");
SuperMedia media = (SuperMedia)secondBun.getSerializable("media");
if you really needed Parcelable then may it help you.
Arraylist in parcelable object
Use Bundle's putParcellableArrayList for storing SuperMedia object
Bundle args = new Bundle();
args.putParcelableArrayList("media", "media");
and for restroring
getArguments().getParcelableArrayList("media");
This way will ensure bundle save your list objects as implemented in parcelable instance.
Also, be aware of using only ArrayList, other List subclasses not supported.

Android getter setter returns null data?

I have one class ApplicationDetails, with getter and setter methods.
public class ApplicationDetails {
String supportURL;
String companyURL;
String copyRightText;
// with getter and setter methods
}
I am setting all data in my splash screen activity.
ApplicationDetails appDetails = new ApplicationDetails();
String supportURL = getResources().getString(R.string.support_url);
appDetails.setSupportURL(supportURL);
For sample I just setting data from string file but in app its coming from different sources.
But when I tried to access data in different activity its returns null value.
e.g.
public class AboutViewController extends Activity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ApplicationDetails appDetails = new ApplicationDetails();
System.out.println(" app support url " + appDetails.getSupportURL());
}
}
output
I/System.out(2242): app support url null
any help.
You get null, because you create a new object and all fields are initialized to zero.
In your case, I see these fields are going to be the same through application, so you can use a Singleton pattern and instantiate only one object for your application and refer to it later on. You don't need to create a new object each time you refer to it. It would be ok for this class and you can also make them constants. (I guess these variables won't change through execution)
As fast solution you can make your supportURL object static, but this isn't good solution.
public class ApplicationDetails {
static String supportURL;
static String companyURL;
static String copyRightText;
// with getter and setter methods
}
better solution is to pass strings from one activity to another with intents, when you are starting your AboutViewController Activity.
You can use the shared preference to store data to be used through your application.
Here the Context in the constructor is nothing but your Activity.
public class ApplicationDetails {
public static final String SUPPORT_URL = "support_url";
public static final String COMPANY_URL = "company_url";
public static final String COPYRIGHT_URL = "copyright_url";
String supportURL;
String companyURL;
String copyRightText;
private Context context;
public ApplicationDetails(Context context) {
super();
this.context = context;
}
private String getPreference(String key)
{
return PreferenceManager.getDefaultSharedPreferences(context).getString(key, null);
}
private void setPreference(String key, String value)
{
PreferenceManager.getDefaultSharedPreferences(context).edit().putString(key, value).commit();
}
public String getSupportURL() {
if(supportURL == null)
supportURL = getPreference(SUPPORT_URL);
return supportURL;
}
public void setSupportURL(String supportURL) {
this.supportURL = supportURL;
setPreference(SUPPORT_URL, supportURL);
}
public String getCompanyURL() {
if(supportURL == null)
supportURL = getPreference(COMPANY_URL);
return companyURL;
}
public void setCompanyURL(String companyURL) {
this.companyURL = companyURL;
setPreference(COMPANY_URL, companyURL);
}
public String getCopyRightText() {
if(copyRightText == null)
copyRightText = getPreference(COPYRIGHT_URL);
return copyRightText;
}
public void setCopyRightText(String copyRightText) {
this.copyRightText = copyRightText;
setPreference(COPYRIGHT_URL, copyRightText);
}
}
Thanks all for all suggestions. Now I am using only one instance of a class.
public class ApplicationDetails {
private static ApplicationDetails instance = null;
String supportURL;
String companyURL;
String copyRightText;
// with getter and setter methods
public static ApplicationDetails getInstance() {
if (instance == null) {
instance = new ApplicationDetails();
}
return instance;
}
}
And I am setting and getting like this
ApplicationDetails appDetails = ApplicationDetails.getInstance();
appDetails.setSupportURL(supportURL);
and in activity
ApplicationDetails appDetails = ApplicationDetails.getInstance();
appDetails.getSupportURL();
Its wrks fine.
Update
As you setting value in Splash screen that object in memory was different and in another activity you creating another object that also different in memory that's why you getting null.
If this was your requirement to init url in splash screen and used in another then there are many ways.
You directly get the string in your activity as you getting in splash screen.
In splash screen make appDetails object as public static so you can access in another activities also
Implement serialization on ApplicationDetails and put this object in putExtra as we put string,int etc value for passing data between activity and get this data using bundle in started activity
Edited
For using single object you need make that object declare as public static in splash screen
public static ApplicationDetails appDetails;
now assign value in splash screen oncreate() and used in another activity or even another class also like this way
public class AboutViewController extends Activity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// direct use object by class name
System.out.println(" app support url " + SplashScreen.appDetails.getSupportURL());
}
}

Categories