RoboSpice + Google HTTP Client + GSON = failed to parse JSON to object - android

I'm using RoboSpice with Google HTTP Client & GSON this way:
ApiSpiceService:
public class ApiSpiceService extends GoogleHttpClientSpiceService {
private static final int THREAD_COUNT = 3;
#Override
public CacheManager createCacheManager(Application application) throws CacheCreationException {
CacheManager cacheManager = new CacheManager();
GsonObjectPersisterFactory gsonObjectPersisterFactory = new GsonObjectPersisterFactory(application);
cacheManager.addPersister(gsonObjectPersisterFactory);
return cacheManager;
}
#Override
public int getThreadCount() {
return THREAD_COUNT;
}
}
Request:
public class InfoRequest extends GoogleHttpClientSpiceRequest<Contact> {
private final String url;
public InfoRequest() {
super(Contact.class);
this.url = "some-url/path.json";
}
#Override
public Contact loadDataFromNetwork() throws Exception {
HttpTransport httpTransport = new NetHttpTransport();
HttpRequestFactory httpRequestFactory = httpTransport.createRequestFactory(new InfoHttpRequestInitializer());
HttpRequest httpRequest = httpRequestFactory.buildGetRequest(new GenericUrl(url));
httpRequest.setParser(new GsonFactory().createJsonObjectParser());
return httpRequest.execute().parseAs(Contact.class);
}
private class InfoHttpRequestInitializer implements HttpRequestInitializer {
#Override
public void initialize(HttpRequest request) throws IOException {
}
}
}
Model (Contact.java):
public class Contact {
private String data;
}
BaseActivity:
public abstract class BaseActivity extends ActionBarActivity {
protected SpiceManager spiceManager = new SpiceManager(ApiSpiceService.class);
#Override
protected void onStart() {
super.onStart();
spiceManager.start(this);
}
#Override
protected void onStop() {
spiceManager.shouldStop();
super.onStop();
}
}
And MainActivity:
public class MainActivity extends BaseActivity {
private InfoRequest infoRequest;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
infoRequest = new InfoRequest();
}
#Override
protected void onStart() {
super.onStart();
spiceManager.execute(infoRequest, "txt", DurationInMillis.ALWAYS_EXPIRED, new TextRequestListener());
}
private class TextRequestListener implements RequestListener<Contact> {
#Override
public void onRequestFailure(SpiceException spiceException) {
//
}
#Override
public void onRequestSuccess(Contact s) {
//
}
}
It seems to be valid code, but, unfortunately, when it finish the request execution, field data in returned Contact instance is null.
There are no errors in logcat.
The requested content is 100% valid JSON. Why it is not being parsed?

Ok, I've found the solution. I need to add #Key annotation to fields in model. It's strange, because pure Gson does not require this.
public class Contact {
#Key
private String data;
}

Related

Xposed - I can print inner class methods, but method hooking doesn't work

