In my application, in MainActivity, there is a thread which works fine. But when I call another class to get data from the server I can't run on a thread. See code example below.
class MainActivity extends Activity implements Runnable {
public void onCreate() {
new Thread(this).start();
}
public void run() {
//here is code for download data from server after completion this and in handler i m call other class in setdata() method....
}
public void setData() {
new CheckData(this);
}
}
class CheckData {
public CheckData(Context context) {
context.runUIonthread(){//cant call as runUIthread............
}
}
See the article Communicating with the UI Thread.
With Context in hand, you can create a Handler in any class. Otherwise, you can call Looper.getMainLooper(), either way, you get the Main UI thread.
For example:
class CheckData{
private final Handler handler;
public Checkdata(Context context){
handler = new Handler(context.getMainLooper());
}
public void someMethod() {
// Do work
runOnUiThread(new Runnable() {
#Override
public void run() {
// Code to run on UI thread
}
});
}
private void runOnUiThread(Runnable r) {
handler.post(r);
}
}
Here's a solution if you don't want to pass the context:
new Handler(Looper.getMainLooper()).post(new Runnable() {
public void run() {
// code goes here
}
});
Activity is a class that extends Context. So there is no need to pass both context and activity. You may pass activity as context and then you can use the context to run on UI thread as follows:
((Activity) context).runOnUiThread(new Runnable() {
public void run() {
//Code goes here
}
});
Word of Caution: Only use this when you're sure that context is an activity context, and it's not a good practice to assume that.
class MainActivity extends Activity implements Runnable{
public void oncreate(){
new Thread(this).start();
}
public void run(){
//here is code for download data from server after completion this and in handler i m call other class in setdata() method....
}
public void setdata();
{
new checkData(this,MainActivity.this);
}
}
class checkData{
public void checkdata(Context context,MainActivity mainactivity){
mainactivity.runUIonthread()..is works fine for me.....
}
}
You might want to take a look at AsyncTask. Even though it's not the best solution, it will help you get started.
http://developer.android.com/reference/android/os/AsyncTask.html
EDIT
I don't see why using an AsyncTask is not a solution for you but anyway. You can hold a Handler class that is initialized in the UI thread. Then using this Handler you can post back messages to the UI in the form of a runnable. So all you need to do is instantiate a new Handler object when you are in the UI thread (before you start your new one) and then share that with your other class. When you are done, you can use that instance to post a message back to the UI thread using the post method. Check out the documentation of the Handler class for more details:
http://developer.android.com/reference/android/os/Handler.html
If someone's looking for an Rx based solution:
Observable.just(true)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(aBoolean -> {
// cool stuff comes here
});
Related
I'm using multiple MutableLiveData on an MVVM architecture.
on the ViewModel, I post the objects but the fragment is not resumed.
when the fragment has resumed the observers get the MutableLiveData but not in the order I post them.
How can I force an order of getting the MutableLiveData?
ViewModel:
void foo(){
first_MutableLiveData.post(newData)
second_MutableLiveData.post(newData)
}
fragment:
initView(){
first_MutableLiveData.observe(this,()->{
"getting called second"})
second_MutableLiveData.observe(this,()->{
"getting called first"})
}
You can't force what you want. As you can see from the code they are posting the result to the MainThread by calling:
ArchTaskExecutor.getInstance()
So now one would bother to support the syncronization between two different LiveData objects. It is your job do do so. It is a corner case.
Just use setValue, instead of postValue directly on the MainThread. Here is an example.
public class MainThreadExecutor implements Executor {
private final Handler handler = new Handler(Looper.getMainLooper());
#Override
public void execute(Runnable runnable) {
handler.post(runnable);
}
}
public class YourClass {
MutableLiveData first_MutableLiveData = new MutableLiveData<Data>();
MutableLiveData second_MutableLiveData = new MutableLiveData<Data>();
private final Executor executor;
public YourClass(Executor executor) {
this.executor = executor;
}
void foo(){
executor.execute(new Runnable(){
#Override
public void run() {
first_MutableLiveData.setValue(newData);
second_MutableLiveData.setValue(newData);
}
});
}
}
So apparently when I changed the observer's order on the fragment they arrived in the order I needed them to be. Thanks everyone for the quick response!
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;
I'm trying to create an abstract class that extends either a service or a thread. This is because i must run this class every second to find out the foreground activity. If its Service i'm using Runnable and make it run every second using Handler. But I'm unable to Start the service or thread from the main activity. I know that abstract classes cant be instantiated but is there any work around that i could use over here?? Please, help.
public abstract class A extends Service Implements Interface {
public void onCreate() {
super.onCreate();
mHandler.postDelayed(runnable, 1 * 1000);
}
protected abstract void getData();
public Runnable runnable = new Runnable() {
public void run() {
//Trying to find Foreground Activities
A start = new B();
start.getData();
mHandler.postDelayed(runnable, 1 * 1000);
}
};
//Inteface methods defined here.
}
Another class:
public class B extends A {
public void getData() {
//Do my stuff
}
}
Now I need to call this A class, so that this abstract method can be executed in which ever class I extend A.
To instantiate an abstract class('s anonymous subclass):
abstract class AbstractClass {}
public class MyActivity extends Activity {
public void onCreate(Bundle i) {
AbstractClass abstractInstance = new AbstractClass(){};
}
}
Though actually you are not supposed to need to do this. What I would suggest is a simple JavaSE concurrency based approach, using ScheduledExecutorService.
I have the following problem.
I have a class named "A" in which I create a list "List dStruct" .
I modify this object in the "A" class and I want to pass it to an Activity for further use.
Also the "A" class extends AsyncTask.
In this case,how do I pass an object to an Activity?
Here is the Activity Code:
List dStruct; //the object I want to access
btnPlanTrip.setOnClickListener(new OnClickListener() {
tripReq = new TripRequest(MainActivity.this);
tripReq.execute(request);
dStruct=tripReq.dStruct;
String str= dStruct.get(0).name;
}
Here is the code for the class "A"
public class TripRequest extends AsyncTask {
List dStruct;
public TripRequest(MainActivity activity) {
this.activity = activity;
dStruct=new ArrayList <DirectionsStruct>();
progressDialog = new ProgressDialog(activity);
}
protected void onPostExecute(Long result) {
code for dStruct
}
}
I solved this issue using Handlers. In my custom AsyncTask, I pass a Handler from an Activity to the constructor. In the AsyncTask's onPostExecute, I call Handler.sendMessage and it sends whatever data back to the Activity.
AsyncTask Code (your "A" class)
public class MyAsyncTask extends AsyncTask<RestClient, Void, RestResponse> {
Handler handler;
public MyAsyncTask(Handler handler) {
this.handler = handler;
}
#Override
protected RestResponse doInBackground(RestClient... rc) {
// Get data from web service or whatever...
}
#Override
protected void onPostExecute(RestResponse response){
Message msg = Message.obtain();
msg.obj = response;
this.handler.sendMessage(msg);
}
}
Handler declared in Activity
private Handler activityHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
// Do something with msg.obj
};
Call to AsyncTask from Activity passing in Handler to ctor (do this in your button click event handler)
MyAsyncTask async = new MyAsyncTask(activityHandler);
async.execute(...);
Arbitrary Java objects aren't really first-class constructs form an Android point of view.
The "main" thread enters your code though an Activity/Broadcast Receiver/Service/Content Provider/View...well, you get the idea. Application code can then control flow as it wishes, spawning new threads, sending intents for the OS to route appropriately, and utilizing other arbitrary classes (like your class A). However, your activity has to ask A, A can't tell your activity.
That being said, if your activity instantiates A, and A creates the List called dStruct in an instance method, you could do something like this.
public partial Class A {
public List createDStruct(){
List dStruct = new List()
//Do stuff to dStruct
return dStruct
}
public partial Class MyActivity {
public List retrieveDstruct(){
A a = new A()
return a.createDStruct()
}
}
I need to update some UI and do it inside of the UI thread by using runOnUiThread
Now the data for the UI comes from the other Thread, represented by data here.
How can i pass the data to the Runnable, so tht they can be used to update the UI?
Android doesn't seem to allow using data directly. Is there an elegant way to do this?
public void OnNewSensorData(Data data) {
runOnUiThread(new Runnable() {
public void run() {
//use data
}
});
}
My solution was creating a fioeld private Data sensordata inside of the runnable, and assigning data to it. This works only, if the original Data data is final.
public void OnNewSensorData(final Data data) {
runOnUiThread(new Runnable() {
private Data sensordata = data;
public void run() {
//use sensordata which is equal to data
}
});
}
The problem you found is that
Inner classes in Java capture ("close over") the lexical scope in which
they are defined. But they only capture variables that are declared "final".
If this is clear as mud, there's a good discussion of the details here:
Cannot refer to a non-final variable inside an inner class defined in a different method
But your solution looks fine. In addition, provided that data is final, you could simplify the code to this:
public void OnNewSensorData(final Data data) {
runOnUiThread(new Runnable() {
public void run() {
// use data here
data.doSomething();
}
});
}
If you want to avoid using an intermediate final variable (as described by Dan S), you can implement Runnable with an additional method to set Data:
public class MyRunnable implements Runnable {
private Data data;
public void setData(Data _data) {
this.data = _data;
}
public void run() {
// do whatever you want with data
}
}
You can then call the method like this:
public void OnNewSensorData(Data data) {
MyRunnable runnable = new MyRunnable();
runnable.setData(data);
runOnUiThread(runnable);
}
you could also make MyRunnable's constructor take in the Data instance as an argument:
public class MyRunnable implements Runnable {
private Data data;
public MyRunnable(Data _data) {
this.data = _data;
}
public void run() {
...
}
}
and then just say runOnUiThread(new MyRunnable(data));
I had a similar problem where I wanted to pass information into the thread. To solve it with the android system, I modifying corsiKa's answer in: Runnable with a parameter?
You can declare a class right in the method and pass the param as shown below:
void Foo(String str) {
class OneShotTask implements Runnable {
String str;
OneShotTask(String s) { str = s; }
public void run() {
someFunc(str);
}
}
runOnUiThread(new OneShotTask(str));
}
You'll need to update every time your program has new Data it wants to show. Your second code listing here is the standard way to accomplish this. There can be some catches if you're continuing to update Data in the thread. If this is the case consider blocking the thread until the UI finishes updating or copying the data to another Data object.
What's happening internally is that the JVM is copying the reference to the Data object for when the anonymous class will run. Data stored inside can still be changed. If your method requires additional changes to Data just use another variable (object reference) such as: final Data finalData = data;. You can also remove the line private Data sensordata = data; and use data directly in your run method.
It may not look elegant but this is the way Java passes object variables to anonymous classes. There is newer syntax in Java Language version 7 but Android is compatible with Java Language version 5 and 6.
Here is a typical case where service callback is called to update a UI status string (TextView textStatus). The service may be threaded.
The sample combines checking if thread redirection is needed and the actual redirection:
// service callbacks
public void service_StatusTextChanged(final String s) {
if( isOnUiThread() ) {
textStatus.setText(s);
} else {
runOnUiThread(new Runnable() {
#Override
public void run() {
textStatus.setText(s);
}
});
}
}
static public boolean isOnUiThread() {
return Thread.currentThread() == Looper.getMainLooper().getThread();
}
See also How to check if running on UI thread in Android?
public static Activity globalContext = null;
CommonSetting.globalContext = this;// put this in MainACtivity.onCreate()
public void createToastShort(final String message) {
runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(CommonSetting.globalContext, message, Toast.LENGTH_SHORT).show();
}
});
}