I'm totally new to posting questions on here, however I have been reading a lot on here for years. Normally I always am able to find my answers by thoroughly searching the web, but this time I am at a loss...
After having spent yet another day of trying to figure out why this is not working I decided to ask for help, hoping you guys can give me a few pointers, or better, a solution.
The problem:
In an Android game I have come to the point where I have to make the application remember its state when a user e.g. presses the HOME-screen button. After some searches I realised that in order to make my classes initialize back to their appropriate states after re-opening the application I had to support the Parcelable interface to pass them with the Bundle.
In my onStop and onStart functions I respectively save and restore the game state to and from a Bundle, however when I call the putParcelable and getParcelable functions on the Bundle the object's writeToParcel and createFromParcel functions are never called.
Fearing that this may have been due to the relative complexity of the game I figured I had best create a very simple application to try to get it to work.
Based on many Parcelable examples I have seen online, this became my class:
public class ParcelableTest implements Parcelable {
int id;
public ParcelableTest(int newID)
{
id = newID;
}
private ParcelableTest(Parcel in) {
readFromParcel(in);
}
public void writeToParcel(Parcel out, int arg1) {
writeToParcel(out);
}
public void writeToParcel(Parcel out) {
Log.v("ParcelableTest","Writing to parcel");
out.writeInt(id);
}
public void readFromParcel(Parcel in) {
id = in.readInt();
}
public int describeContents() {
return 0;
}
public static final Parcelable.Creator<ParcelableTest> CREATOR = new
Parcelable.Creator<ParcelableTest>() {
public ParcelableTest createFromParcel(Parcel in) {
Log.v("ParcelableTest","Creating from parcel");
return new ParcelableTest(in);
}
public ParcelableTest[] newArray(int size) {
return new ParcelableTest[size];
}
};
}
And from my Main activity I would call the following functions to save / restore the data:
public Bundle saveToBundle(Bundle savedState)
{
savedState.putParcelable("Test1",mTest1);
savedState.putParcelable("Test2",mTest2);
return savedState;
}
public void restoreFromBundle(Bundle savedState)
{
mTest1 = savedState.getParcelable("Test1");
mTest2 = savedState.getParcelable("Test2");
}
But for some reason neither of the functions (with the putParcelable and getParcelable functions) will result in the appropriate Parcelable calls in my test class.
The strangest thing is that it does somehow read the correct values (I have tried with more variables in the class), but my debugging and my log shows that tha application never gets to writeToParcel and createFromParcel.
What am I missing here?
Any help / thoughts would be appreciated.
Apparently the Android Bundle class does not adhere to the parcelable protocol that instead is followed during IPC marshalling.
Instead, it seems like the Bundle implementation just writes and reads the Parcelable object into its own internal map by means of reflection. From a test we did, it seems that the Bundle writes/reads every field defined in your Parcelable-derived class, just because you have declared those fields.
Technically, the documentation doesn't say that writeToParcel or createFromParcel are called from onSaveInstance. As a matter of fact, if you check the savedState in your code you are going to find that it is exactly the same object instance in both the save and the restore cases; it makes sense to avoid serialize-deserialize if you can. OTOH, the documentation doesn't say either that serialization is not done. The conclusion should be that you shouldn't depend on either case, just assume that you get the correct bundle.
Also, you may want to check http://developer.android.com/guide/topics/resources/runtime-changes.html
I confirm what superjos said.
On the saveToBundle event, Android bundle just stores the class's members per reflection and doesn't call the Parcelable functions.
I have lost one day on this problem! sad....
This is really bad .... This means you potentially stores a huge amount of data for nothing using this way.
Related
I am using IntelliJ IDEA and I have problem with method usage finding.
Suppose I have interface Worker.
public interface Worker {
void startWork();
void endWork();
}
And I have two implementations.
public class Develper implements Worker {
#Override
public void startWork() {
System.out.println("Developer Start Working");
}
#Override
public void endWork() {
}
}
public class Qa implements Worker {
#Override
public void startWork() {
System.out.println("QA start Work");
}
#Override
public void endWork() {
}
}
I open the Developer class and trying to find usages of startWork().
I want only to view usage of the Developer.startWork() implemented method.
But when I find usages it shows both Developer and Qa.startWork() method usages. How can I avoid Qa.startWork() method usage when finding Developer.startWork() usages?
Using Ctrl+Shift+Alt+F7 (⌘+⇧+⌥+F7 for Mac) should show the prompt from Jim Hawkins answer.
See: https://www.jetbrains.com/help/idea/find-usages-method-options.html
When you search for usages of a method implementation with this dialog Ctrl+Shift+Alt+F7, IntelliJ IDEA will ask whether or not you want to search for the base method. With any other find usages actions such as Alt+F7 or Ctrl+Alt+F7, the base method will be included in the search results automatically.
I'm using IntelliJ IDEA 15.0.1 .
I think what you see when using the "find usages" functionality depends from the context.
If you place the cursor in method name Developer.startWork and invoke find usages , you should see a small dialog. You are asked "Do you want to find usages of the base method?" .
If you say "No", and in your sources you did only call the method via the base class or interface (Worker.start() in your example), IDEA doesn't show you any hits. Thats correct.
If you call the overridden method via Developer.startWork() , and press "No" in the dialog, then you will see the usages of the specific implementation.
Update:
After reading the answer from #JimHawkins, I think the elephant is still in the room :) The question is, do you want to see where Developer.startWork() is actually called, or do you want to see where it is statically referenced?
Eg:
Developer developer = new Developer();
developer.startWork(); // you want to find only this?
Worker worker = developer;
worker.startWork(); // ..or this as well?
The find usages method can only tell, where a given method is statically referenced, but not where it is actually used (that is determined runtime via the mechanism of polymorphism).
I currently have developed an app with some GUI and network operations, but I need to make it more of a library without the GUI.
I know that there is a "is library" option under Properties/Android. But the question is: how to move the GUI elements out of the project to a different app, so that the library/project will have only java code; any suggestion ?
Thanks.
If you are making code into a library, you want to try and decouple it as much as you can from anything else. This makes it much more portable so that more people can use the library how they wish. Even though you are using this library just for yourself right now, later on you may wish to release it to others.
For example, maybe your code is like this currently:
public void computeSum(int a, int b) {
int sum = a + b;
mTextView.setText(String.valueOf(sum));
}
Right now this code is tightly coupled with mTextView. Instead, it makes sense to rewrite the code like this:
//In library
public int computeSum(int a, int b) {
return a+b;
}
and
//Somewhere in your app
mTextView.setText(String.valueOf(computeSum(3,4)));
This is a small change, but you can see that computeSum() is no longer coupled with mTextView. This makes it much easier to use throughout your project and even other projects. Now the computeSum() method is part of an API.
So for your network calls, try to decouple them from your GUI stuff either by using callbacks or return values.
In regards to your latest comment:
You could create a wrapper like so:
public class UIWrapper {
public Runnable runnable;
public SomeUiCallback callback;
}
And then use this in your AsyncTask:
public class YourTask extends AsyncTask<UIWrapper, Void, Void> {
SomeUiCallback mCallback;
protected void doInBackground(UIWrapper... wrapper) {
mCallback = UiWrapper.callback;
UIWrapper.runnable.run();
}
protected void onProgressUpdate() {
}
protected void onPostExecute() {
mCallback.runYourUiStuff();
}
}
I wrote that code quickly so it likely won't compile, but hopefully you get the idea. I think something like this would work, not sure if it's the most elegant solution. You can replace the Runnable with whatever you want to run in the thread.
So both UIWrapper and YourTask would reside in your library. You would create the UIWrapper and then use that in the YourTask.
Recently I've had some problems with people cheating using an app for root users called Gamecih. Gamecih let's users pause games and change variables in runtime.
If I obfuscate my code I though it'll be hard for cheaters to know what variables to change in runtime, but I'm also worried it might cause some other problems.
I serialize game objects using Javas Serializable interface and then write them out to a file. Now let's say I'm serializing an object of the class "Player". It gets serialized and saved to a file. Then a user downloads the update with the Proguard implementation. Proguard will rename classes and class member names. Won't that cause major errors when trying to read in an already saved Player object?
If I had not yet launched my game, this wouldn't be a problem. But now some players are playing on the same saved game(it's an RPG) for months. They would be pretty pissed off if they downloaded an update and had to start over from scratch.
I know I can instruct Proguard not to obfuscate certain classes, but it's the Player class I really need to obfuscate.
Clarification: Let's say I have the following simple unobfuscated class:
public class Player {
private int gold;
private String name;
//Lots more.
public Player(String name)
{
this.name = name;
}
public int getGold() {
return gold;
}
public void setGold(int gold) {
this.gold = gold;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
A player is created, serialized and saved to a file. After I implement obfuscator, it might look like this:
public class Axynasf {
private int akdmakn;
private String anxcmjna;
public Axynasf(String adna)
{
anxcmjna=adna;
}
public int getAkdmakn() {
return akdmakn;
}
public void setAkdmakn(int akdmakn) {
this.akdmakn = akdmakn;
}
public String getAnxcmjna() {
return anxcmjna;
}
public void setAnxcmjna(String anxcmjna) {
this.anxcmjna = anxcmjna;
}
}
Imagine that I post an update now and a player that has an unobfuscated version of Player downloads that update. When trying to read that Object there will be different member names and a different class name. I'll most likely get ClassCastException or something of the sorts.
No expert in Proguard, but I think you're right to assume it is going to break serialisation.
One possible way of solving this might be to implement a layer over your current save structure - You can tell Proguard which classes you don't want to obfuscate. Leave the Player (and alike objects) the same for now and don't obfuscate. Once the object has been de-serialised, pass it up to your new layer (which is obfuscated) which the rest of the game deals with - if you don't retain the non-obfuscated object, then it'll cause cheaters problems tweaking during game play (although not at load time). At the same time, you could look at moving your player's game files over to another save option that doesn't depend on serialisation, which will probably make such issues easier in the future.
For ensuring compatible serialization in ProGuard:
ProGuard manual > Examples > Processing serializable classes
For upgrading a serialized class to a different class in Java:
JDK documentation > Serialization > Object Input Classes > readResolve
JDK documentation > Serialization > Object Serialization Examples > Evolution/Substitution
I understand ppl can update vars # runtime w/ the app you named.
If you change the member names, the values will still give hints.
If you obfuscate, the class name will change but new name will end on a forum anyway.
So this is not enough
What you could do in your update is, at startup, load serialized data in old object, transfer to "new" obfuscated class, use a custom serialization (with an XOR using the deviceID value or the gmail adress so to make it less obvious).
Try to have your player data into several classes too.
What I would do in your situation:
Release an update with obfuscated and non-obfuscated class. When player gets loaded it will try with both classes. If player got loaded with non-obf. class then map this class to your obfuscated class.
When player gets saved it will save with obfuscated class.
After a proper amount of time release an update with only the obfuscated classes.
Coming from a non-Java background, I find myself writing a lot of View classes with extensive functionality (in an effort to be portable), that don't necessarily fit nicely into the Android FW setup as far as maintenance - for example, I might have a widget that does something on a interval that I want to stop and clean up when an Activity is paused/stopped/destroyed. Generally I can manage this by just calling a public method on the widget from the containing Activity, but A) sometimes this gets pretty deep, and having to create a public method to access a child in every parent can get ugly, and B) requires extra (uneeded?) attention.
I'm considering using an approach like a global delegate to manage this kind of thing, but have read a lot of warnings about this sort of approach - would something like the class that follows have any inherent flaws that I might be missing?
import java.util.HashMap;
import java.util.HashSet;
public class ActiveRegistry {
private static final ActiveRegistry instance = new ActiveRegistry();
public static ActiveRegistry getInstance(){
return instance;
}
private HashMap<String, HashSet<Runnable>> registry = new HashMap<String, HashSet<Runnable>>();
private ActiveRegistry(){
}
public void register(String key, Runnable runnable){
if(!registry.containsKey(key)){
HashSet<Runnable> list = new HashSet<Runnable>();
registry.put(key, list);
}
HashSet<Runnable> list = registry.get(key);
list.add(runnable);
}
public void execute(String key){
if(registry.containsKey(key)){
HashSet<Runnable> list = registry.get(key);
for(Runnable runnable : list){
runnable.run();
}
}
}
}
Use might be something like...
A View has something that needs to be cleaned up. On instantiation, register it... ActiveRegistry.getInstance().register("paused", someRunnableThatCleansUpStuff)
Extend Activity so that onPause calls ActiveRegistry.getInstance().execute("paused");
You are doing way more work than you need to. Using Fragments (from the support package, if you want to ensure backwards compatibility with older versions of android), will make your life a whole lot easier. Each fragment is embedded in an activity and has a lifecycle that is directly linked with its host activity's lifecycle. Using them should significantly reduce the complexity of your code, as most of what you are currently worrying about will be managed by the system instead.
I've created a few minor apps for Android while learning. Being a PHP developer, it's a challenge to get used to it.
I'm especially wondering how I could define a couple of "general" functions in a separate class. Eg I have a function that checks if network connection is available, and if not, shows a dialog saying that the user should enable it. Currently, that function exists in several of my activities. Of course that seems strange - I suppose it would be more logical to define it once and include it in the activites where needed.
I tried putting it in a new class, and included that class in the original activity. But that failed since eg getBaseContext() is not accepted anymore.
I'm wondering how to go ahead. What should I be Google-ing for ? What is this mechanism called?
You need to create class with static methods. Like this
public class HelperUtils {
public static void checkNetworkConnection(Context ctx) {...}
}
Then you can call it from any place like this:
HelperUtils.checkNetworkConnection(this.getContext());
Assuming current class has Context.
You should read books on general OOP concepts where different type of methods are explained.
You can for example create a class - let's call it NetworkUtils. In this class you can create static method boolean isNetworkConnectionAvailable() and return true if is available and false otherwise. In this class you can create another static method void showNoConnectionDialog(Activity activity) - and in this method you create dialog starting with
public static void showNoConnectionDialog(Activity activity) {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
//setting message, listener etc. and finally
builder.create().show();
}
In your activity, where you want to check and handle network connection you should call:
if (!NetworkUtils.isConnectionAvailable(getApplicationContext())) {
NetworkUtils.showNoConnectionDialog(YourActivityClassName.this)
}
I guess this should work.