I'm trying to hook a method in inner class, but nothing happen, while I can print all the methods of that class.
All of the logs printed except which is in the replaceHookedMethod.
public class Keyguard implements IXposedHookLoadPackage {
#Override
public void handleLoadPackage(XC_LoadPackage.LoadPackageParam lpparam) throws Throwable {
if (!lpparam.packageName.equals("com.android.keyguard"))
return;
XposedBridge.log("we are in keyguard!");
Class HwClockView = XposedHelpers.findClass("com.android.keyguard.AbsClockView$HwClockView",
lpparam.classLoader);
for (Method m : HwClockView.getDeclaredMethods()) {
XposedBridge.log("method: " + m.getName());
}
XposedHelpers.findAndHookMethod(HwClockView, "getDateString",
TimeZone.class, new XC_MethodReplacement() {
#Override
protected Object replaceHookedMethod(MethodHookParam param) throws Throwable {
XposedBridge.log("we are in getDateString!");
return String.format("%s", Utils.getPersianDateShort());
}
});
}
Update:
After second comment changed code to this, but same as before nothing happens:
public class Keyguard implements IXposedHookLoadPackage {
#Override
public void handleLoadPackage(XC_LoadPackage.LoadPackageParam lpparam) {
if (!lpparam.packageName.equals("com.android.keyguard"))
return;
XposedBridge.log("we are in keyguard!");
Class HwClockView = XposedHelpers.findClass("com.android.keyguard.AbsClockView$HwClockView",
lpparam.classLoader);
for (Method m : HwClockView.getDeclaredMethods()) {
XposedBridge.log("method: " + m.getName());
if ("getDateString".equalsIgnoreCase(m.getName())) {
XposedBridge.hookMethod(m, new XC_MethodReplacement() {
#Override
protected Object replaceHookedMethod(MethodHookParam param) {
XposedBridge.log("we are in getDateString!");
return String.format("%s", Utils.getPersianDateShort());
}
});
}
}
}
Target class:
public class AbsClockView extends RelativeLayout {
protected Calendar mCalendar;
private HwCustKeyguardStatusViewEx mCustKeyguardStatusViewEx;
protected TextView mDateView;
protected TextView mDescriptionView;
protected Factory mFactory;
protected final AtomicBoolean mFixedTimeZone;
protected FrameLayout mTimeParent;
protected TextView mTimeView;
public interface Factory {
void refreshDate();
void setHwDateFormat();
void updateHwTimeStyle();
}
private class HwClockView implements Factory {
protected Context mContext;
public HwClockView(Context context) {
...
}
private CharSequence getDateString(TimeZone timeZone) {
return someString;
}
}
public AbsClockView(Context context) {
this(context, null);
}
}

My Class in not an enclossing class

so I have class constructor:
public class HealthDataStore { // this class is 3rd party api - can't modify
public HealthDataStore(Context context, HealthDataStore.ConnectionListener listener){ /* bla... */ }
/* bla... */
// with Listener Interface:
public interface ConnectionListener {
void onConnected();
void onConnectionFailed(HealthConnectionErrorResult var1);
void onDisconnected();
}
}
and in my repository class i have:
public class HealthRepository {
private string DSConnectionStatus;
public void connectDataStore(HealthDSConnectionListener listener) {
mStore = new HealthDataStore(app, listener);
mStore.connectService();
}
// with inner class:
public class HealthDSConnectionListener implements HealthDataStore.ConnectionListener{
#Override public void onConnected() { DSConnectionStatus = "Connected"; }
#Override public void onConnectionFailed(HealthConnectionErrorResult healthConnectionErrorResult) { DSConnectionStatus = "Connection Failed"; }
#Override public void onDisconnected() { DSConnectionStatus = "Disconnected"; }
};
}
and in my view model class i have below object:
public class SplashViewModel extends AndroidViewModel {
public void connectRepoDataStore(){
// repo is object of class HealthRepository
repo.connectDataStore(mConnectionListener)
// other things to do here
}
private final HealthRepository.HealthDSConnectionListener mConnectionListener = new HealthRepository.HealthDSConnectionListener(){
#Override public void onConnected() {
super.onConnected(); // i need this super to set DSConnectionStatus value
// other things to do here
}
#Override public void onConnectionFailed(HealthConnectionErrorResult error) {
super.onConnectionFailed(error); // i need this super to set DSConnectionStatus value
// other things to do here
}
#Override public void onDisconnected() {
super.onDisconnected(); // i need this super to set DSConnectionStatus value
// other things to do here
}
}
why is private final HealthRepository.HealthDSConnectionListener mConnectionListener = new HealthRepository.HealthDSConnectionListener() throw me error that the class is not enclosing class?
then how should i achieve this? to have my final listener class have capability to set DSConnectionStatus in healthrepository class?
Always try to avoid using inner classes if you know you'll have to extend them. Instead use a separate class, and swap the outer class with a field. If you need to modify a private field that you do not want to expose then create a package-private setter.
public class HealthRepository {
private String DSConnectionStatus;
public void connectDataStore(HealthDSConnectionListener listener) {
mStore = new HealthDataStore(app, listener);
mStore.connectService();
}
void setConnectionStatus(String status) {
DSConnectionStatus = status;
}
}
// create another class in the same package
public class HealthDSConnectionListener implements HealthDataStore.ConnectionListener {
private final HealthRepository repo;
public HealthDSConnectionListener(HealthRepository repo) {
this.repo = repo;
}
#Override public void onConnected() { repo.setConnectionStatus("Connected"); }
#Override public void onDisconnected() { repo.setConnectionStatus("Disconnected"); }
#Override public void onConnectionFailed(HealthConnectionErrorResult error) {
repo.setConnectionStatus("Connection Failed");
}
};
public class SplashViewModel extends AndroidViewModel {
private final HealthRepository repo;
public void connectRepoDataStore() {
// repo is object of class HealthRepository
repo.connectDataStore(mConnectionListener)
// other things to do here
}
private final HealthDSConnectionListener mConnectionListener = new HealthDSConnectionListener(repo) {
#Override public void onConnected() {
super.onConnected();
// ...
}
#Override public void onConnectionFailed(HealthConnectionErrorResult error) {
super.onConnectionFailed(error);
// ...
}
#Override public void onDisconnected() {
super.onDisconnected();
// ...
}
}
}

Android comunicate between library and app

