Can a Runnable return a value? - android

Is it possible for a Runnable to return a value? I need to do some intensive work on an Editable and then return it back. Here is my mock code.
public class myEditText extends EditText {
...
private Editable workOnEditable() {
final Editable finalEdit = getText();
Thread mThread = new Thread(new Runnable() {
public void run() {
//do work
//Set Spannables to finalEdit
}
});
mThread.start();
return finalEdit;
}
...
}
So obviously my first problem is I'm trying to change finalEdit, but it has to be final in order to access it in and out of the thread, right? What's the correct way to do this?

In Java, a Runnable cannot "return" a value.
In Android specifically, the best way to handle your type of scenario is with AsyncTask. It's a generic class so you can specify the type you want to pass in and the type that is returned to the onPostExecute function.
In your case, you would create an AsyncTask<Editable, Void, TypeToReturn>. Something like:
private class YourAsyncTask extends AsyncTask<Editable, Void, Integer> {
protected Long doInBackground(Editable... params) {
Editable editable = params[0];
// do stuff with Editable
return theResult;
}
protected void onPostExecute(Integer result) {
// here you have the result
}
}

The following exists simply to point out the use of "pseudo-closures" in Java, as unsuitable as they may be in this case.
Java allows pseudo-closures through mutable-types stored in final variables.
See Java's pseudo-closures by Christopher Martin skip to the "Faking it" section. He introduces a mutable-type ValueHolder<T>:
private static class ValueHolder<T> {
T value;
}
...
final ValueHolder<Integer> i = new ValueHolder<Integer>();
...
i.value = 42;
Happy coding.

You realize that the thread keeps working past the end of the workOnEditable() function, right? If you want a synchronous response, get rid of the thread. If not, use a Handler to pass the data back to the main thread.

I have made 2 utility methods around Runnable that enable you to post a runnable and block until you get the result.
You can take a look here: https://github.com/Petrakeas/HVTHandler/

Related

can use variables from doitbackground in onpostexecute

I have a inner class of asynctask in a class. I defined some variables arrays in that inner class. In doitbackground, i put some values into them.
When i go go onpostexecute, i can use them because they are all in same inner class.
So, i dont need to return something for pass? I am really confused. Is that a bad way, should i define all those inside doitbackground?
Because if i have to pass values, i need to define wrapper because i have to pass 4-5 arraylists. They are different types. But now i can use them and no need return or pass.
I am searching but there is no information about this. In all asyntask examples, they define variables outside of doitbackground.
I usually create a class with these fields in a doInBackground, and pass this class as a result.
This also allows you to pass null if an error happened.
class DataClass {
private int someIntData;
private String someStringData;
}
new AsyncTask<Void, Void, DataClass>() {
#Override
protected DataClass doInBackground(Void... params) {
DataClass data = new DataClass();
// doing some job
if (!errorHappened) {
data.someIntData = 5;
data.someStringData = "Just an example string";
return data;
}
return null;
}
#Override
protected void onPostExecute(DataClass result) {
if (result != null) {
// handle the result
} else {
// error happened
}
}
};
Technically you can do it, but think about encapsulation concept
as you know,
doitbackground happen in another thread than ui thread
onpostexecute happen in ui thread
so there is common pattern that send AsyncTask parameters in Constructor or Execute Argument, by this way, you can make your self sure that Async class can be reused maybe in another application and fully encapsulated.

Is it right if I read view on other thread,Android UI

