How to create Android Handler in a Java plugin called from Unity - java

So, let's say you have a Unity Java plugin, you call into the Java plugin like so
private static readonly AndroidJavaClass m_somePlugin = new AndroidJavaClass("com.unity3d.Plugin.blah.SomePlugin");
using (var unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer"))
{
using (var currentActivity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity"))
{
m_somePlugin.CallStatic("onInitialise", currentActivity);
}
}
and the plugin looks something like this
public class SomePlugin
{
static public void onInitialise(final Activity currentActivity)
{
Handler someHandler = new Handler();
}
}
All quite simple. Except it will crash. Creating a Handler is the cause. I'm guessing it's a thread issue.
So the question is, how does one create a handler in a Java plugin, in the activity that I'm passing in? Anyone know?

Yes, the solution to the problem was to use runOnUiThread. So in order to get the above code to not crash SomePlugin should look like so
public class SomePlugin
{
static public void onInitialise(final Activity currentActivity)
{
currentActivity.runOnUiThread(new Runnable() {
Handler someHandler = new Handler(); });
}
}

Related

How to call sendKeyDownUpSync in the background?

I want to programmatically switch a music track, but this code does not work in the background, how to solve this problem?
Instrumentation inst = new Instrumentation();
inst.sendKeyDownUpSync(KeyEvent.KEYCODE_MEDIA_NEXT);
You need to get an instance of ModuleAndroidKeyboard then call start() on that.
public class ModuleAndroidKeyboard extends Thread {
#Override
public void run() {
Instrumentation inst = new Instrumentation();
inst.sendKeyDownUpSync(KeyEvent.KEYCODE_MEDIA_NEXT);
}
}
ModuleAndroidKeyboard module = new ModuleAndroidKeyboard();
module.start(); // this line executes the codes of run()
To learn more about Thread in Java, visit W3Schools
I figured it out, I had to sign the apk with a system certificate and register INJECT_EVENTS in the manifest, after which everything worked.

How to initialize a handler in Android Studio?

I've been trying to do timed tasks with a handler in Android Studio, but when I try to initialize it, this happens:
private Handler handler = new Handler() {
#Override
public void publish(LogRecord record) {
}
#Override
public void flush() {
}
#Override
public void close() throws SecurityException {
}
};
Whenever I look at online examples where people use Handlers to execute code at intervals, their declarations look as such:
private Handler handler = new Handler();
How do I avoid the big jumble of methods within the Handler?
Looks like you're trying to use java.util.logging.Handler instead of android.os.Handler. Changing which one you import at the top of the file should fix your problem.
The auto-complete should show you which packages you will be importing from, so watch out for that in the future.

Is it possible to use a non-final in an enclosing scope like a runnable (no.)

The plan:
I created a little PreferenceActivity (don't hate me, I'm supporting API 10 and up) and need to display the current usage of local storage data by my app. I did this using a specialized class (a pretty big one, as of the moment) that handles all file operations (it's called FileOperations.java for a reason). Inside this class file there is a method getSize(File file) {...} which does just that. It gets the size of a file (or folder) with this little piece of code:
public long getSize(File file) {
long size = 0;
if(file.isDirectory()) {
for(File child : file.listFiles()) {
size += getSize(child);
}
}
size = file.length();
return size;
}
The general idea was to use this in a background Thread so it doesn't clog the UI even the slightest bit. (I am really annoyed by lagging apps and suffer from them daily)
The problem:
This works just fine. However, as soon as I purge the folder the app stores it's data in using this beauty:
private void purgeLocalStorage() {
new Thread(new Runnable() {
#Override
public void run() {
Looper.prepare();
Log.i("ActivityPrefsLocalStorage.purgeLocalStorage.Thread.Runnable.run", "Started to run");
final String directory = context.getResources().getString(R.string.app_name);
final String usedData = context.getResources().getString(R.string.ActivityPrefsLocalStorage_usedData);
final File file = new File(Environment.getExternalStorageDirectory()+"/"+directory);
final FileOperations FO = new FileOperations(context);
Log.i("ActivityPrefsLocalStorage.purgeLocalStorage.Thread.Runnable.run", "deleting folder: "+file);
if(FO.delete(file)) {
Log.i("ActivityPrefsLocalStorage.purgeLocalStorage.Thread.Runnable.run", file+" deleted");
runOnUiThread(new Runnable() {
#Override
public void run() {
Toast.makeText(context, R.string.ActivityPrefsLocalStorage_deleteSucces, Toast.LENGTH_SHORT).show();
setTotalLocalDataTexts(usedData+" "+context.getResources().getString(R.string.pref_totalData_default), "");
getUsedStorage();
}
});
} else {
Log.e("ActivityPrefsLocalStorage.purgeLocalStorage.Thread.Runnable.run", "could not delete "+file);
runOnUiThread(new Runnable() {
#Override
public void run() {
Toast.makeText(context, R.string.ActivityPrefsLocalStorage_deleteError, Toast.LENGTH_SHORT).show();
}
});
}
}
}).start();
}
Things hit the fan...
See, the problem is that my method for reading the size of the folder does not want to function properly when called by the previous method.
Here's a snippet:
private void getUsedStorage() {
new Thread(new Runnable() {
#Override
public void run() {
Log.i("ActivityPrefsLocalStorage.getUsedStorage.Thread.Runnable.run", "Started to run");
final String directory = context.getResources().getString(R.string.app_name);
final String usedData = context.getResources().getString(R.string.ActivityPrefsLocalStorage_usedData);
final File file = new File(Environment.getExternalStorageDirectory()+"/"+directory);
final FileOperations FO = new FileOperations(context);
final DataUsage DU = new DataUsage(context);
Log.i("ActivityPrefsLocalStorage.getUsedStorage.Thread.Runnable.run", "Checking filesize of folder: "+file);
long fileSize = FO.getSize(file);
String usedUnits = DU.getUnit(fileSize, true, false, false);
String usedBytes = DU.getUnit(fileSize, true, true, true);
Log.i("ActivityPrefsLocalStorage.getUsedStorage.Thread.Runnable.run", "filesize of "+file+": "+usedUnits);
setTotalLocalDataTexts(usedData+" "+usedUnits, usedBytes);
}
}).start();
}
However, a quick and easy workaround would be to place it on the UI thread like so:
...blabla code you already read above.
long fileSize = FO.getSize(file);
String usedUnits = DU.getUnit(fileSize, true, false, false);
String usedBytes = DU.getUnit(fileSize, true, true, true);
Log.i("ActivityPrefsLocalStorage.getUsedStorage.Thread.Runnable.run", "filesize of "+file+": "+usedUnits);
runOnUiThread(new Runnable() {
#Override
public void run() {
setTotalLocalDataTexts(usedData+" "+usedUnits, usedBytes);
}
});
}
}).start();
}
And that's where it starts getting interesting. I cannot use non-finals inside the new Runnable(), and I cannot make them final since I want the value to update and not remain stuck at eg. 32MiB (while it has just been purged).
Possible fixes:
I should man up and just use a final. The user will understand they need to refresh the page manually. (oh no...)
Hire... erm. Extend an AsyncTask<Void, Void, Void> to do the work.
My ideal fix:
Someone giving me an awesome snippet of code for free that does all the magic. no, seriously though, I would really appreciate anything apart from my list of possible fixes. There has to be some way to pass the new Runnable() a variable without creating classes and implementing the entire universe? Or is that what I am trying to achieve really a new thing?
TL;DR:
Things go wrong as soon as I call getUsedStorage() from within a new Runnable(). This function is also a background task inside a Runnable, but updates the UI using a private void function that sets it. It only passes variables to this function. and then things fly off the handle(r).
Edit: grammar.
Edit2: Also a pretty interesting thing to note here, I used something similar in another PreferenceActivity, and that one works. (but that one does not update at the press of a button that calls another private something functionName() {new Thread(new Runnable() {public void run() {...});})
There are a couple of ways to use non-finals inside of a Runnable or other enclosed classes.
The first is to change your variables to be members of an enclosing class. This will allow you to use the variables inside the Runnable. An example follows:
public class Foo {
private long time;
public void run() {
time = System.currentTimeMillis();
new Thread(new Runnable() {
#Override
public void run() {
time += 1;
System.out.println("Our current time is: " + time);
}
});
}
}
The other option, and it is quite hacky, is to use a final array with a length of 1. An example of that follows:
public class Foo {
public void run() {
final long[] time = { System.currentTimeMillis() };
new Thread(new Runnable() {
#Override
public void run() {
time[0] += 1;
System.out.println("Our current time is: " + time[0]);
}
});
}
}
As gonemad16 on reddit.com/r/androiddev pointed out, my issue had nothing to do with final vs non final. That was not the reason I was getting an old value. All my variables are given a value, sent to setTotalLocalDataTexts and then go out of scope... nothing is updating their values.. so there is no harm in them being final and no benefit to them being non final...
It was an an issue in getSize()
I thought I had a correct loop there using if file.isDirectory() {...}. It created a directory tree and executed itself using the children it has found. When all items have been scanned the value returns to the function calling it.
This was working just fine for me while I was still running all of my code on the ui thread. Everything was slow. But it worked.
However, I forgot that I removed a very crucial ...} else {...
I believe I removed that one because it caused a stack overflow at some point, so I removed it and I guess forgot to put it back...
And here I was thinking my first SO question wouldn't be a noobish question...

Android - advice on writing my recursive method more efficiently for two independent animations

I'm new to Java and Android programming and taking a course on this via Coursera. My app has two images that animate up and down. Right now, I've gotten as far as having both images animate together repeatedly. I got help and wrote a recursive method to have them animate repeatedly until a pleaseStop boolean flag is changed.
I would like them to move independently. Rather than writing two stepRecursive methods, how can I write just one?
Here's where I set up and run the animation.
mHandler = new Handler(); // .os package class when importing
mLeftfoot = findViewById(R.id.leftfoot);
mRightfoot = findViewById(R.id.rightfoot);
mFootAnim = AnimationUtils.loadAnimation(this, R.anim.foot); //this looks to the foot.xml file for the animations
stepRecursive();
Here's my recursive method. Notice mInterval. I would like mLeftfoot and mRightfoot to run at their own mInterval.
private void stepRecursive() {
mHandler.postDelayed(new Runnable() {
#Override
public void run() {
mLeftfoot.startAnimation(mFootAnim);
mRightfoot.startAnimation(mFootAnim);
if (!pleaseStop)
stepRecursive();
}
}, mInterval);
Pass one boolean variable via stepRecursive() method and decide which View has to be animated based on that boolean value...
private void stepRecursive(final boolean isLeftFoot,final int mInterval) {
mHandler.postDelayed(new Runnable() {
#Override
public void run() {
if (isLeftFoot) {
mLeftfoot.startAnimation(mFootAnim);
} else {
mRightfoot.startAnimation(mFootAnim);
}
if (!pleaseStop)
stepRecursive(isLeftFoot,mInterval);
}
}, mInterval);
}
and when calling this method, pass appropriate interval based on the boolean value.
like
stepRecursive(true,intervalForLeft);
stepRecursive(false,intervalForRight);

Own Listener change UI-Thread in Android

#first Sorry for my bad english.
I have created a own Listener. I want to change a TextView, when the Listener is called in the MainActivity from a Service. The idea for my own Listener is from:
http://tseng-blog.nge-web.net/blog/2009/02/17/how-implement-your-own-listener-android-java/
In the Code Example the TriggerMethod() ist called from a Calculation Thread, running in the Service.
I solved the Problem, but I find, it isn't pretty nice, because in every new Activity I have to make a new Thread. Is it possible to create an interface/listener that automatically can change the UI?
Used to solve the Problem:
http://developer.android.com/guide/components/processes-and-threads.html
ResultListener.java:
public interface ResultListener {
public void onResultAvailable(double result);
}
SimuService.java:
public class SimuService extends Service {
private ResultListener mResultListener = null;
public void setResultListener(ResultListener listener){
mResultListener=listener;
}
public void triggerMethode(){
observeResultDouble=getObserveDouble;
mResultListener.onResultAvailable(observeResultDouble);
}
MainActivity:
public class MainActivity extends FragmentActivity{
TextView txtView;
ResultListener mResultListener;
SimuService mSimuService;
protected void onCreate(Bundle savedInstanceState) {
txtView = (TextView) findViewById(R.id.txtServiceTime);
//Create Service .....an Bind
mResultListener = new ResultListener() {
#Override
public void onResultAvailable(double result) {
txtView.setText("Result: "+result);
}
};
mSimuService.setResultListener(mResultListener);
}
MY SOLUTION:
ResultListener = new ResultListener() {
#Override
public void onResultAvailable(double result) {
this.result=result;
runOnUiThread(setNewDataToUI);
}
};
private Thread setNewDataToUI = new Thread(new Runnable() {
#Override
public void run() {
txtView.setText("Result: "+result);
}
});
First of all: If you reference a Service in an Activity, the Service becomes pretty much useless. The advantage of services are, that they are loose coupled and can work indepenendtly form activities (=what the user sees) and its lifecycle and might even be in their own process. Thus activity-service communication is through intents or inter-process language AIDL, not through callbacks. If you want something executed asynchronosly use AsyncTask.
To your main problem: as you found out, you can only modify the UI on the UI-thread. So by design, leave changing UI in the component, thats responsibly for that (either activtiy or fragment), that will prevent the need of runOnUiThread()
Your code seems like txtView.setText("Result: "+result); will be executed in the Activity, but it wont. It will be executed in the Service, which (as I impleied before) does not run on the UI-thread. The problem is, I dont get the intent, what exactly you want to achieve so it is hard to give you an alternative solution.

Categories