i'm pretty new in programming android Apps actually this is my first, so sorry for my (maybe simple) question.
All i want to do is to post some values by httprequest on a website (this works fine so far) and get a message back, if it was success full (there's the problem). So my class MainActivity looks like this:
public class MainActivity extends Activity implements OnClickListener {
private Button sendButton;
private Button graficButton;
[...]
#Override
public void onClick(View v) {
[...]
new ExecutePost().execute(zusammen);
return;
}
public void checkResponse(Integer responseCode) {
if(responseCode == 200){
new AlertDialog.Builder(this)
.setMessage(R.string.response_ok)
.setNeutralButton(R.string.error_ok, null)
.show();
return;
}else{
new AlertDialog.Builder(this)
.setMessage(R.string.response_false)
.setNeutralButton(R.string.error_ok, null)
.show();
return;
}
}
In class ExecutePost I try to call the function checkResponse from the MainActivity class but there i get the Compiler Error:
No enclosing instance of the type MainActivity is accessible in scope
This is how i coded the class ExecutePost:
public class ExecutePost extends AsyncTask<String, Void, HttpResponse>{
private IOException exception;
private ClientProtocolException clientException;
#Override
public HttpResponse doInBackground(String... alles) {
works fine
}
#Override
protected void onPostExecute(HttpResponse resRes) {
Integer code = resRes.getStatusLine().getStatusCode();
super.onPostExecute(resRes);
MainActivity.this.checkResponse(code);
}
}
I get the error message in the last line for *MainActivity.this.*checkResponse(code); I guess it has something to do with instances / static non-statics methods and so one...
Thanks in advance.
Timo
Related
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
}
});
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);
After using LeakCanary I found that there were many leaks in my app, most of them due to Volley's anonymous callback listeners. So I wrote a Util (below) class which uses static callbacks and WeakReference to keep reference to Context and an anonymous callback. But when I open the app for the first time, i.e. a cold start, the context is GCed soon after the request is made but during a warm start all works fine. Also this happens only for the first activity in the app.
Any alternative way of handling memory leaks with volley which works properly are also welcome.
public abstract class VUtil {
public static final String TAG = VUtil.class.getSimpleName();
public interface JsonCallback {
void onSuccess(JSONObject response);
}
public interface StringCallback {
void onSuccess(String response);
}
public interface ErrorCallback {
void onError(VolleyError error);
}
public static class JsonResponseListener implements Response.Listener<JSONObject> {
private final WeakReference<Context> mContextWeakReference;
private final WeakReference<JsonCallback> mCallbackWeakReference;
public JsonResponseListener(Context context, JsonCallback callback) {
mContextWeakReference = new WeakReference<>(context);
mCallbackWeakReference = new WeakReference<>(callback);
}
#Override
public void onResponse(JSONObject jsonObject) {
Context context = mContextWeakReference.get();
JsonCallback callback = mCallbackWeakReference.get();
if (context != null && callback != null) {
callback.onSuccess(jsonObject);
} else {
Log.d(TAG, "Context was GCed");
}
}
}
public static class StringResponseListener implements Response.Listener<String> {
private final WeakReference<Context> mContextWeakReference;
private final WeakReference<StringCallback> mCallbackWeakReference;
public StringResponseListener(Context context, StringCallback callback) {
mContextWeakReference = new WeakReference<>(context);
mCallbackWeakReference = new WeakReference<>(callback);
}
#Override
public void onResponse(String response) {
Context context = mContextWeakReference.get();
StringCallback callback = mCallbackWeakReference.get();
if (context != null && callback != null) {
callback.onSuccess(response);
} else {
Log.d(TAG, "Context was GCed");
}
}
}
public static class ErrorListener implements Response.ErrorListener {
private final WeakReference<Context> mContextWeakReference;
private final WeakReference<ErrorCallback> mCallbackWeakReference;
public ErrorListener(Context context, ErrorCallback callback) {
mContextWeakReference = new WeakReference<>(context);
mCallbackWeakReference = new WeakReference<>(callback);
}
#Override
public void onErrorResponse(VolleyError error) {
Context context = mContextWeakReference.get();
ErrorCallback callback = mCallbackWeakReference.get();
if (context != null && callback != null) {
callback.onError(error);
} else {
Log.d(TAG, "Context was GCed");
}
}
}
}
GC depends on many many things that are happening. One possible cause for your case is that when you do your first request after a 'cold boot' you app must init various custom objects, fragments, activities, views caches etc. and thus needs memory before increases the heap and thus do a GC.
The solution I propose however is to change your architecture.
1) it seems that u keep ref to context but it is never used. just drop it
2) you have Volley callbacks which delegates to your custom callbacks which you need to pass anyway, why don't you simply use 1 set of callbacks which you pass to the respective requests.
3) you WeekRef your custom callbacks but u cannot do without them. Week Referencing is not the ultimate solution to memory leaks. you have to find out why the ref is still there when you don't need it.
so if you leak issue is in JsonCallback, StringCallback and ErrorCallback implementations just try to figure this out instead of making the chain longer and cutting it at the end.
Thanks to djodjo's answer which helped me to reach a solution
Always use addToRequestQueue(request, TAG). Here TAG bit is what we'll use to cancel requests when their Activity/Fragment/View or anything is GCed
What i did is create a base activity and add all this request cancellation code in that activity. Here's what it looks like
public abstract class BaseActivity extends AppCompatActivity {
public final String tag;
public BaseActivity() {
super();
tag = getClass().getSimpleName();
}
#Override
protected void onDestroy() {
App.getInstance().cancelRequests(tag);
super.onDestroy();
}
protected <T> void addToRequestQueue(Request<T> request) {
App.getInstance().addToRequestQueue(request, tag);
}
}
cancelRequests is just simple code
getRequestQueue().cancelAll(tag);
Extend your activities from this BaseActivity and use addToRequestQueue to make requests, which will get cancelled automatically when your activity is destroyed. Do similar thing for fragment / dialog / whatever else.
If you make requests from anywhere else which doesn't follow a life-cycle, make sure that it's not binding to any Context and you'll be fine.
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
}
}
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
}
}