Android can't update view direct on non-ui thread,but if I just read/get some information for ui?
For example I have a method updateModel() like
void updateModel() {
dailyReport.log.setValue(editLog.getText().toString());
dailyReport.plan.setValue(editPlan.getText().toString());
dailyReport.question.setValue(editQuestion.getText().toString());
}
Is it a problem if I run this method on non-ui thread.
Example below helped me solve this problem. Hope this will help you too
runOnUiThread(new Runnable() {
#Override
public void run() {
//do your job
}
});
Is it a problem if I run this method on non-ui thread?
With the assumption that dailyPlan is a model class and its methods do not modify the UI, then no, it is not a problem, Android will not complain and you will not receive any runtime errors. However, I would not follow this approach as in general it's a bad practice to access directly one threads data from another thread - you never know who is modifying what, read/write issues can occur and so on. These are usually solved by synchronizing the data, but if you put synchronized code in UI thread you made things even worse!
For your kind of problem, why don't you pass the data from UI controls to the thread that uses above logic? When you create it, pass the 3 strings:
editLog.getText().toString()
editPlan.getText().toString()
editQuestion.getText().toString()
Example:
private EditText editLog;
private EditText editPlan;
private EditText editQuestions;
private void activityMethodThatStartsThread() {
String log = editLog.getText().toString();
String plan = editPlan.getText().toString();
String questions = editQuestions.getText().toString();
DailyReportModel model = new DailyReportModel(log, plan, questions);
model.start();
}
public class DailyReportModel extends Thread {
private String log;
private String plan;
private String questions;
public DailyReportModel(String log, String plan, String questions) {
super();
this.log = log;
this.plan = plan;
this.questions = questions;
}
void updateModel() {
dailyReport.log.setValue(log);
dailyReport.plan.setValue(plan);
dailyReport.question.setValue(questions);
}
}
Yes you can Update the UI from a Non UI thread. There are two ways of doing this.
1) Do this with activity object (easy option get and Update)
2) Do this using Message Handler (a bit difficult and Update only)
Going for the 1st one all you need to do is Pass the Activity into the constructor. Here is Thread snippet
public class MyThread extends Thread {
private Activity _activity;
public MyThread(Activity activity) {
this._activity = activity;
}
#Override
public void run() {
super.run();
//do all what you want. and at the end to Update the Views Do this
if(!this._activity.isFinishing())
{ // executed if the activity is not finishing
this._activity.runOnUiThread(new Runnable() {
#Override
public void run() {
//set the public variables UI Variables like this
dailyReport.log.setValue(this._activity.editLog.getText().toString());
dailyReport.plan.setValue(this._activity.editPlan.getText().toString());
dailyReport.question.setValue(this._activity.editQuestion.getText().toString());
});
}
}
}
Now in the Activity
MyThread thread = new MyThread(this);
thread.start;

Use Asynctask as a private class or with broadcast receiver?

I'm trying to make an application that uses Asynctask. Particularly, I want to make different http petitions with different JSON in different activities without the activity being frozen while the communication is done.
At first I thought to use asynctask as a private inner class in those activities, but I saw that they share a lot of code. So I thought to make a single class and play with broadcast receivers as I need to monitorize when I receive the result of the http petition, and isn't good to interfere with activity directly in the onPostExecute while in a different class.
What I want to know is, what is more efficient and better practice. Make a class that has the shared code and extends asynctask, then doing inner classes for each activity that extends that one or make a single asynctask that sends broadcast and receive them with each activity when needed.
Excuse my poor english, if needed I'll try to specify more clearly.
Thanks in advance
Background
What I want to know is, what is more efficient and better practice. Make a class that has the shared code and extends asynctask, then doing inner classes for each activity that extends that one or make a single asynctask that sends broadcast and receive them with each activity when needed.
I'm unclear as to why these are your only two options. Create a single AsyncTask, such as JsonPetitionTask, then push a new JsonPetitionTask.Data object. This object would contain your URL, your JSON, and any other data you need.
Setting up the AsyncTask
Something like this:
public class JsonPetitionTask extends AsyncTask<JsonPetitionTask.Data, Integer, Boolean> {
protected Boolean doInBackground(JsonPetitionTask.Data... args) {
for (int i = 0; i < args.length; i++) {
JsonPetitionTask.Data data = args[i];
// Send your JSON; check for errors, and return false if needed.
if (isCancelled()) break;
}
return true;
}
protected void onProgressUpdate(Integer... progress) {
// Show progress?
}
protected void onPostExecute(Boolean result) {
// result is your success true/false.
}
public static class Data {
public String jsonContent;
public String petitionUrl;
public Data(String content, String url) {
jsonContent = content;
petitionUrl = url;
}
}
}
Calling the JsonPetitionTask
Then you can call it like so:
JsonPetitionTask.Data data = new JsonPetitionTask.Data(myJSON, myURL);
new JsonPetitionTask().execute(data);
And voilà, you've executed your AsyncTask using only one class with no receivers.
Implementing a callback
Now, if you want to register a callback (something to execute that is specific to the calling code), that's a bit trickier. If this is part of what you're looking for, I'll be glad to edit this post and explain it.
To add a callback, we can use the Runnable class to execute some code after the job is done.
Firstly, we need to add a new field in the Data inner class:
public Runnable callback;
Next, before we call execute(), we need to add a new callback to our data object.
data.callback = new Runnable() {
public void run() {
// Whatever code you want to run on completion.
}
};
Third, in the JsonPetitionTask class, we need a list of things to run:
private ArrayList<Runnable> mRunnables = new ArrayList<Runnable>();
Make sure, in each iteration of the doInBackground() loop, that you do mRunnables.add(data.callback);.
Lastly, in onPostExecute(), we need to call this:
protected void onPostExecute(Boolean result) {
for (Runnable r : mRunnables)
if (r != null) r.run();
}
I do realize I didn't send result to the Runnable, however I didn't feel like implementing a new Runnable type just to handle that. If you need this, I guess that's a bit of homework for you!
The way I found the best is just simply create public class that extends AsyncTask and then you just override onPostExecute function in every activity you use it.
Example:
MyDataTask dataTask = new MyDataTask() //you can add your parameters in class constructor
{
#Override
protected void onPostExecute(Object result) //replace Object with your result type
{
MyActivity.this.doStuff(result); //use result in current activity
}
};
you can also create some custom functions to set private variables in datatask
dataTask.AddParam("user", username);
dataTask.AddParam("pass", pass);
and then just execute it with your args...
dataTask.execute(myArgs);
I have used Async task class as single class. And for every Webservice call i have used unique IntentFilter to Broadcast response.
Put that Broadcast receiver in every class. You have perfect solution.
Its working well.

Android's Activity.runOnUiThread is not static, so how can i use it?

For example, if I have a thread doing expensive stuff, and from that thread I want to fire runOnUiThread in the Main (activity) class. Obviously I shouldn't make an instance of my activity class (Main). So if I try
Main.runOnUiThread(mRunnable);
from my thread it gives me an error saying it's not a static method, and therefor it can't be accessed in my way. Now my understanding would be that the activity class is nearly almost accessed in a static way.
How would I do this?
(Btw: I'm doing this because I was getting CalledFromWrongThreadException, Only the original thread that created a view hierarchy can touch it's views)
Raunak has the right idea. I'll just add that you can also specify an integer in the method sendEmptyMessage as an identifier to the handler. This will allow you to create one handler that can handle all of your UI updates, e.g.
public static final int EXAMPLE = 0;
public static final int ANOTHER_EXAMPLE = 1;
private final Handler handler = new Handler(){
#Override
public void handleMessage(Message msg) {
switch( msg.what ){
case EXAMPLE:
//Perform action
break;
case ANOTHER_EXAMPLE;
//Perform action
break;
}
}
}
//Call to submit handler requesting the first action be called
handler.sendEmptyMessage(EXAMPLE);
Hope this helps!
You should use the Handler class. The handler class runs on the UI thread. When you finish work in your thread, call handler.sendEmptyMessage(), from where you can make the changes to your ui.
private final Handler handler = new Handler(){
#Override
public void handleMessage(Message msg) {
// make changes to ui
}
}
Your question doesn't really provide enough details, but from the sound of things, you're in a private inner class (Runnable?) in your activity (Main). If that is the case, you can either write:
Main.this.runOnUiThread(mRunnable);
or
runOnUiThread(mRunnable); //will see that there is no runOnUiThread in the current class and begin looking "upwards"
Also, you may want to look at AsyncTask, specifically at the onPostExecute, onPreExecute and onProgressUpdate callbacks, which run on the UI thread.
first create a runnable outside onCreate. Like this:
private Runnable myRunnable = new Runnable() {
#Override
public void run() {
//work to be done
}
};
and then call the runnable using:
runOnUiThread(myRunnable);
all of the above answers are not very correct.
1)if you want a piece of code to run on UI thread from any thread code base. you can do:
Looper.getMainLooper().post(new Runnable(...))
because Looper.getMainLooper() is a static variable and initialized in ActivityThread.
2) if your runnable code snippet is inside an activity
then you can use:
MainActivity.this.runOnUiThread(...)
For those who are looking for an easy instant solution follow the simple steps
Make a reference of your class before your onCreate() method
MyClass obj;
Initialize it in you onCreate() method
obj = MyClass.this;
Call runOnUiThread()
obj.runOnUiThread(new Runnable() {
public void run() {
//perform your UI tasks here
}
});
Hope it helps.