I'm creating a library in Android and I want to pass some values (strings) from the library to the app that is using the library after some events. The app that uses the library has only one screen to display the strings sent by the library.
My app has a MainActivity that will populate an listView with the events received by the library.
It also have an MyApp that extends Application.
Here I'm doing this:
public class MyApp extends Application{
private static MyApp sMyApp;
public MyApp() {
}
#Override
public void onCreate() {
super.onCreate();
sMyApp= this;
MyLibrary.getInstance().setApplication(sMyApp);
}
public static MyApp getInstance() {
return sMyApp;
}
}
In my library:
public class MyLibrary {
private static MyLibrary sInstance = new MyLibrary();
private Application mMyApp;
public static MyLibrary getInstance() {
return sInstance;
}
private MyLibrary() {
}
public void setApplication(Application myApp) {
mMyApp = myApp;
}
public void sendEventMessage(String message) {
mMyApp.setEvent(message);
}
}
I've tried to implement an interface in MainActivity so that mMyApp.setEvent(message); could send a message that MainActivity could receive but with no success.
How can I achieve what I pretend?
You could try callback as this sample:
Firstly, declare your callback inside library
public interface ILibrary {
public void onStart(String msg);
public void onProcess(String msg);
public void onFish(String msg);}
public class SDK {
private static final String START = "I'm started";
private static final String PROCESSING = "I'm running";
private static final String STOP = "I'm done";
private ILibrary mCallback;
// Make it easy for demo
public SDK(ILibrary callback) {
mCallback = callback;
}
public void start() {
mCallback.onStart(START);
}
public void process() {
mCallback.onProcess(PROCESSING);
}
public void stop() {
mCallback.onFish(STOP);
}}
And then do something like that:
SDK sdk = new SDK(new ILibrary() {
#Override
public void onStart(String msg) {
Log.d("TAG", msg);
}
#Override
public void onProcess(String msg) {
Log.d("TAG", msg);
}
#Override
public void onFish(String msg) {
Log.d("TAG", msg);
}
});
AsyncTask<Void, Void, Void> asyncTask = new AsyncTask<Void, Void, Void>() {
#Override
protected Void doInBackground(Void... params) {
sdk.process();
return null;
}
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
sdk.stop();
}
#Override
protected void onPreExecute() {
super.onPreExecute();
sdk.start();
}
};
asyncTask.execute();

Android retrofit get json object

