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);
}
}
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();
// ...
}
}
}
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();
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.
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();
}