I am going to use Xposed Bridge API to customize my status bar on my Android phone.
Hooking methods are working pretty well, but there's a problem.
public class WPSModule implements IXposedHookLoadPackage {
final int ICON_SIZE = 100;
FrameLayout FlStatusBar;
...
void HideWidget(FrameLayout FlLayout, String Name)
{
int ViewId = FlLayout.getResources().getIdentifier(Name, "id", "com.android.systemui");
if(ViewId == 0)
{
XposedBridge.log("Failed to find resource " + Name + " on systemui package.");
return;
}
View v = FlLayout.findViewById(ViewId);
if(v == null)
{
XposedBridge.log("v == null with resource " + Name + " on systemui package.");
return;
}
v.setVisibility(View.INVISIBLE);
}
public static TextView TvText = null;
public void handleLoadPackage(final LoadPackageParam LppParam) throws Throwable {
if (!LppParam.packageName.equals("com.android.systemui"))
return;
XposedBridge.log("WPS: SystemUI package found.");
//Hook
findAndHookMethod("com.android.systemui.statusbar.phone.PhoneStatusBarView", LppParam.classLoader, "onFinishInflate", new XC_MethodHook() {
#Override
protected void beforeHookedMethod(MethodHookParam MhpParam) throws Throwable {
// this will be called before the clock was updated by the original method
}
#Override
protected void afterHookedMethod(MethodHookParam MhpParam) throws Throwable {
FlStatusBar = (FrameLayout) MhpParam.thisObject;
}
});
....
}
}
And when I try to use FlStatusBar like this:
HideWidget(FlStatusBar, "notification_lights_out");
It doesn't work. On Xposed's log...
07-31 20:22:09.962 E/Xposed (18737): java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.res.Resources android.widget.FrameLayout.getResources()' on a null object reference.
Other things which uses FlStatusBar doesn't work too..(ex: FlStatusBar.toString() gives me NullPointerException)
Related
java.lang.IllegalStateException: Can not perform this action inside of
onLoadFinished
at android.app.FragmentManagerImpl.checkStateLoss(FragmentManager.java:1886)
at android.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1905)
at android.app.BackStackRecord.commitInternal(BackStackRecord.java:688)
at android.app.BackStackRecord.commit(BackStackRecord.java:646)
at android.app.DialogFragment.dismissInternal(DialogFragment.java:312)
at android.app.DialogFragment.dismiss(DialogFragment.java:278)
Why I am getting this crash in play store console for some of my users. This is not device or OS specific.
I am not doing any UI related transaction in onLoadFinished. I am executing ABCAsyncTask, and in onPostExecute of it, i am calling pausehandler to execute the UI.
Additionally, As I am using two cursors, so onLoadFinished in called twice here.
#Override
public void onLoadFinished(Loader<Cursor> cursorLoader, Cursor cursor) {
if (cursor == null) {
Log.e(LOG_TAG, "cursor is null");
return;
}
(new ABCAsyncTask(this, cursorLoader, cursor)).execute();
}
ABCAsyncTask ->
onPostExecute() {
LoadItemPauseHandlerObject loadItemPauseHandlerObject = new LoadItemPauseHandlerObject ();
Message responseMessage = new Message();
responseMessage.what = 1; // some int
responseMessage.obj = loadItemPauseHandlerObject;
pauseHandler.sendMessage(responseMessage);
}
In android OS source code:
void callOnLoadFinished(Loader<Object> loader, Object data) {
if (mCallbacks != null) {
String lastBecause = null;
if (mHost != null) {
lastBecause = mHost.mFragmentManager.mNoTransactionsBecause;
mHost.mFragmentManager.mNoTransactionsBecause = "onLoadFinished";
}
try {
if (DEBUG) Log.v(TAG, " onLoadFinished in " + loader + ": "
+ loader.dataToString(data));
mCallbacks.onLoadFinished(loader, data);
} finally {
if (mHost != null) {
mHost.mFragmentManager.mNoTransactionsBecause = lastBecause;
}
}
mDeliveredData = true;
}
}
since finally {} block will always be executed synchronously after try {} block in the main thread, and in onLoadFinished() i am not doing any fragment transaction directly, so, mNoTransactionsBecause should reset to lastBecause then why this crash is coming for some of my users?
I am using :
android.app.LoaderManager android.app.Activity android.app.Fragment
Try adding check
isAdded()
in your handleMessage() method of your handler possibly it would be in your Fragment.
Let me know if you have further doubt
So I have quite a few model classes in my project and have a singleton class which makes Retrofit calls to convert between the model classes. The method getUsersFromChats in that class takes in an array of Chat model objects, converts each object to a User model object, and adds them to a public ArrayList of User objects.
Code:
//These are instantiated in another method and are not null.
public static ArrayList<User> users;
private static int index;
public void getUsersFromChats(Chat[] chats) {
if (index < chats.length) {
Call<UserResponse> getUser = AuthRetrofitClient
.getInstance()
.getAuthApi()
.getUserById(chats[index].getUserID());
getUser.enqueue(new Callback<UserResponse>() {
#Override
public void onResponse(Call<UserResponse> call, Response<UserResponse> response) {
if (response.isSuccessful()) {
UserResponse ur = response.body();
Log.i("User", ur.getUser().getName());
users.add(ur.getUser());
Log.i("List", users.toString());
index++;
getUsersFromChats(chats);
} else {
try {
String errorBody = response.errorBody().string();
int index = errorBody.indexOf("\"message\":");
if (index != -1) {
String errorSub = errorBody.substring(index + 10);
//errorBody = errorSub.substring(1, errorSub.length() - 2);
}
Toast.makeText(context, errorBody, Toast.LENGTH_SHORT).show();
} catch (IOException e) {
e.printStackTrace();
}
}
}
#Override
public void onFailure(Call<UserResponse> call, Throwable t) {
Log.i("Didn't work", t.toString());
}
});
}
}
I have an Activity which calls that method after getting an array of Chat objects from a Retrofit call and tries to save ArrayList from the singleton class to a local User objects ArrayList.
Call<ChatListResponse> getAllContacts = ChatRetrofitClient
.getInstance()
.getChatAPI()
.loadChats(SharedPrefManager.getInstance(ChatActivity.this).getUser().getToken());
getAllContacts.enqueue(new Callback<ChatListResponse>() {
#Override
public void onResponse(Call<ChatListResponse> call, Response<ChatListResponse> response) {
if(response.isSuccessful()){
ChatListResponse clr = response.body();
if(clr.getChats() == null || clr.getChats().length < 1)
createChat();
else{
for(Chat c: clr.getChats())
Log.i("Testing", c.getUserID());
ConvertFieldsToUserObjects.getInstance(ChatActivity.this).getUsersFromChats(clr.getChats());
ArrayList<User> users = ConvertFieldsToUserObjects.users;
Log.i("Testing", users.toString());
for(User u: users)
Log.i("Testing", u.getId());
Log.i("Testing", person.getId());
if(users.contains(person)){
int i = users.indexOf(person);
chat = clr.getChats()[i];
Toast.makeText(ChatActivity.this, chat.getName(), Toast.LENGTH_SHORT).show();
}
However, this code doesn't work and the local ArrayList is always empty even though the Chat objects list obtained from the Call contains elements. Does this have something to do with the Retrofit calls being asynchronous or is it something else? (The API's, RetrofitClients, and the Response objects work fine as far as I have tested.)
When coding a Minecraft plugin in java, you can create an event listener method, and name it whatever you want, but you have to pass in the class of the event listener, for example:
#EventListener
public void onPlayerJoin(PlayerJoinEvent event) {
// code here
}
I am just wondering, how is this method executed 'behind the scenes', if the name of the method is not known by any class in the Bukkit API? I hope I explained myself well. Thanks
When registering an instance that implements Listener, Bukkit will use reflection to check every method in that class with the #EventHandler annotation and with one argument that extends Event. It will be stored in a registry and will be called when the event occurs.
Edit: The source code below may be of interest to you. Source
#Override
#NotNull
public Map<Class<? extends Event>, Set<RegisteredListener>> createRegisteredListeners(#NotNull Listener listener, #NotNull final Plugin plugin) {
Validate.notNull(plugin, "Plugin can not be null");
Validate.notNull(listener, "Listener can not be null");
boolean useTimings = server.getPluginManager().useTimings();
Map<Class<? extends Event>, Set<RegisteredListener>> ret = new HashMap<Class<? extends Event>, Set<RegisteredListener>>();
Set<Method> methods;
try {
Method[] publicMethods = listener.getClass().getMethods();
Method[] privateMethods = listener.getClass().getDeclaredMethods();
methods = new HashSet<Method>(publicMethods.length + privateMethods.length, 1.0f);
for (Method method : publicMethods) {
methods.add(method);
}
for (Method method : privateMethods) {
methods.add(method);
}
} catch (NoClassDefFoundError e) {
plugin.getLogger().severe("Plugin " + plugin.getDescription().getFullName() + " has failed to register events for " + listener.getClass() + " because " + e.getMessage() + " does not exist.");
return ret;
}
for (final Method method : methods) {
final EventHandler eh = method.getAnnotation(EventHandler.class);
if (eh == null) continue;
// Do not register bridge or synthetic methods to avoid event duplication
// Fixes SPIGOT-893
if (method.isBridge() || method.isSynthetic()) {
continue;
}
final Class<?> checkClass;
if (method.getParameterTypes().length != 1 || !Event.class.isAssignableFrom(checkClass = method.getParameterTypes()[0])) {
plugin.getLogger().severe(plugin.getDescription().getFullName() + " attempted to register an invalid EventHandler method signature \"" + method.toGenericString() + "\" in " + listener.getClass());
continue;
}
final Class<? extends Event> eventClass = checkClass.asSubclass(Event.class);
method.setAccessible(true);
Set<RegisteredListener> eventSet = ret.get(eventClass);
if (eventSet == null) {
eventSet = new HashSet<RegisteredListener>();
ret.put(eventClass, eventSet);
}
for (Class<?> clazz = eventClass; Event.class.isAssignableFrom(clazz); clazz = clazz.getSuperclass()) {
// This loop checks for extending deprecated events
if (clazz.getAnnotation(Deprecated.class) != null) {
Warning warning = clazz.getAnnotation(Warning.class);
WarningState warningState = server.getWarningState();
if (!warningState.printFor(warning)) {
break;
}
plugin.getLogger().log(
Level.WARNING,
String.format(
"\"%s\" has registered a listener for %s on method \"%s\", but the event is Deprecated. \"%s\"; please notify the authors %s.",
plugin.getDescription().getFullName(),
clazz.getName(),
method.toGenericString(),
(warning != null && warning.reason().length() != 0) ? warning.reason() : "Server performance will be affected",
Arrays.toString(plugin.getDescription().getAuthors().toArray())),
warningState == WarningState.ON ? new AuthorNagException(null) : null);
break;
}
}
EventExecutor executor = new EventExecutor() {
#Override
public void execute(#NotNull Listener listener, #NotNull Event event) throws EventException {
try {
if (!eventClass.isAssignableFrom(event.getClass())) {
return;
}
method.invoke(listener, event);
} catch (InvocationTargetException ex) {
throw new EventException(ex.getCause());
} catch (Throwable t) {
throw new EventException(t);
}
}
};
if (useTimings) {
eventSet.add(new TimedRegisteredListener(listener, executor, eh.priority(), plugin, eh.ignoreCancelled()));
} else {
eventSet.add(new RegisteredListener(listener, executor, eh.priority(), plugin, eh.ignoreCancelled()));
}
}
return ret;
}
This question already has answers here:
What is a NullPointerException, and how do I fix it?
(12 answers)
Closed 6 years ago.
I've looked at so many questions and answers but none of what i found has actually worked!
So basically if the title doesn't help much then what I'm trying to do is execute an AsyncTask from a dialog but it's not executing and when it does, it'll show up as an null object and if I'm honest it's bloody annoying!
So if anyone can help then that would be great.
The Class is subbed.
Here's the Async class:
static class UpdatePassword extends AsyncTask<String, String, String> {
Context context;
String oldPassword;
String newPassword;
public UpdatePassword(String setOldPassword, String setNewPassword, Context context) {
this.oldPassword = setOldPassword;
this.newPassword = setNewPassword;
this.context = context;
}
#Override protected String doInBackground(String... params) {
HttpRequestUtils httpRequestUtils = new HttpRequestUtils(context);
if (TextUtils.isEmpty(oldPassword) || TextUtils.isEmpty(newPassword)) {
return null;
} else {
String response = null;
String baseUrl = "rest/ws/user/update/password";
ApiResponse apiResponse = null;
try {
response = httpRequestUtils.getResponse(baseUrl + "?oldPassword=" + oldPassword + "&newPassword=" + newPassword, "application/json", "application/json");
if (TextUtils.isEmpty(response)) {
return null;
}
apiResponse = (ApiResponse) GsonUtils.getObjectFromJson(response, ApiResponse.class);
if (apiResponse != null && apiResponse.isSuccess()) {
return apiResponse.getStatus();
}
Log.i("Update", "password call" + apiResponse);
} catch (Exception e) {
e.printStackTrace();
}
return newPassword;
}
}
}
And here's what I'm doing to execute it:
String oldPassword = changePassOld.getText().toString();
String newPassword = changePassNew.getText().toString();
AsyncTask task = new UpdatePassword(oldPassword, newPassword, ProfileFragment.this.getContext());
task.execute();
Edit: I have noticed that i only have doInBackground but even when i had preExecute, it still wouldn't work
AsyncTask doesn't always call but when it does, it comes up null?
It is the most interesting AsyncTask ;)
Generally speaking, you seem to not be returning the data to the point where you expect it (or a return null condition is being hit).
You can instead define a callback.
public interface PasswordChangeListener {
void onPasswordChanged(String oldPass, String newPass);
}
Implement that on your Fragment class
public class ProfileFragment extends Fragment
implements PasswordChangeListener { // See here
...
#Override
public void onPasswordChanged(String oldPass, String newPass) {
Toast.makeText(getActivity(),
String.format("Changed %s to %s", oldPass, newPass),
Toast.LENGTH_SHORT).show();
}
Call your AsyncTask after you add that callback as a parameter
(Context usually goes first, by the way)
new UpdatePassword(
ProfileFragment.this.getActivity(),
oldPassword, newPassword,
ProfileFragment.this).execute();
Suggestion: You should return apiResponse; from doInBackground
And implement onPostExecute on the AsyncTask with that suggestion in mind
#Override
public void onPostExecute(ApiResponse result) {
if (apiResponse != null && apiResponse.isSuccess()) {
if (this.callback != null) {
callback.onPasswordChanged(this.oldPassword, this.newPassword);
} else {
Log.w("Password change", "Password callback not set!");
}
} else {
// TODO: Error handling
}
}
I'm using an asyncronus XML-RPC-Client (https://github.com/gturri/aXMLRPC) in my Project and wrote some methods using the asyncronous Callback-Methods of this Client like this this:
public void xmlRpcMethod(final Object callbackSync) {
XMLRPCCallback listener = new XMLRPCCallback() {
public void onResponse(long id, final Object result) {
// Do something
if (callbackSync != null) {
synchronized (callbackSync) {
callbackSync.notify();
}
}
}
public void onError(long id, final XMLRPCException error) {
// Do something
if (callbackSync != null) {
synchronized (callbackSync) {
callbackSync.notify();
}
}
}
public void onServerError(long id, final XMLRPCServerException error) {
Log.e(TAG, error.getMessage());
if (callbackSync != null) {
synchronized (callbackSync) {
callbackSync.notifyAll();
}
}
}
};
XMLRPCClient client = new XMLRPCClient("<url>");
long id = client.callAsync(listener, "<method>");
}
In other methods I like to call this method (here "xmlRpcMethod") and wait until it finished. I wrote methods like this:
public void testMethod(){
Object sync = new Object();
xmlRpcMethod(sync);
synchronized (sync){
try{
sync.wait();
}catch(Interrupted Exception e){
e.printStackTrace();
}
}
// Do something after xmlRcpFinished
}
But this way of waiting and synchronizing get's ugly when the projects grows larger and I need to wait for many requests to finish.
So is this the only possible / best way? Or does someone knows a better solution?
My first shot to create blocking RPC calls would be:
// Little helper class:
class RPCResult<T>{
private final T result;
private final Exception ex;
private final long id;
public RPCResult( long id, T result, Exception ex ){
// TODO set fields
}
// TODO getters
public boolean hasError(){ return null != this.ex; }
}
public Object xmlRpcMethod() {
final BlockingQueue<RPCResult> pipe = new ArrayBlockingQueue<RPCResult>(1);
XMLRPCCallback listener = new XMLRPCCallback() {
public void onResponse(long id, final Object result) {
// Do something
pipe.put( new RPCResult<Object>(id, result, null) );
}
public void onError(long id, final XMLRPCException error) {
// Do something
pipe.put( new RPCResult<Object>(id, null, error) );
}
public void onServerError(long id, final XMLRPCServerException error) {
Log.e(TAG, error.getMessage());
pipe.put(new RPCResult<Object>(id, null, error));
}
};
XMLRPCClient client = new XMLRPCClient("<url>");
long id = client.callAsync(listener, "<method>");
RPCResult result = pipe.take(); // blocks until there is an element available
// TODO: catch and handle InterruptedException!
if( result.hasError() ) throw result.getError(); // Relay Exceptions - do not swallow them!
return result.getResult();
}
Client:
public void testMethod(){
Object result = xmlRpcMethod(); // blocks until result is available or throws exception
}
Next step would be to make a strongly typed version public T xmlRpcMethod().