I am using retrofit library for a web service that expect request as json and give response as json.
public class GitHubClient extends Activity{
private static final String API_URL = "http://10.0.0.32/test";
static class Contributor {
String login;
int contributions;
}
public static class Array {
public String id;
public String name;
}
class Contributor1 {
public Array array;
}
interface Login {
#POST("/testapp/")
Contributor1 mu(#Body User user,Callback<Contributor1> callBack);
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
new myasyncclass().execute();
}
public class User {
public String mail;
public String password;
}
public class myasyncclass extends AsyncTask<Void, Void, Void>{
#Override
protected Void doInBackground(Void... params) {
// Create a very simple REST adapter which points the GitHub API endpoint.
RestAdapter restAdapter = new RestAdapter.Builder()
.setServer(API_URL)
.build();
Login login = restAdapter.create(Login.class);
User user=new User();
user.mail="ttete";
user.password="tett";
Contributor1 contributors = login.mu(user,new Callback<Contributor1>() {
#Override
public void failure(RetrofitError error) {
System.out.println("failure, error: " + error);
}
#Override
public void success(Contributor1 result, Response arg1) {
System.out.println("success, result: " + result);
}
});
return null;
}
}
}
This is my entire class .But i am getting the following error
Caused by: java.lang.IllegalArgumentException: Method mu may only have return type or Callback as last argument, not both.
What should i do overcome this error?
This interface definition is wrong as per the error.
interface Login {
#POST("/testapp/")
Contributor1 mu(#Body User user,Callback<Contributor1> callBack);
}
You should modify it to
interface Login {
#POST("/testapp/")
Contributor1 mu(#Body User user);
}
Since now it does not have a callback, you should be able to call it synchronously.

issue with calling Fragment class' method

I have a class "HomeActivity", which is as follows:
public class HomeActivity extends FragmentActivity implements OnClickListener {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
FragmentManager fm = getSupportFragmentManager();
// Create the list fragment and add it as our sole content.
if (fm.findFragmentById(android.R.id.content) == null) {
HomeFragment list = new HomeFragment();
fm.beginTransaction().add(android.R.id.content, list).commit();
}
}
public static class HomeFragment extends Fragment {
webServiceTask = WebServiceTask.getInstance(
getActivity(), Constants.METHOD_NAME_PRODUCTS,
Constants.PRODUCT_NAME, null);
public void Work() {}
}
}
I have another class WebServiceTask, which is as follows:
final public class WebServiceTask extends AsyncTask<String, String, String> {
private WebServiceTask(final Activity activity, final String methodName,
final String productName, final String addInfo[]) {
super();
this.activity = activity;
this.methodName = methodName;
this.productName = productName;
this.addInfo = addInfo;
}
public static WebServiceTask getInstance(final Activity activity,
final String methodName, final String productName,
final String additionalInfo[]) {
webServiceTask = new WebServiceTask(activity, methodName, productName,
additionalInfo);
return webServiceTask;
}
protected void onPostExecute() {
// Here I am trying to call the work() method in HomeFragment, How can I do that?
}
My question is how can i call the work() method in HomeFragment class from onPostExecute().
I would propose making a listener for you task, and invoke its method in post execute. It will geve you a lot more flexibility and control on what you want to deafter the task finishes. Here is sample code I would use:
public class MyTask extend AsyncTask<Void, Void, Boolean> {
public interface MyTaskListener {
void onSuccess();
void onFailure();
void onError(Throwable t);
}
private Throwable error;
private MyTaskListener listener;
public MyTask(MyTaskListener listener) {
this.listener = listener;
}
#Overrride
public Boolean doInBackground(Void... params) {
try {
if (workCompleted()) {
//work completed without error - return true
return Boolean.TRUE;
} else {
//work failed to complete - return false
return Boolean.FALSE;
}
} catch(Exception e) {
//unexpected error happened - remember error and return null
this.error = e;
return null;
}
}
#Override
public void onPostExecute(Boolean result){
if (!isCancelled()) { //you only want to process if task wasn't cancelled
if (this.error != null && result == null) { //we have error, process it
if (listener != null) {
listener.onError(this.error);
}
}
if (Boolean.FALSE.equals(result)) { //we have faile, process it
if (listener != null) {
listener.onFail();
}
}
if (Boolean.TRUE.equals(result)) { //we have success
if (listener != null) {
listener.onSuccess();
}
}
}
}
}
And then, in you activit/fragment/service/ use something like this:
public class MyActivity extends Activity {
private void someInstanceMethod() {/ *do your work here */}
#Override
public void onCreate(Bundle savedInstanceState) {
//setup ui, or do whatever you need
//create MyAsyncTask with proper listener
MyAsyncTask task = new MyAsyncTask(new MyAsyncTask.MyAsyncTaskListener() {
#Override
public void onSuccess() {
//call your instance method here
someInstanceMethod();
}
#Override
public void onFailure() {
//process fail
}
#Override
public void onError() {
//process error
}
});
}
}
This is one method. I don't know if it is the best one:
Make work function as public static void. Call it from Asynctask onpostexecute as
HomeActivity.Work();
Edit:
One more way( again not sure if this is the best way):
If you cant make this work, consider putting your asynctask class inside the home activity class
Well using the FragmentManger findFragmentById() or findFragmentByTag() you can get an instance of the current fragment and call your fragment method.
Create an interface file
public interface AsynAction
{
public void Work();
}
Implements AsynAction in HomeActivity
public class HomeActivity extends FragmentActivity implements OnClickListener,AsyncAction {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
FragmentManager fm = getSupportFragmentManager();
// Create the list fragment and add it as our sole content.
if (fm.findFragmentById(android.R.id.content) == null) {
HomeFragment list = new HomeFragment();
fm.beginTransaction().add(android.R.id.content, list).commit();
}
}
public static class HomeFragment extends Fragment {
webServiceTask = WebServiceTask.getInstance(
getActivity(), Constants.METHOD_NAME_PRODUCTS,
Constants.PRODUCT_NAME, null);
#Override
public void Work()
{
}
}
}
Then make changes in you asynctask to receive asyncAction object as reference
final public class WebServiceTask extends AsyncTask<String, String, String> {
private WebServiceTask(final AyscAction asycAction,final Activity activity, final String methodName,
final String productName, final String addInfo[]) {
super();
this.activity = activity;
this.asycAction=asycAction;
this.methodName = methodName;
this.productName = productName;
this.addInfo = addInfo;
}
public static WebServiceTask getInstance(final AyscAction asycAction,final Activity activity,
final String methodName, final String productName,
final String additionalInfo[]) {
webServiceTask = new WebServiceTask(asycAction,activity, methodName, productName,
additionalInfo);
return webServiceTask;
}
protected void onPostExecute() {
// You can call work from here
if(asynAction!=null)
asyncAction.Work();
}

Categories

Resources