Hi I am trying to get an arraylist of data from a an async task class to another main class:
I was following the answer below but I am a little lost:
How to get the result of OnPostExecute() to main activity because AsyncTask is a separate class?
So I have my class that extends async task and calls to the database to get my object array:
public class GetVideoInfoFromDataBase extends AsyncTask {
// Paginated list of results for song database scan
static PaginatedScanList<AlarmDynamoMappingAdapter> results;
// The DynamoDB object mapper for accessing DynamoDB.
private final DynamoDBMapper mapper;
public interface AlarmsDataBaseAsyncResponse {
void processFinish(PaginatedScanList<AlarmDynamoMappingAdapter> output);
}
public AlarmsDataBaseAsyncResponse delegate = null;
public GetVideoInfoFromDataBase(AlarmsDataBaseAsyncResponse delegate){
mapper = AWSMobileClient.defaultMobileClient().getDynamoDBMapper();
this.delegate = delegate;
}
#Override
protected Object doInBackground(Object[] params) {
DynamoDBScanExpression scanExpression = new DynamoDBScanExpression();
results = mapper.scan(AlarmDynamoMappingAdapter.class, scanExpression);
return results;
}
#Override
public void onPostExecute(Object obj) {
delegate.processFinish(results);
}
}
There are no errors but I think I have done something incorrectly in it causing my error.
So in my main activity to call the results I have:
GetVideoInfoFromDataBase asyncTask =new GetVideoInfoFromDataBase(new GetVideoInfoFromDataBase.AlarmsDataBaseAsyncResponse(){
#Override
public void processFinish(PaginatedScanList<AlarmDynamoMappingAdapter> output) {
}
}).execute();
I have two problems here
I am getting the error:
"incompatible types: AsyncTask cannot be converted to GetVideoInfoFromDataBase"
In the mainactivity where i have:
`new GetVideoInfoFromDataBase(new GetVideoInfoFromDataBase.AlarmsDataBaseAsyncResponse()`
it wants me to cast it like this:
(GetVideoInfoFromDataBase) new GetVideoInfoFromDataBase(new GetVideoInfoFromDataBase.AlarmsDataBaseAsyncResponse()
That doesn't seem right but I thought i would check.
I am not sure how to return the result when overriding the onprocessfinished.
Thanks in advance for your help
First create an Interface
public interface AsyncInterface {
void response(String response);
}
Assign it in the asynctask class as below :-
Context context;
Private AsyncInterface asyncInterface;
AsyncClassConstructor(Context context){
this.context = context;
this.asyncInterface = (AsyncInterface) context;
}
Then inside onPostExecute method of asynctask class :-
#Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
asyncInterface.response(s);
}
Then implement this interface in your activity :-
class MainActivity extends AppCompatActivity implements AsyncInterface {
and then import the method of asyncInterface
#Override
public void response(String response) {
//Here you get your response
Log.e(TAG, response);
}
Modify Constructor of class.
Need default constructor. By the way, create method to set Interface.
public void setInterface(AlarmsDataBaseAsyncResponse delegate){
this.delegate = delegate;}
In MainActivity, push your logic in:
object.setInterface(new AlarmsDataBaseAsyncResponse(){
#Override
public void processFinish(PaginatedScanList<AlarmDynamoMappingAdapter> output) {
//your logic
}
});
Related
I'm new in Java/Android and I come from c#. I've been taking a look into it and testing I found that when I execute an AsyncTask the mainthread keeps executing while the external task is doing it's work. I even found that I can only set the asynctask that execute an external task from the MainActivity.
My problem is that I want to execute an external class that when finished brings back the results(just like c#) to the maintask without setting the async class in the MainActivity.
So.. in code should be something like:
MainActivity.java
public onClickButton(View view) {
String result = SecondaryClass.DoAsyncTask();
}
SecondaryClass.java
private class DoAsyncTask extends AsyncTask<Long, Integer, Integer>
{
#Override
protected Integer doInBackground(Long... params) {
String longString = ThirdAPIClass.GiveMeSomeCode(); //Or work here
return lognString;
}
#Override
protected void onPostExecute(String result) {
return result; //Somehow(?)
}
}
Any idea if there is something similar in Java/Android(?)
PD: I use AsyncTask as an example, I don't know if there is another instruction that do the same or something like that.
Class Singnature:
First Note is that if your result is a String then you need to change your extend clause to:
class DoAsyncTask extends AsyncTask<Long, Integer, String>
Communicating with calling activity:
The AsyncTask's onPostExecute signature is void and it doesn't return data. The most common practices are:
To have this class as an inner class inside your activity, and onPostExecute you can call a method inside that activity.
Add a constuctor to you asyncTask class and pass the activity to it and then call the method using that instance of activity.
First Approach:
#Override
protected void onPostExecute(String result) {
someMethodInMainActivity(result);
}
Second Approach:
public class DoAsyncTask extends AsyncTask<Long, Integer, String>
{
YouActivityName _activity;
public DoAsyncTask(YouActivityName activity)
{
_activity = activity;
}
#Override
protected String doInBackground(Long... params) {
String longString = ThirdAPIClass.GiveMeSomeCode(); //Or work here
return lognString;
}
#Override
protected void onPostExecute(String result) {
if(_activity != null) {
_activity.someMethodInMainActivity(result);
}
}
}
Then you create your AsynTask using :
new DoAsyncTask(this);
I have an issue with the scope of a variable in Android using Retrofit:
In the MainActivity I use Retrofit to get the JSON reply into a POJO (ApiResponse), create a extendedJourney Object and add it to the extendedJourneyArrayList:
public class MainActivity extends Activity {
private ArrayList<ExtendedJourney> extendedJourneyArrayList = new ArrayList<>();
...
getAPIReply(...){
service.getInfo(..., new getCallback());
...}
private class getCallback implements Callback<ApiResponse> {
public void success(ApiResponse apiResponse, Response response) {
try {
consumeApiData(apiResponse);
}
...
}
}
private void consumeApiData(ApiResponse apiResponse){
ExtendedJourney extendedJourney = new ExtendedJourney(apiResponse, params);
extendedJourneyArrayList.add(extendedJourney);
}
public void getData(View view){
getAPIReply(...);
//Do stuff with the extendedJourneyArrayList
}
Inside consumeApiData() everything is OK, i.e. the extendedJourney Object is correctly created from the apiResponse and other params and the extendedJourneyArrayList is correctly updated with the new extendedJourney.
However, in getData(View view), extendedJourneyArrayList is empty.
How can this be solved? Thanks :D
You are making an asynchronous call.
That means, that after the call to service.getInfo(..., new getCallback()); the flow continues normally, until it's intrrrupted by the callback.
So you code in getData(View v) is probably excecuting before the response is received.
So you should do what you want with the data on the callback ( for example in the end of the consumeApiData(..) after the data is added in the list ), or do a synchronous request ( which you must do in a separate thread ).
Thanks #Kushtrim for your answer. To solve the problem I make of use an AsyncTask to perform synchronous requests, the code now looks like this:
public class MainActivity extends Activity {
private ArrayList<ExtendedJourney> extendedJourneyArrayList = new ArrayList<>();
...
public void getData(View view){
for(int i = 0; i < NUM_REQUESTS; i++){
new getAPIReply().execute(params);
}
}
private class getAPIReply extends AsyncTask<Params, Void, ApiResponse>{
#Override
protected ApiResponse doInBackground(Coords[] coords) {
return service.getRouteInfo(params);
}
#Override
protected void onPostExecute(ApiResponse apiResponse){
try {
consumeApiData(apiResponse);
} catch (JSONException e) {...}
}
private void consumeApiData(ApiResponse apiResponse) throws JSONException{
ExtendedJourney extendedJourney = new ExtendedJourney(apiResponse, params);
extendedJourneyArrayList.add(extendedJourney);
if(extendedJourneyArrayList.size() == NUM_REQUESTS) {
//Do stuff
}
}
How do I return a list from AsyncTask to a class instead of a method?
I have this AsyncTask which connects to a webpage, reads the page into a string and then splits it all into variables. This is the page
This is the AsyncTask:
public class sellableIds_AsyncTask extends AsyncTask<String, Void, List> {
String bodyHtml;
List<String> items;
private Context context;
private sellableIdsFilter sellableIdsFilter;
public sellableIds_AsyncTask(Context context) {
this.context = context;
}
public void setSellableIdsFilter(sellableIdsFilter sellableIdsFilter) {
this.sellableIdsFilter = sellableIdsFilter;
}
#Override
protected List doInBackground(String... params) { //Incompatible return type
try {
HttpClient httpClient = new DefaultHttpClient();
HttpGet get = new HttpGet(params[0]);
HttpResponse response = httpClient.execute(get);
bodyHtml = EntityUtils.toString(response.getEntity()).replace("[", "");
;
items = Arrays.asList(bodyHtml.split("\\s*,\\s*"));
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return items;
}
#Override
protected void onPostExecute(List result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
this.sellableIdsFilter.sellableIdsFilter(result);
}
public interface sellableIdsFilter {
public void sellableIdsFilter(List result);
}
}
And called in the activity:
sellableIds_AsyncTask sellableIds_AsyncTask = new sellableIds_AsyncTask(this);
sellableIds_AsyncTask.setSellableIdsFilter(this);
sellableIds_AsyncTask.execute(sellableIdsUrl);
How can I return this list to the activity where I call it from and have the list able to use anywhere within the class? instead to the method sellableIdsFilter();
Create a listener interface
public interface OnSellableIdsFilterListener {
void onSellableIdsFilterSuccess(List<Integer> ids);
}
make the class you need to get the ids implement that interface
public class SomeClassThatNeedsTheIDs implements OnSellableIdsFilterListener {
void someVoid() {
//Pass the instance of this class to the constructor of the asynctask as a listener
new YourAsyncTask(this, this).execute();
}
#Override
public void onGetSellableIdsFilterSuccess(List<Integer> ids) {
// do whatever you want with the ids
}
}
Change your asynctask adding a listener to the constructor
public class YourAsyncTask extends AsyncTask< , , > {
Context context;
OnSellableIdsFilterListener listener;
public YourAsyncTask(Context context, OnSellableIdsFilterListener listener) {
this.listener = listener;
this.context = context;
}
// In onPostExecute check if listener!=null and invoke the method, passing the ids
public void onPostExecute() {
if(listener!=null) {
listener.onSellableIdsFilterSuccess(ids);
}
}
}
You can add a method which returns List 'items' in your 'sellableIds_AsyncTask' class. After calling asyncTasks execute , call get() to ensure async task has finished its task. Then call the getter function to get your List 'items'. Hope this helps.
I'm a beginner in Java and coding for Android. When I was coding an app which makes some network requests, I got NetworkOnMainThreadException exception. I googled and found out the reason and solution. But I still have a question. My app makes requests on different sites and will does different actions with responses (first response on login action, it will be checked, second action is some api calls, third action is requesting images), I think I should not make three different classes for each case (doInBackground is the same, but different onPostExecute methods will be here). How can I fix this problem? Thanks
You can pass an aditional variable as doInBackground Params, save it as "global" class variable and switch in onPostExecute so u dont have to make 3 different classes
Like this
public class Async_DL extends AsyncTask<String, String, String> {
String type_of_request;
String url;
#Override
protected void onPreExecute(){
}
#Override
protected String doInBackground(String... params) {
this.url = params[0];
this.type_of_request = params[1];
doinBackground stuff....
}
#Override
protected void onPostExecute(String result) {
switch(this.type_of_request){
case a:
do some stuff
break;
}
}
}
One solution would be to create an interface callback like this
interface Callback {
public void call (String response); //or whatever return type you want
}
Then you might extends your AsyncTask class like this
private class HttpTask extends AsyncTask <Void,Void,String> {
Callback callback;
HttpTask (Callback callback) {
this.callback = callback;
}
// your doInBackground method
#Override
protected void onPostExecute (String response) {
callback.call(response);
}
}
Then you might call your AsyncTask like this
new HttpTask (new Callback () {
#Override
public void call (String response) { /* Here goes implementation */ }
}).execute();
You dont need to make three separate classes for each action. You can extend only once the AsyncTask and i would suggest to add an interface call which can be implemented by your activity:
public interface RequestListener {
public void onLoginCall();
public void onApiCall();
public void onImageCall();
}
At the same time create an enumeration to hold the requests' types:
public enum RequestType{
LOGIN,
API,
IMAGE;
}
Meanwhile you can extend the AsyncTask and call the necessary listener's methods per each case. You can use the second attribute to hold the type of the request:
public class RequestTask extends AsyncTask<Object, RequestType, Object> {
private RequestListener listener;
#Override
protected void onPreExecute(){
}
#Override
protected String doInBackground(Object... params) {
this.url = params[0];
this.type_of_request = params[1];
doinBackground stuff....
}
#Override
protected void onPostExecute(Object result) {
if(result is from login)
listener.onLoginCall();
... and so on
}
}
In my MainActivity I have a method called getAPI that returns an OTBServiceWrapper. This is used to setup retrofit for calling to an API.
In my MainActivityTest file I am trying to stub out the new OTBService().getService() call that the getApi method is making so I can return a MockedOTBService which changes the client to a custom one that return json.
As is, the current implementation will it the MockedOTBService if I had to place a logger within MockedOTBService but also falls through and calls the real api, which is not want I want in a test.
I am trying to stub the Retrofit API calls using Mockito and return json. I cant seem to understand why the stub is being called yet is not stubbing the method in question.
Notes:
I am using ActivityInstrumentationTestCase2
I am only running one test
If I add a verify(mockedOTBService, atLeastOnce()).getService(); is says it was never called.
If I change the when...thenReturn to use a mMainActivity = spy(getActivity()) there is not change and the real API is called.
Logcat Output
Logger﹕ MockedOTBService was called // Mock is called
Logger﹕ Real OTBService was called // Real API is called
Logger﹕ MainActivity getAPI method class is "$Proxy1" // Mock is shown in MainActivity
Logger﹕ RealAPIResponse JSON Parsed ID: 266 // Real API response returned
Real Flow
MainActivity.onCreate() > OTBService.getService() > OTBServiceWrapper.createSearch(...)
Trying to Achieve within Tests
MainActivity.onCreate() > MockedOTBService.getService() > OTBServiceWrapper.createSearch(...)
MainActivity.java
public class MainActivity extends Activity {
private OTBServiceWrapper serviceWrapper;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
getApi().createSearch(...)
}
public OTBServiceWrapper getApi() {
return new OTBService().getService();
}
}
OTBService.java
public class OTBService {
public OTBServiceWrapper getService() {
RestAdapter restAdapter = new RestAdapter.Builder()
.setEndpoint(Constants.API_URL)
.build();
return restAdapter.create(OTBServiceWrapper.class);
}
}
OTBServiceWrapper.java
public interface OTBServiceWrapper {
#POST(Constants.API_SEARCHES_POST_URL)
void createSearch(#Body Request request, Callback<Request.Response> callback);
}
MainActivityTest.java
public class MainActivityTest extends ActivityInstrumentationTestCase2<MainActivity> {
private OTBService mMockedOTBService;
private MainActivity mMainActivity;
private View mSearchButton;
public MainActivityTest() { super(MainActivity.class); }
#Override
protected void setUp() throws Exception {
super.setUp();
setActivityInitialTouchMode(true);
System.setProperty("dexmaker.dexcache", getInstrumentation().getTargetContext().getCacheDir().getPath());
mMockedOTBService = mock(OTBService.class);
when(mMockedOTBService.getService()).thenReturn(new MockedOTBService(getInstrumentation().getContext()).getService());
mMainActivity = getActivity();
mSearchButton = mMainActivity.findViewById(R.id.AbSearchButton);
mYourHolidayButton = mMainActivity.findViewById(R.id.AbYourHolidayButton);
}
public void testButtonActions() {
TouchUtils.clickView(this, mSearchButton);
...
}
}
MockedOTBService.java
public class MockedOTBService {
private Context context;
public MockedOTBService(Context context) { this.context = context; }
public OTBServiceWrapper getService() {
RestAdapter restAdapter;
restAdapter = new RestAdapter.Builder()
.setClient(new LocalJsonClient(context))
.setEndpoint(Constants.API_TEST_URL)
.build();
return restAdapter.create(OTBServiceWrapper.class);
}
}
LocalJsonClient.java
#SuppressLint("DefaultLocale")
public class LocalJsonClient implements Client { ... }
build.gradle
dependencies {
androidTestCompile 'com.google.dexmaker:dexmaker:1.0'
androidTestCompile 'com.google.dexmaker:dexmaker-mockito:1.0'
}
Remove the need for mocking your request by allowing the Activity to set the service.
In your MainActivity create a class variable and a class setter for the service. It needs to be a at the class scope to prevent the OnCreate method being called before you have set the service to what you want it to be. Also create an instance getter which sets the service if you have not already.
In your test before you call getActivity() set the service to be your mock service. (Maybe think about moving this out to a support object).
MainActivity.java
public class MainActivity extends Activity {
private static OTBServiceWrapper serviceWrapper;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
getServiceWrapper.createSearch(...)
}
public OTBServiceWrapper getServiceWrapper() {
if (serviceWrapper == null) {
MainActivity.setServiceWrapper(new OTBService().getService());
}
return serviceWrapper;
}
public static void setServiceWrapper(OTBServiceWrapper serviceWrapper) {
MainActivity.serviceWrapper = serviceWrapper;
}
}
MainActivityTest.java
public class MainActivityTest extends ActivityInstrumentationTestCase2<MainActivity> {
private MainActivity mMainActivity;
public MainActivityTest() { super(MainActivity.class); }
#Override
protected void setUp() throws Exception {
super.setUp();
setActivityInitialTouchMode(true);
MainActivity.setServiceWrapper(
new MockedOTBService(getInstrumentation().getContext()).getService()
);
mMainActivity = getActivity();
}
}