Android: How can I pass parameters to AsyncTask's onPreExecute()?

I use an AsyncTask for loading operations that I implemented as an inner class.
In onPreExecute() I show a loading dialog which I then hide again in onPostExecute(). But for some of the loading operations I know in advance that they will finish very quickly so I don't want to display the loading dialog.
I wanted to indicate this by a boolean parameter that I could pass to onPreExecute() but apparently for some reason onPreExecute() doesn't take any parameters.
The obvious workaround would probably be to create a member field in my AsyncTask or in the outer class which I would have to set before every loading operation but that does not seem very elegant. Is there a better way to do this?
You can override the constructor. Something like:
private class MyAsyncTask extends AsyncTask<Void, Void, Void> {
public MyAsyncTask(boolean showLoading) {
super();
// do stuff
}
// doInBackground() et al.
}
Then, when calling the task, do something like:
new MyAsyncTask(true).execute(maybe_other_params);
Edit: this is more useful than creating member variables because it simplifies the task invocation. Compare the code above with:
MyAsyncTask task = new MyAsyncTask();
task.showLoading = false;
task.execute();
1) For me that's the most simple way passing parameters to async task
is like this
// To call the async task do it like this
Boolean[] myTaskParams = { true, true, true };
myAsyncTask = new myAsyncTask ().execute(myTaskParams);
Declare and use the async task like here
private class myAsyncTask extends AsyncTask<Boolean, Void, Void> {
#Override
protected Void doInBackground(Boolean...pParams)
{
Boolean param1, param2, param3;
//
param1=pParams[0];
param2=pParams[1];
param3=pParams[2];
....
}
2) Passing methods to async-task
In order to avoid coding the async-Task infrastructure (thread, messagenhandler, ...) multiple times you might consider to pass the methods which should be executed in your async-task as a parameter. Following example outlines this approach.
In addition you might have the need to subclass the async-task to pass initialization parameters in the constructor.
/* Generic Async Task */
interface MyGenericMethod {
int execute(String param);
}
protected class testtask extends AsyncTask<MyGenericMethod, Void, Void>
{
public String mParam; // member variable to parameterize the function
#Override
protected Void doInBackground(MyGenericMethod... params) {
// do something here
params[0].execute("Myparameter");
return null;
}
}
// to start the asynctask do something like that
public void startAsyncTask()
{
//
AsyncTask<MyGenericMethod, Void, Void> mytest = new testtask().execute(new MyGenericMethod() {
public int execute(String param) {
//body
return 1;
}
});
}
why, how and which parameters are passed to Asynctask<>, see detail here. I think it is the best explanation.
Google's Android Documentation Says that :
An asynchronous task is defined by 3 generic types, called Params, Progress and Result, and 4 steps, called onPreExecute, doInBackground, onProgressUpdate and onPostExecute.
AsyncTask's generic types :
The three types used by an asynchronous task are the following:
Params, the type of the parameters sent to the task upon execution.
Progress, the type of the progress units published during the background computation.
Result, the type of the result of the background computation.
Not all types are always used by an asynchronous task. To mark a type as unused, simply use the type Void:
private class MyTask extends AsyncTask<Void, Void, Void> { ... }
You Can further refer : http://developer.android.com/reference/android/os/AsyncTask.html
Or You Can clear whats the role of AsyncTask by refering Sankar-Ganesh's Blog
Well The structure of a typical AsyncTask class goes like :
private class MyTask extends AsyncTask<X, Y, Z>
protected void onPreExecute(){
}
This method is executed before starting the new Thread. There is no input/output values, so just initialize variables or whatever you think you need to do.
protected Z doInBackground(X...x){
}
The most important method in the AsyncTask class. You have to place here all the stuff you want to do in the background, in a different thread from the main one. Here we have as an input value an array of objects from the type “X” (Do you see in the header? We have “...extends AsyncTask” These are the TYPES of the input parameters) and returns an object from the type “Z”.
protected void onProgressUpdate(Y y){
}
This method is called using the method publishProgress(y) and it is usually used when you want to show any progress or information in the main screen, like a progress bar showing the progress of the operation you are doing in the background.
protected void onPostExecute(Z z){
}
This method is called after the operation in the background is done. As an input parameter you will receive the output parameter of the doInBackground method.
What about the X, Y and Z types?
As you can deduce from the above structure:
X – The type of the input variables value you want to set to the background process. This can be an array of objects.
Y – The type of the objects you are going to enter in the onProgressUpdate method.
Z – The type of the result from the operations you have done in the background process.
How do we call this task from an outside class? Just with the following two lines:
MyTask myTask = new MyTask();
myTask.execute(x);
Where x is the input parameter of the type X.
Once we have our task running, we can find out its status from “outside”. Using the “getStatus()” method.
myTask.getStatus();
and we can receive the following status:
RUNNING - Indicates that the task is running.
PENDING - Indicates that the task has not been executed yet.
FINISHED - Indicates that onPostExecute(Z) has finished.
Hints about using AsyncTask
Do not call the methods onPreExecute, doInBackground and onPostExecute manually. This is automatically done by the system.
You cannot call an AsyncTask inside another AsyncTask or Thread. The call of the method execute must be done in the UI Thread.
The method onPostExecute is executed in the UI Thread (here you can call another AsyncTask!).
The input parameters of the task can be an Object array, this way you can put whatever objects and types you want.
You can either pass the parameter in the task constructor or when you call execute:
AsyncTask<Object, Void, MyTaskResult>
The first parameter (Object) is passed in doInBackground.
The third parameter (MyTaskResult) is returned by doInBackground. You can change them to the types you want. The three dots mean that zero or more objects (or an array of them) may be passed as the argument(s).
public class MyActivity extends AppCompatActivity {
TextView textView1;
TextView textView2;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
textView1 = (TextView) findViewById(R.id.textView1);
textView2 = (TextView) findViewById(R.id.textView2);
String input1 = "test";
boolean input2 = true;
int input3 = 100;
long input4 = 100000000;
new MyTask(input3, input4).execute(input1, input2);
}
private class MyTaskResult {
String text1;
String text2;
}
private class MyTask extends AsyncTask<Object, Void, MyTaskResult> {
private String val1;
private boolean val2;
private int val3;
private long val4;
public MyTask(int in3, long in4) {
this.val3 = in3;
this.val4 = in4;
// Do something ...
}
protected void onPreExecute() {
// Do something ...
}
#Override
protected MyTaskResult doInBackground(Object... params) {
MyTaskResult res = new MyTaskResult();
val1 = (String) params[0];
val2 = (boolean) params[1];
//Do some lengthy operation
res.text1 = RunProc1(val1);
res.text2 = RunProc2(val2);
return res;
}
#Override
protected void onPostExecute(MyTaskResult res) {
textView1.setText(res.text1);
textView2.setText(res.text2);
}
}
}

Categories

Resources