I'm new to writing app for android. I've got program writing experience in non object oriented program language but would like to learn this way of programming too.
I would like to start simple and do the following:
Press a button and a the vibrator of the phone will be triggered in a certain pattern until the button is pressed again
I know that if you say: vibrator.vibrate(pattern , 0); that it will repeat the pattern. But I would like to turn on and off the screen in that pattern too for example.
What would be the right way to do this?
Thank you very much for your help.
package com.trick-design.simple_prog;
import android.app.Activity;
import android.os.Bundle;
import android.content.Context;
import android.os.Vibrator;
import android.view.View;
public class simple_prog extends Activity {
private long[] pattern = {100, 100, 300, 100, 900, 1050};
boolean vibrator_on = true;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
#Override
protected void onStart() {
super.onStart();
findViewById(R.id.vibrate_button).setOnClickListener(vibrate_click_listener);
}
View.OnClickListener vibrate_click_listener = new View.OnClickListener() {
public void onClick(View v) {
Vibrator vibrator = (Vibrator)getSystemService(Context.VIBRATOR_SERVICE);
vibrator.vibrate(pattern , -1);
}
};
#Override
protected void onStop() {
super.onStop();
// The activity is no longer visible (it is now "stopped")
}
#Override
protected void onDestroy() {
super.onDestroy();
// The activity is about to be destroyed.
}
}
As an extension of TVK-'s answer:
You would need to create a class that either implements Runnable or extends Thread to do this work in another thread to prevent the hang. You can do this with a second class in the same *.java file -- allowing it to access the variables from the other class in the file:
private class VibrateRunner implements Runnable
{
public void run()
{
while(vibrate_on)
{
executeVibrate();
}
}
private void executeVibrate()
{
vibrator.vibrate(pattern , -1);
}
}
Your on click listener would need to be smart enough to start/stop the thread - ex:
// Make a Thread class variable
Thread bgThread = null;
onClick(View v)
{
// You already started the thread - stop it
if(bgThread != null)
{
vibrate_on = false;
bgThread.join();
return;
}
// Need to turn on the thread
vibrate_on = true;
Runnable runner = new VibrateRunner();
bgThread = new BackgroundThread(runner);
bgThread.setDaemon(true); // Run it in the background
bgThread.start();
}
That should get you off in the right direction. Note: I cut out a lot of exception handling in here -- just read up some on Java threads to get the feel for it. Eclipse will also help you generate the right try/catch blocks.
-- Dan
Try this:
public void vibrate() {
vibrator.vibrate(pattern , -1);
if(vibrator_on) {
vibrate();
}
}
This method will repeat itself until vibrate_on is false. (Make sure it runs in its own thread, otherwise it will freeze up whatever thread it's running it for as long as vibrate_on is true.
Update:
As discussed in the comments, this is no good.
This should do better:
public void doVibrate() {
while(vibrate_on) {
executeVibrate();
}
}
public void executeVibrate() {
vibrator.vibrate(pattern , -1);
}
Related
For my app I want to disable/change a specific button that is pressed.
I have an onclick method called btnClicked which simplified looks like this:
Public class MainActivity extends Activity{
Button myBytton;
#Override
protected void onCreate(Bundle savedInstanceState) {
myBytton = (Button)findViewById(R.id.buttonCall);
}
public void btnClicked(View view)
{
myBytton.setText("loading");
myBytton.setEnabled(false);
myBytton.setClickable(false);
// Do a call to an external api
callApi();
}
public void callApi(){
// run querys
if(succesullyCalledApi){
vibrator.vibrate(500);
// I tried commenting out the below part,
// it is than visible that the phone vibrates before it
// has changed the text (atleast a quarter of a second).
myBytton.setText("search");
myBytton.setEnabled(true);
myBytton.setClickable(true);
}
}
}
In the callApi method is a vibrate method which vibrates after the function gets a result.
Also if there is a result in the callApi myButton will be enabled and the text changed to search.
What happens is the following:
I click on the button, the phone vibrates first and afterwards it changes its text.
my question.
Why did callApi / vibrate run before myBytton.setText ?
what NigelK said is true.
When you arrive in the btnClicked method all the instructions are made on the UI thread. Therefore when you ask the System to vibrate, it will be blocked for XX time depending on the time you passed to the method vibrator.vibrate(XX);.
In order to avoid this "freeze" you need to make the vibration on another Thread.
Here is what it will look like :
Public class MainActivity extends Activity
{
Button myBytton;
#Override
protected void onCreate(Bundle savedInstanceState)
{
myBytton = (Button)findViewById(R.id.buttonCall);
}
public void btnClicked(View view)
{
myBytton.setText("loading");
myBytton.setEnabled(false);
myBytton.setClickable(false);
// Do a call to an external api
callApi();
}
public void callApi()
{
// run querys
if(succesullyCalledApi)
{
// here you create and run the Thread.
// put anything you want to do inside the run method
new Thread(
new Runnable()
{
public void run()
{
// here you start the vibration
vibrator.vibrate(500);
}
}
).start();
// I tried commenting out the below part,
// it is than visible that the phone vibrates before it
// has changed the text (atleast a quarter of a second).
myBytton.setText("search");
myBytton.setEnabled(true);
myBytton.setClickable(true);
}
}
}
And that's it. It will launch another Thread that will handle the vibration and not freeze your UI thread.
EDIT
Here is the AsyncTask version :
The three elements asked when you extend AsyncTask are :
The type of the parameters you pass to the doInBackground() method
The Type of the elements that are passed in the onProgressUpdate() method.
The Type of the element returned by the doInBackground() method that is also the parameter of the onPostExecute() method.
This is what it looks like :
public class MyTask extends AsyncTask<Void, Integer, Boolean>
{
private Button mButton;
public MyTask(Button button)
{
mButton = button;
}
// Here everything will run on a background Thread
protected Boolean doInBackground(Void... voids)
{
boolean succesullyCalledApi = false;
// do your long querys here
// ...
return succesullyCalledApi;
}
// Here everything will run on the UI Thread
protected void onProgressUpdate(Integer... progress) {
// here you can make some update to the UI like updating a
// progress bar
}
// Here everything will run on the UI Thread
protected void onPostExecute(Boolean succesullyCalledApi)
{
if(succesullyCalledApi)
{
mButton.setText("search");
mButton.setEnabled(true);
mButton.setClickable(true);
// here you start the vibration
vibrator.vibrate(500);
}
}
}
And in your callApi() method you only have to to this :
public void callApi()
{
new MyTask(myButton).execute();
}
EDIT 2
In order to retrieve the query back to your main Thread (or UI Thread) all you have to do is ... nothing.
You are in the UI Thread when the onPostExecute() method is called.
But I assume that you want to retrieve the query back to your MainActivity. To do so :
Pass MainActivity in parameter of MyTask constructor,
Create a method in MainActivity named processQuery() (or whatever you want),
Finally call this method in the onPostExecute() method.
Here are some snippets :
Public class MainActivity extends Activity
{
Button myBytton;
...
public void callApi()
{
// add this to the constructor
new MyTask(this, myButton).execute();
}
// I put String here but adapt it to your query Type.
public void processQuery(String query)
{
// process your query here.
}
}
public class MyTask extends AsyncTask<Void, Integer, Boolean>
{
private Button mButton;
private MainActivity mMainActivity;
public MyTask(MainActivity mainActivity, Button button)
{
mButton = button;
mMainActivity = mainActivity;
}
...
// Here everything will run on the UI Thread
protected void onPostExecute(Boolean succesullyCalledApi)
{
if(succesullyCalledApi)
{
// process your query
mMainActivity.processQuery("THE QUERY YOUR WANT TO PROCESS");
mButton.setText("search");
mButton.setEnabled(true);
mButton.setClickable(true);
// here you start the vibration
vibrator.vibrate(500);
}
}
}
There probably is a better way to do this but this one is simple and work :)
Hope it helps.
Cheers
This is because your call to the API is being done on the UI thread. Even though you have made changes to the UI, the screen won't refresh until the processing invoked from the button clicked event completes. Call your API on a new thread or via an Async Task to get the behaviour you want.
Because you are doing all stuff at the UI Thread. You must use an AsyncTask for your long running operations.
Try below implementation:
public void callApi() {
MyTask myTask = new MyTask();
myTask.execute();
}
private class MyTask extends AsyncTask<Void, Void, Boolean> {
protected void doInBackground(Void... params) {
// This runs on a separate background thread
boolean succesullyCalledApi = false;
// run querys
// do your long running query here and return its result.
return succesullyCalledApi;
}
protected void onPostExecute(Boolean succesullyCalledApi) {
// this runs on UI Thread
if(succesullyCalledApi){
vibrator.vibrate(500);
myBytton.setText("search");
myBytton.setEnabled(true);
myBytton.setClickable(true);
} else {
// You should better think this part also. what will happen if result is false?
}
}
}
I am currently developing an app in Android which will record sensor data for a fixed length of time for several cycles. For example, I plan to record the data for 10 seconds, and then stop, let the phone rest for 10 seconds, and start record again, ... working in this pattern for 1 hour. My question is, how to let the phone automatically execute this plan? I am currently using code below ( from Android: How to collect sensor values for a fixed period of time?) , but it only works for one cycle, I have to manually start new cycles after I am sure the previous cycle has finished.
public void onResume() {
mSensorManager.registerListener(mListener, mSensorAcceleration, SensorManager.SENSOR_DELAY_GAME);
mSensorManager.registerListener(mListener, mSensorMagnetic, SensorManager.SENSOR_DELAY_GAME);
Handler h = new Handler();
h.postDelayed(new Runnable() {
#Override
public void run() {
// do stuff with sensor values
mSensorManager.unregisterListener(mListener);
}
}, 10000);
...
Any help will be appreciated!!
I think there's a better and more correct way to implement this. Specifically, I think it's wrong to let the Activity implement Runnable. It leaks logic in its public interface that should be kept private (and hidden). I.e. no one is ever supposed to invoke run() outside the activity. I would suggest implementing it as follows instead:
public class PostDelayedDemo extends Activity {
// Declaration of sensor-related fields.
private static final int PERIOD = 10000;
private Handler handler;
private final Runnable processSensors =
new Runnable() {
#Override
public void run() {
mSensorManager.registerListener(mListener, mSensorAcceleration, SensorManager.SENSOR_DELAY_GAME);
mSensorManager.registerListener(mListener, mSensorMagnetic, SensorManager.SENSOR_DELAY_GAME);
// Do work with the sensor values.
mSensorManager.unregisterListener(mListener);
// The Runnable is posted to run again here:
handler.postDelayed(this, PERIOD);
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
handler = new Handler();
}
#Override
public void onResume() {
super.onResume();
handler.post(processSensors);
}
#Override
public void onPause() {
handler.removeCallbacks(processSensors);
super.onPause();
}
}
Step #1: Have your activity implement Runnable, rather than use an anonymous inner class, moving your run() method to be implemented on the activity.
Step #2: In your run() method, schedule yourself (the activity) to run again after a delay using postDelayed(). This, plus your existing call to postDelayed(), will effectively set up a periodic call to run().
Step #3: Keep track of whether you are in "sensors on" or "sensors off" mode, and, in run(), either register or unregister the listeners as appropriate.
Step #4: In onPause(), call removeCallbacks() on your Handler to stop the periodic calls to run().
You will see an example of this sort of schedule-yourself-to-run-again logic in this sample project. Here is the activity:
package com.commonsware.android.post;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Toast;
public class PostDelayedDemo extends Activity implements Runnable {
private static final int PERIOD=5000;
private View root=null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
root=findViewById(android.R.id.content);
}
#Override
public void onResume() {
super.onResume();
run();
}
#Override
public void onPause() {
root.removeCallbacks(this);
super.onPause();
}
#Override
public void run() {
Toast.makeText(PostDelayedDemo.this, "Who-hoo!", Toast.LENGTH_SHORT)
.show();
root.postDelayed(this, PERIOD);
}
}
I am using Thread for loading library (Native code ) have to call some functions from the android code to the native code. it's working fine after some time thread terminating, so those functions are not calling properly. present i am using this code for thread creation.
class aThread extends Thread {
public static boolean finished;
public void run() {
if ( a_app.initApp() != 0) {
return;
} else {
}
a_app.startPjsua(ApjsuaActivity.CFG_FNAME);
finished = true;
a_app.deinitApp();
}
}
Is it correct process or not.?
Can i use any service for solving this problem, if yes how to create communication between activity and Service.
My requirement is i have to call a function in the background continuous upto app closes fully.? what is the best way to do like this.
Are you looking for something like this?
boolean ok;
onCreate(Bundle a)
{
...
ok=true;
new aThread().start();
}
class aThread extends Thread {
public static boolean finished;
public void run() {
while(ok==true)
{
if ( a_app.initApp() != 0) {
ok=false;
} else {
a_app.startPjsua(ApjsuaActivity.CFG_FNAME);
finished = true;
a_app.deinitApp();
}
//If you want to execute after some interval..
//Thread.sleep(time_in_milliseconds);
}
}
}
This way it will run as long as ok=true. When you exit the app or if you want to stop the thread; set the value of ok=false.
Why i can't force Android ANR with this code?
No log messages or pop up. The application is just launched lazily.
[UPDATE]
I can't get it even sleeping a View.setOnClickListener or BroadcastReceiver.onReceive!
Is there a trick?
public class MainActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
Log.e("Test", "", e);
}
}
}
I'm using Samsung GT-6200L with stock Android 3.2
Try it in onTouchEvent. In onCreate your activity is not fully running
#Override
public boolean onTouchEvent(MotionEvent event) {
Log.d(TAG,"onTouchEvent");
while(true) {}
}
The ANR-WatchDog project has a test app that produces ANRs in a reliable manner (as reliable as ANRs can be): the app hangs because of a deadlock.
The gist of it:
Prepare a lock object as a private field in your activity:
final Object mutex = new Object();
Have a thread that performs some work in a critical section, and an android.os.Handler that posts work depending on the same lock.
new Thread(new Runnable() {
#Override
public void run() {
synchronized (mutex) {
while (true) {
try {
Thread.sleep(60000);
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}).start();
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
synchronized (mutex) {
// Shouldn't happen
throw new IllegalStateException();
}
}
}, 1000);
Putting the above code snippet inside a button click handler, for example, should do the trick.
I've been facing the same issue yesterday, and I've found out that using a plain debug build ANR dialogs simply won't show up. (Although the UI thread was completely hanged.)
But after exporting and properly signing the application the dialogs were popped up properly (in every cases mentioned above). However I am still not sure what really prevents to pop up ANR messages, maybe someone else can clarify this later...
Try using:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
int a=0;
while(true) {
a++;
}
}
Your code probably didn't work because it got setup too early, and the Activity probably wasn't fully initialized and created yet. With the above code, launch the activity and touch/swipe on the screen and wait for the ANR dialog to popup.
Make a button in your activity.
public void onBtn1(View v) {
int a = 0;
while(true) {
a++;
}
}
Make the button execute the above code.
Spam click the button with your finger =)
I used this code for force ANR
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void force(View view){
while(true) {}
}
I just created a simple button in the xml file and set android:onClick=force
I have a very simple AsyncTask implementation example and am having problem in testing it using Android JUnit framework.
It works just fine when I instantiate and execute it in normal application.
However when it's executed from any of Android Testing framework classes (i.e. AndroidTestCase, ActivityUnitTestCase, ActivityInstrumentationTestCase2 etc) it behaves strangely:
It executes doInBackground() method correctly
However it doesn't invokes any of its notification methods (onPostExecute(), onProgressUpdate(), etc) -- just silently ignores them without showing any errors.
This is very simple AsyncTask example:
package kroz.andcookbook.threads.asynctask;
import android.os.AsyncTask;
import android.util.Log;
import android.widget.ProgressBar;
import android.widget.Toast;
public class AsyncTaskDemo extends AsyncTask<Integer, Integer, String> {
AsyncTaskDemoActivity _parentActivity;
int _counter;
int _maxCount;
public AsyncTaskDemo(AsyncTaskDemoActivity asyncTaskDemoActivity) {
_parentActivity = asyncTaskDemoActivity;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
_parentActivity._progressBar.setVisibility(ProgressBar.VISIBLE);
_parentActivity._progressBar.invalidate();
}
#Override
protected String doInBackground(Integer... params) {
_maxCount = params[0];
for (_counter = 0; _counter <= _maxCount; _counter++) {
try {
Thread.sleep(1000);
publishProgress(_counter);
} catch (InterruptedException e) {
// Ignore
}
}
}
#Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
int progress = values[0];
String progressStr = "Counting " + progress + " out of " + _maxCount;
_parentActivity._textView.setText(progressStr);
_parentActivity._textView.invalidate();
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
_parentActivity._progressBar.setVisibility(ProgressBar.INVISIBLE);
_parentActivity._progressBar.invalidate();
}
#Override
protected void onCancelled() {
super.onCancelled();
_parentActivity._textView.setText("Request to cancel AsyncTask");
}
}
This is a test case. Here AsyncTaskDemoActivity is a very simple Activity providing UI for testing AsyncTask in mode:
package kroz.andcookbook.test.threads.asynctask;
import java.util.concurrent.ExecutionException;
import kroz.andcookbook.R;
import kroz.andcookbook.threads.asynctask.AsyncTaskDemo;
import kroz.andcookbook.threads.asynctask.AsyncTaskDemoActivity;
import android.content.Intent;
import android.test.ActivityUnitTestCase;
import android.widget.Button;
public class AsyncTaskDemoTest2 extends ActivityUnitTestCase<AsyncTaskDemoActivity> {
AsyncTaskDemo _atask;
private Intent _startIntent;
public AsyncTaskDemoTest2() {
super(AsyncTaskDemoActivity.class);
}
protected void setUp() throws Exception {
super.setUp();
_startIntent = new Intent(Intent.ACTION_MAIN);
}
protected void tearDown() throws Exception {
super.tearDown();
}
public final void testExecute() {
startActivity(_startIntent, null, null);
Button btnStart = (Button) getActivity().findViewById(R.id.Button01);
btnStart.performClick();
assertNotNull(getActivity());
}
}
All this code is working just fine, except the fact that AsyncTask doesn't invoke it's notification methods when executed by within Android Testing Framework. Any ideas?
I met a similar problem while implementing some unit-test. I had to test some service which worked with Executors, and I needed to have my service callbacks sync-ed with the test methods from my ApplicationTestCase classes. Usually the test method itself finished before the callback would be accessed, so the data sent via the callbacks would not be tested. Tried applying the #UiThreadTest bust still didn't work.
I found the following method, which worked, and I still use it. I simply use CountDownLatch signal objects to implement the wait-notify (you can use synchronized(lock){... lock.notify();}, however this results in ugly code) mechanism.
public void testSomething(){
final CountDownLatch signal = new CountDownLatch(1);
Service.doSomething(new Callback() {
#Override
public void onResponse(){
// test response data
// assertEquals(..
// assertTrue(..
// etc
signal.countDown();// notify the count down latch
}
});
signal.await();// wait for callback
}
I found a lot of close answers but none of them put all the parts together correctly. So this is one correct implementation when using an android.os.AsyncTask in your JUnit tests cases.
/**
* This demonstrates how to test AsyncTasks in android JUnit. Below I used
* an in line implementation of a asyncTask, but in real life you would want
* to replace that with some task in your application.
* #throws Throwable
*/
public void testSomeAsynTask () throws Throwable {
// create a signal to let us know when our task is done.
final CountDownLatch signal = new CountDownLatch(1);
/* Just create an in line implementation of an asynctask. Note this
* would normally not be done, and is just here for completeness.
* You would just use the task you want to unit test in your project.
*/
final AsyncTask<String, Void, String> myTask = new AsyncTask<String, Void, String>() {
#Override
protected String doInBackground(String... arg0) {
//Do something meaningful.
return "something happened!";
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
/* This is the key, normally you would use some type of listener
* to notify your activity that the async call was finished.
*
* In your test method you would subscribe to that and signal
* from there instead.
*/
signal.countDown();
}
};
// Execute the async task on the UI thread! THIS IS KEY!
runTestOnUiThread(new Runnable() {
#Override
public void run() {
myTask.execute("Do something");
}
});
/* The testing thread will wait here until the UI thread releases it
* above with the countDown() or 30 seconds passes and it times out.
*/
signal.await(30, TimeUnit.SECONDS);
// The task is done, and now you can assert some things!
assertTrue("Happiness", true);
}
The way to deal with this is to run any code that invokes an AsyncTask in runTestOnUiThread():
public final void testExecute() {
startActivity(_startIntent, null, null);
runTestOnUiThread(new Runnable() {
public void run() {
Button btnStart = (Button) getActivity().findViewById(R.id.Button01);
btnStart.performClick();
}
});
assertNotNull(getActivity());
// To wait for the AsyncTask to complete, you can safely call get() from the test thread
getActivity()._myAsyncTask.get();
assertTrue(asyncTaskRanCorrectly());
}
By default junit runs tests in a separate thread than the main application UI. AsyncTask's documentation says that the task instance and the call to execute() must be on the main UI thread; this is because AsyncTask depends on the main thread's Looper and MessageQueue for its internal handler to work properly.
NOTE:
I previously recommended using #UiThreadTest as a decorator on the test method to force the test to run on the main thread, but this isn't quite right for testing an AsyncTask because while your test method is running on the main thread no messages are processed on the main MessageQueue — including the messages the AsyncTask sends about its progress, causing your test to hang.
If you don't mind executing the AsyncTask in the caller thread (should be fine in case of Unit testing), you can use an Executor in the current thread as described in https://stackoverflow.com/a/6583868/1266123
public class CurrentThreadExecutor implements Executor {
public void execute(Runnable r) {
r.run();
}
}
And then you run your AsyncTask in your unit test like this
myAsyncTask.executeOnExecutor(new CurrentThreadExecutor(), testParam);
This is only working for HoneyComb and higher.
I wrote enough unitests for Android and just want to share how to do that.
First off, here is helper class that responsible to wait and release waiter. Nothing special:
SyncronizeTalker
public class SyncronizeTalker {
public void doWait(long l){
synchronized(this){
try {
this.wait(l);
} catch(InterruptedException e) {
}
}
}
public void doNotify() {
synchronized(this) {
this.notify();
}
}
public void doWait() {
synchronized(this){
try {
this.wait();
} catch(InterruptedException e) {
}
}
}
}
Next, lets create interface with one method that should be called from AsyncTask when work is done. Sure we also want to test our results:
TestTaskItf
public interface TestTaskItf {
public void onDone(ArrayList<Integer> list); // dummy data
}
Next lets create some skeleton of our Task that we gonna test:
public class SomeTask extends AsyncTask<Void, Void, SomeItem> {
private ArrayList<Integer> data = new ArrayList<Integer>();
private WmTestTaskItf mInter = null;// for tests only
public WmBuildGroupsTask(Context context, WmTestTaskItf inter) {
super();
this.mContext = context;
this.mInter = inter;
}
#Override
protected SomeItem doInBackground(Void... params) { /* .... job ... */}
#Override
protected void onPostExecute(SomeItem item) {
// ....
if(this.mInter != null){ // aka test mode
this.mInter.onDone(data); // tell to unitest that we finished
}
}
}
At last - our unitest class:
TestBuildGroupTask
public class TestBuildGroupTask extends AndroidTestCase implements WmTestTaskItf{
private SyncronizeTalker async = null;
public void setUP() throws Exception{
super.setUp();
}
public void tearDown() throws Exception{
super.tearDown();
}
public void test____Run(){
mContext = getContext();
assertNotNull(mContext);
async = new SyncronizeTalker();
WmTestTaskItf me = this;
SomeTask task = new SomeTask(mContext, me);
task.execute();
async.doWait(); // <--- wait till "async.doNotify()" is called
}
#Override
public void onDone(ArrayList<Integer> list) {
assertNotNull(list);
// run other validations here
async.doNotify(); // release "async.doWait()" (on this step the unitest is finished)
}
}
That's all.
Hope it will help to someone.
This can be used if you want to test the result from the doInBackground method. Override the onPostExecute method and perform the tests there. To wait for the AsyncTask to complete use CountDownLatch. The latch.await() waits till the countdown runs from 1 (which is set during initialization) to 0 (which is done by the countdown() method).
#RunWith(AndroidJUnit4.class)
public class EndpointsAsyncTaskTest {
Context context;
#Test
public void testVerifyJoke() throws InterruptedException {
assertTrue(true);
final CountDownLatch latch = new CountDownLatch(1);
context = InstrumentationRegistry.getContext();
EndpointsAsyncTask testTask = new EndpointsAsyncTask() {
#Override
protected void onPostExecute(String result) {
assertNotNull(result);
if (result != null){
assertTrue(result.length() > 0);
latch.countDown();
}
}
};
testTask.execute(context);
latch.await();
}
How about using join?
fun myTest() = runBlocking {
CoroutineScope(Dispatchers.IO).launch {
// test something here
}.join()
}
Use this simple solution
runBlocking{
//Your code here
}
Most of those solutions require a lot of code to be written for every test or to change your class structure. Which I find very difficult to use if you have many situations under test or many AsyncTasks on your project.
There is a library which eases the process of testing AsyncTask. Example:
#Test
public void makeGETRequest(){
...
myAsyncTaskInstance.execute(...);
AsyncTaskTest.build(myAsyncTaskInstance).
run(new AsyncTest() {
#Override
public void test(Object result) {
Assert.assertEquals(200, (Integer)result);
}
});
}
}
Basically, it runs your AsyncTask and test the result it returns after the postComplete() has been called.