I am having a design issue sending progress bar value from class called from a Thread in Activity class to update the GUI, as the following
[The code snippet don't compile it's for explaining only]:
Class A : Extend Activity {
new Thread(new Runnable()
{
public void run()
{
B objB = new B();
objB.DownloadFile();
}
}).start();
}
Class B {
public void DownloadFile()
{
... some work [preparing SOAP request]
while(response.read())
{
//send calculated progress to Class A to update the progress value
}
}
}
Any help or guide would be greatly appreciated
I've used a Handler to achieve this effect. Create it in the Activity that you create the ProgressDialog in, then pass the Handler into the maethod you want to get the progress from. Then you can send a message back to the calling Activity to update the progress:
public class ClassA extends Activity {
...
private static final int HANDLER_MESSAGE_PERFORM_DIALOG_UPDATE = 0;
...
new Thread(new Runnable()
{
public void run()
{
B objB = new objB();
objB.DownloadFile(handler);
}
}).start();
...
private Handler handler = new Handler(){
#Override
public void handleMessage(Message msg) {
switch(msg.what){
case Constants.HANDLER_MESSAGE_PERFORM_DIALOG_UPDATE:
progress.setProgress(msg.arg1);
break;
default:
Log.w("TAG_NAME","handleMessage / Message type not recognised / msg.what = "+String.valueOf(msg.what));
}
}
};
}
Class B
{
public void DownloadFile(Handler handler)
{
... some work [preparing SOAP request]
while(response.read())
{
//send calculated progress to Class A to update the progress value
sendMessage(handler,HANDLER_MESSAGE_PERFORM_DIALOG_UPDATE,progress);
}
}
private void sendMessage(Handler handler,int what, int arg1){
Message msg = Message.obtain();
msg.what = what;
msg.arg1 = arg1;
handler.sendMessage(msg);
}
}
I always use this kind of pattre and works gr8 for me...
class A{
new Thread(new Runnable()
{
public void run()
{
B objB = new B(new ListnerClass());
objB.DownloadFile();
}
}).start();
class ListnerClass implements B.ValueListner{
update(int v){
doWork();
}
}
}
class B{
ValueListner listner;
interface ValuListner{
update(int i);
}
B(ValueListner listner){
this.listner = listner;
}
public void DownloadFile()
{
... some work [preparing SOAP request]
while(response.read())
{
listner.update(value);
}
}
}
You could make an updateProgressBar method in class A and then pass class B a reference to class A. Class B could then call the callback function in A (probably pass an int or something to indicate how far the progress is). Updating the UI from a different thread then the UI thread tends to cause problems. Luckily the Activity class has the method "runOnUiThread(Runnable action)". So to set the progress you could do something like:
while(response.read()){
//do stuff here
int progress = getProgress(); //set the progress to something
a.runOnUiThread(new Runnable(){
a.updateProgress(progress);
});
}
Related
I wanted to do some task in the background like in android we can use AsyncTask to do some work using UI thread, in Harmony we have EventHandler which allows us to send and process InnerEvent and Runnable objects on asynchronous threads.
I just want a simple example on how to use it.
please check the sample -
public class EventHandlerImplementation extends EventHandler {
private EventHandlerImplementation(EventRunner runner) {
super(runner);
}
#Override
public void processEvent(InnerEvent event) {
getUITaskDispatcher().asyncDispatch(() -> {
// do your stuff here
});
}
}
private final int eventUpdateGet = 1001;
private final int eventUpdateSend = 1002;
private class MyEventHandler extends EventHandler {
private MyEventHandler(EventRunner runner) throws IllegalArgumentException {
super(runner);
}
#Override
protected void processEvent(InnerEvent event) {
super.processEvent(event);
switch (event.eventId) {
case eventUpdateGet:
Object object = event.object;
txGet.setText(String.valueOf(object));
break;
case eventUpdateSend:
....
break;
default:
break;
}
}
}
#Override
protected void onStart(Intent intent) {
myHandler = new MyEventHandler(EventRunner.current());
}
When you use, you could :
String msgGet = "......"
InnerEvent event = InnerEvent.get(eventUpdateGet, msgGet);
myHandler.sendEvent(event);
For more details, pls kindly refer to this official Docs.
I have a Service which is connected to a socket in a thread. When the socket receives a message it triggers a callback in a fragment via a (static) interface. Now, when two messages are received in a very short time (.3 sec) the callback is triggered twice but with the same return value.
Code:
In the service I have declared the interface like this:
public interface OnVideoViewTokenReceived {
void videoViewTokenReceived(String videoStreamToken, String cameraId);
}
public static void setOnVideoViewTokenReceived(OnVideoViewTokenReceived _onVideoViewTokenReceived) {
Log.d(TAGSHRDL, "_onVideoViewTokenReceived set");
onVideoViewTokenReceived = _onVideoViewTokenReceived;
}
public static OnVideoViewTokenReceived onVideoViewTokenReceived;
and in a thread, service is connecting to a socket and receiving message frm it:
networkThread = new Thread() {
#Override
public void run() {
...
socket.addListener(new WebSocketAdapter() {
#Override
public void onTextMessage(WebSocket websocket, String message) throws Exception {
....
streamToken = messageJSON.getJSONObject("payload").getString("token");
Handler handler = new Handler(Looper.getMainLooper()); //!!!Without this, token will not be received in the fragment
handler.post(new Runnable() {
#Override
public void run() {
onVideoViewTokenReceived.videoViewTokenReceived(streamToken, camId);
}
});
}
}
};
networkThread.start();
and callback in my fragment:
GeneralSocketService.setOnVideoViewTokenReceived(new GeneralSocketService.OnVideoViewTokenReceived() {
#Override
public void videoViewTokenReceived(String videoStreamToken, String camId) {
for (int i = 0; i<9 ; i++){
....}
Now here in my fragment, it all works well, but when the time between two messages is very short, the callback is triggered twice but with the same return value of videoStreamToken. I have used synchronized() as well but I had no luck. What should I do?
So I had a crack at coding my own AsyncTask class like system that runs on a ThreadPoolExecutor natively. Everything was working fine until I decided to implement the progress side of things. The progress works much like AsyncTask, the onProgressUpdate function is called on the UI thread. The problem I'm experiencing is that whenever there is a System.out or Log.x line in the onProgressUpdate it hangs indefinitely with no error or warning oddly. The code is as below:
public abstract class Task<A, B> {
private static final Executor EXECUTOR = getExecutor();
private static final int DEFAULT_PRIORITY = Thread.MIN_PRIORITY;
private static final int DEFAULT_PROGRESS_INCREMENT = 1;
private static final Executor getExecutor() {
ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newCachedThreadPool();
executor.setCorePoolSize(1);
executor.allowCoreThreadTimeOut(false);
// TODO set rejection handler
//executor.setRejectedExecutionHandler(new Handler());
// TODO set thread factory
executor.prestartCoreThread();
return executor;
}
public static class ExecutionListener<B> {
public void onPreExecute() {
Log.i("TASK", "Pre - Thread: " + Thread.currentThread().getId());
}
public void onPostExecute(B output) {
Log.i("TASK", "Post - Thread: " + Thread.currentThread().getId() + " - Output: " + output);
}
public void onProgressUpdate(int progress) {
Log.d("TASK", "Hello");
}
}
private Handler handler;
private ExecutionListener<B> executionListener;
private volatile int progress = 0;
private AtomicBoolean progressPublished = new AtomicBoolean(true);
private B output;
public Task() {
this.handler = new Handler();
this.executionListener = new ExecutionListener();
}
public void setExecutionListener(ExecutionListener executionListener) {
if(executionListener == null) {
this.executionListener = new ExecutionListener();
}
else {
this.executionListener = executionListener;
}
}
protected void updateProgress(int progressMade) {
Log.d("TASK", "Test");
progress += progressMade;
if(progressPublished.compareAndSet(true, false)) {
if(!handler.post(new Runnable() {
#Override
public void run() {
Log.d("TASK", new Integer(progress).toString() + " - a");
executionListener.onProgressUpdate(progress);
// Hangs below
progressPublished.lazySet(true);
Log.d("TASK", new Integer(progress).toString() + " - b");
}
})) {
Log.d("TASK", "Failed to post");
}
}
}
protected void updateProgress() {
updateProgress(DEFAULT_PROGRESS_INCREMENT);
}
protected abstract B doTask(A input);
public void execute(final A input, final int priority) {
EXECUTOR.execute(new Runnable() {
#Override
public void run() {
Thread.currentThread().setPriority(priority);
handler.post(new Runnable() {
#Override
public void run() {
executionListener.onPreExecute();
}
});
output = doTask(input);
if(!handler.post(new Runnable() {
#Override
public void run() {
Log.d("TASK", "Done");
executionListener.onPostExecute(output);
}
})) {
Log.d("TASK", "Failed to post post");
}
}
});
}
public void execute(final A input) {
execute(input, DEFAULT_PRIORITY);
}
}
The ExecutionListener is just a class to override the methods to be run on the UI much like AsyncTask's methods for doing the same. The code uses Runnable objects to execute the doTask method and send updates / the result to the appropriate method in the ExecutionListener.
The Thread.currentThread() parts are just to ensure things are running on the thread I intended them to. The problem only shows itself when running a Task that frequently calls updateProgress() - I have tried putting a thread sleep in the onProgressUpdate() method and that seems so solve things, though that obviously isn't a good solution.
It also only seems to have a problem with Log.x / System.out - I don't know whether the call frequency of either of them could cause this kind of issue. I'm at a loss with this progress feature and logging so any advice would be greatly appreciated - I've also found this quite hard to explain so please ask if you need me to clarify anything!
Turns out the Thread.currentThread().getId() is at fault. Removing that part fixes everything. Follow up question here: Is Java Thread getId() thread-safe?
I have 2 Classes: a Main Class handling the UI and a second Class for retrieving Data from SQL Server by using PHP.
From the first class a mehtod in the second class is called with passing and retrieving variables.
Actually it is working fine without AsyncTask.
But since I want to use the code on devices running Android 3.0 and above, I need to change the method to be an AsyncTask. Else I get this error: "android.os.networkonmainthreadexception"
the actual working code Looks like this:
Main class:
...
String inputString="1";
String outputString;
outputString = Class2.SomeMethodInClass2(inputString);
....
Class2:
public class Class2 {
public static String SomeMethodInClass2(String input) {
String Output;
...
//Do some php-sql stuff based on "input"-variable
//and return the "output"-variable
...
return output;
}
}
This code works perfectly on Android 2.0 but I need to change it to AsyncTask, because Andoid 3.0 and above is giving me: "android.os.networkonmainthreadexception"
I have read a lot of threads about AsyncTask, but I can not get it to work with Input and Output in my code.
Eclipse allways tells me there is something wrong with my code.
How do I have to change my code, to be a working async Task? (please explain using my above code sample)
--edit: if there is an easier way to get rid of "android.os.networkonmainthreadexception" on 3.0 an above than AsyncTask, this would be fine too! --
Have a Callback in SecondClass
Extend your SecondClass with Asynctask
Implement preExecute,doinbackground, postExecute methods
Do your stuff in doinbackground
return result in doinbackground
In postExecute pass result to the Callback
Implement SecondClass.Callback in FirstClass
start SecondClass (execute) and pass a Callback reference from FirstClass
In Callback just handle your next operations with the result
EDIT :
public class SecondClass extends AsyncTask<String, Void, String> {
public interface Callback {
public void update(String result);
}
Callback mCallback;
public SecondClass(Callback callback) {
super();
mCallback = callback;
}
#Override
protected String doInBackground(String... params) {
String result = null;
//do your stuff and save result
return result;
}
#Override
protected void onPostExecute(String result) {
if(mCallback != null)
mCallback.update(result)
super.onPostExecute(e);
}
}
public class FirstClass implements SecondClass.Callback{
#Override
public void update(String result){
//do your stuff with result
}
return_type someMethod(){
SecondClass sc = new SecondClass(this) ;
sc.execute(someurl);
}
}
thanks for your Posts!
But i found an alternative way that seems much easier and better to me than doing async Task.
i added to my main class:
public class MainClass extends Activity implements OnTouchListener {
...
BackgroundOperations1 ourBackgroundOperations; //<===new
...
#Override
protected void onCreate(Bundle savedInstanceState) {
...
ourBackgroundOperations = new BackgroundOperations1(); //<===new
...
}
#Override
protected void onPause() {
....
ourBackgroundOperations.pause(); // <===new
}
#Override
protected void onResume() {
....
ourBackgroundOperations.resume(); // <===new
}
//whole new class inside of "MainClass"
//runs a different thread, i believe...?
public class BackgroundOperations1 implements Runnable {
Thread ourThread = null;
boolean isRunning = false;
public void pause() {
isRunning = false;
while (true) {
try {
ourThread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
break;
}
}
public void resume() {
isRunning = true;
ourThread = new Thread(this);
ourThread.start();
}
#Override
public void run() {
while (isRunning) {
if (dothis==true){
//here i call my mehtod from class2, whenever "dothis" is set to true (somewhere in my onTouch or where ever i want)
String inputString="1";
String outputString;
outputString = Class2.SomeMethodInClass2(inputString);
}
}
}
}
}
this works on Android 4.0 and i think it is the best way to do what i want. and to me it seems a lot clearer then AsyncTask, because i can call my methods an pass varaibles in a simple way.
or is there a reason to not do it like this?
The below method onReceivedTitlegets called 2-3 times with in a second when webview url changes. I want to call a method in it, when onReceivedTitle is being called last time. I am doing this because I just want to monitor url changes with in webview. shouldOverrideUrlLoading is not getting called when url changes through ajax.
class MyWebChromeClient extends WebChromeClient {
#Override
public void onReceivedTitle(WebView view, String title) {
Log.v("onReceivedTitle", "=>" + title);
// callAMehod();
super.onReceivedTitle(view, title);
}
}
If you want to throttle how often a method call causes another method call you can do so for example via a Handler. The simplest version enqueues a delayed message on the first call and any subsequent call while there is an enqueued message will not enqueue a new one. That results in 1 call every X time to go though - but it take at least that amount of time until the first action happens.
Example implementation (you can put that class unmodified somewhere in your code)
public abstract class ThrottleExecutor {
private final long mMinDelay;
public ThrottleExecutor(long minDelay) {
mMinDelay = minDelay;
}
/** Implement to do something */
public abstract void doThrottled();
public final void scheduleExecution() {
if (mHandler.hasMessages(0)) {
// message already enqueued, do nothing
} else {
// otherwise enqueue a message for later
mHandler.sendEmptyMessageDelayed(0, mMinDelay);
}
}
public final void cancelExecution() {
mHandler.removeMessages(0);
}
private final Handler mHandler = new Handler(Looper.getMainLooper()) {
#Override
public void handleMessage(Message msg) {
doThrottled();
}
};
}
And then use it for example like so
class Usage {
private ThrottleExecutor mThrottle = new ThrottleExecutor(2000) {
#Override
public void doThrottled() {
// happens at most every 2000ms
methodToBeThrottled();
}
};
void methodThatHappensTooOften() {
mThrottle.scheduleExecution();
}
void methodToBeThrottled() {
Log.d("TAG", "triggered at 2000ms before");
}
}
You might want to use Handler and do something like this:
class MyWebChromeClient extends WebChromeClient {
private boolean mOnReceivedTitleInvoked;
#Override
public synchronized void onReceivedTitle(final WebView view, final String title) {
if (!mOnReceivedTitleInvoked) {
mOnReceivedTitleInvoked = true;
Log.v("onReceivedTitle", "=>" + title);
handler.postDelayed(new Runnable() {
#Override
public void run() {
super.onReceivedTitle(view, title);
mOnReceivedTitleInvoked = false;
}
}, 1000);
}
}
}
Although you might want to reconsider the onReceivedTitle behaviour.