In my app I'm getting some TEXT from a Website by ion library and I'm using a progressBar to show the progress of downloading that data.
But my main issue is that in onComplete I implemented some methods that work with the TEXT I've got from the website these are some cyclic methdods that use lot's of for and other stuff and actually my progressBar at the beginning works properly, but when it's complete downloading the data the progressBar just sticks until all the methods are complete in onComplete().
I would that the progressBar runs anyway and doesn't get stuck without removing methods from onComplete() is it possible?
Here is my function where I use ion library that I invoke in the onClick() event:
private void getHTML(){
progressDialog = new SpotsDialog(MainActivity.this, R.style.Custom);
progressDialog.show();
Ion.with(getApplicationContext())
.load("IP")
.asString()
.setCallback(new FutureCallback<String>() {
#SuppressLint("SetTextI18n")
#Override
public void onCompleted(Exception e, String result) {
htmlresultart = result;
htmlresultart = htmlresultart.replace("</td>", "\n");
getTable();
getHeader();
getBody();
progressDialog.cancel();
}
});
}
If the methods called in the onCompleted() callback take too much to execute then they need to be run on a background thread. In this situation it doesn't make sense to use a callback with Ion, instead you should synchronously fetch the data and after this do all the other tasks, all on a single background thread, something like below:
private void getHTML(){
progressDialog = new SpotsDialog(MainActivity.this, R.style.Custom);
progressDialog.show();
// start a background thread
ExecutorService executor = Executors.newSingleThreadExecutor();
executor.execute(new Runnable() {
#Override
public void run() {
String htmlresultart = null;
try {
String htmlresultart = Ion.with(getApplicationContext())
.load("IP")
.asString()
.get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
// if htmlresultart is null at this point, an exception occured and the string couldn't be fetched so you most likely should abort the following processing.
if (htmlresultart != null) {
htmlresultart = htmlresultart.replace("</td>", "\n");
getTable();
getHeader();
getBody();
progressDialog.cancel();
}
}
});
}
Related
I'm beginner in android and trying to show toast in the async task, for that purpose I wrote this code:
public class GetReading {
public GetReading() {
}
public List<ReadingModel> Get(String TokenKey, Context adapter) throws ExecutionException, InterruptedException {
GetReadingTask params = new GetReadingTask(TokenKey, adapter);
List List_result = (List)(new GetReading.AsyncRead()).execute(new GetReadingTask[]{params}).get();
return List_result;
}
private class AsyncRead extends AsyncTask<GetReadingTask, Void, List<ReadingModel>> {
ir.behineh.wepapiinterface.GETREADINGINTERFACE.ReadingModel.List x;
private AsyncRead() {
}
protected List<ReadingModel> doInBackground(GetReadingTask... getReadingTasks) {
final Context pos = getReadingTasks[0].adapter;
Handler handler = new Handler(pos.getMainLooper());
handler.post(new Runnable() {
public void run() {
Toast.makeText(pos, "Created a server socket", 1).show();
}
});
ir.behineh.wepapiinterface.GETREADINGINTERFACE.GetReading taskService = (ir.behineh.wepapiinterface.GETREADINGINTERFACE.GetReading)ServiceGenerator.createService(ir.behineh.wepapiinterface.GETREADINGINTERFACE.GetReading.class);
Call tasks = taskService.getReadings("application/x-www-form-urlencoded", "application/json", "bearer " + getReadingTasks[0].TokenKey);
try {
this.x = (ir.behineh.wepapiinterface.GETREADINGINTERFACE.ReadingModel.List)tasks.execute().body();
} catch (IOException var7) {
var7.printStackTrace();
}
return this.x;
}
}
}
and when i try to call that async task with this code:
GetReading reading=new GetReading();
List<ReadingModel> result= reading.Get("VQ",LineActivity.this);
after finishing doinbackground get the toast, but i want to show toast first to user, what happen? how can i solve that problem? thanks all.
Toasts as well as anything that has to do with the UI cannot be fired from any thread that runs in the background.
Move your code for displaying the toast to either onProgressUpdate or on onPostExecute.
All your troubles arise because you use the .get() in
execute(new GetReadingTask[]{params}).get();
Never use .get() as it kills the asynchonity of your task.
Instead: do the things you want to do with the result in onPostExecute().
I download a high amount of data from API and want to make it efficient so I get first 100 record in one asyncTask and then in another asyncTask get another several thousands(in 500 hundred portions) The loadListAsynchronously(); looks identicall as loadData function without content,progress,loadContent(); function but this functions are not the problem - without loadListAsynchronously(); app runs smoothly after frezee when download first data. I tried add transaction but that does not help me.
private void loadData() {
DottedProgressBar progressBar = (DottedProgressBar) findViewById(R.id.loadIngDots);
progressBar.startProgress();
content = (LinearLayout)findViewById(R.id.activity_main) ;
progress = (RelativeLayout) findViewById(R.id.progressPage) ;
AsyncTask<String, Void, String> read =new AsyncTask<String, Void, String>() {
SharedPreferences keyValues;
#Override
protected void onPreExecute() {
content.setVisibility(View.GONE);
keyValues = getSharedPreferences(Settings.MODEL_LAST_CALL, Context.MODE_PRIVATE);
DisplayMetrics displaymetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
height = displaymetrics.heightPixels;
width = displaymetrics.widthPixels;
super.onPreExecute();
}
#Override
protected String doInBackground(String... params) {
modelList = new ArrayList<>();
Map<String,String> options= new HashMap<>();
options.put("limit",String.valueOf(AMOUNT_OF_LOADED_modelS));
ApiHelper.getModelWithParams(new Callback<ModelApiEnvelope>() {
#Override
public void onResponse(Call<ModelApiEnvelope> call, Response<ModelApiEnvelope> response) {
Log.i(TAG,"First call model Get response");
final ModelApiEnvelope envelope = response.body();
if(envelope==null)
Toast.makeText(MainActivity.this,getString(R.string.server_down_explanation),Toast.LENGTH_SHORT).show();
else{
try {
final Dao<Model,Integer> modelDAO = getHelper().getmodelDAO();
final Dao<Submodel,Integer> submodelDAO=getHelper().getsubmodelDAO();
TransactionManager.callInTransaction(getHelper().getConnectionSource(),
new Callable<Void>() {
public Void call() throws Exception {
modelList=envelope.getData();
Log.i(TAG,"LoadData loop Start");
for( final model m: modelList){
m.setLogo(m.getLogo()+"?width="+width/2+"&height="+height);
m.setLanguage(m.getLanguage().substring(0,2));
if(m.getLanguage().equals("uk"))
m.setLanguage("ua");
if(m.getsubmodels().size()!=0){
for(final submodel e: m.getsubmodels()){
e.setLanguage(m.getLanguage());
submodelDAO.createOrUpdate(e);
}
}
try {
modelDAO.createOrUpdate(m);
}catch (SQLException e) {e.printStackTrace();}
}
return null;}
});
if(envelope.getData().isEmpty()){
SharedPreferences.Editor editor = sharedPreferences.edit();
long time = System.currentTimeMillis();
editor.putString(Settings.model_LAST_CALL , Long.toString(time));
editor.apply();
}
else
loadListAsynchronously();
} catch (SQLException e) {
Log.i(TAG," message "+e.getMessage()) ; e.printStackTrace();
}}
loadContent();
content.setVisibility(View.VISIBLE);
progress.setVisibility(View.GONE);
}
#Override
public void onFailure(Call<modelApiEnvelope> call, Throwable t) {
Log.i(TAG,"ERROR"+ t.getMessage());
Toast.makeText(MainActivity.this,getString(R.string.server_down_explanation),Toast.LENGTH_LONG).show();
loadContent();
}
},MainActivity.this,options, keyValues.getString(lang,"0"));
return null;
}
#Override
protected void onProgressUpdate(Void... values) {
super.onProgressUpdate(values);
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
}
};
read.execute();
}
UPDATE: Method Trace added
UPDATE 2: Removing the transaction solve my problem. It seems that the making transaction for thousands saveings into database freeze Ui.
Callback in Retrofit1 and AsyncTask are not compatible. You have to modify your API interface from something like this :
public interface Api {
void getModelWithParams(Callback<Something> callback);
}
To this :
public interface Api {
Something getModelWithParams();
}
Then Retrofit will not provide async execution support and you can execute that row method inside AsyncTask.doInBackground method.
Other option is to stay with that interface definition and just call Retrofit method directly (without AsyncTask wrapping). The question is if your further logic is not heavy, because onResponse will be executed on UI Thread which cause your freezes and in general is root cause of your problem.
I load my articles from my wordpress webpage. And want to display them in my app.
In order to be allowed to wait for a internet response I had to create a Thread.
Using this method:
private void loadArticles(final String url) {
Thread thread = new Thread(new Runnable(){
#Override
public void run() {
try {
//Get my data and run createArticles();
} catch (Exception e) {
e.printStackTrace();
}
}
});
thread.start();
}
Then in the createArticles function I try to use my function addViewToParent(...) and I get an error that says:
Only the original thread that created a view hierarchy can touch its
views.
How can i work around this problem?
EDIT: I use these networking functions if it matters...
//Connect to the url
URL pageURL = new URL(url);
HttpURLConnection connection = (HttpURLConnection) pageURL.openConnection();
BufferedReader in = new BufferedReader(
new InputStreamReader(connection.getInputStream())
);
If you want to modify your Views, e.g. show your article, you have to run the code on the UI/main thread. To achieve this, you could call run runOnUiThread() in your Activity:
private void loadArticles(final String url) {
Thread thread = new Thread(new Runnable(){
#Override
public void run() {
try {
//Get my data ...
runOnUiThread(new Runnable() {
public void run() {
// modify Views here
createArticles();
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
});
thread.start();
}
You need to use function runOnUiThread. This is function for user interface thread.
private void loadArticles(final String url) {
//Get my data ...
runOnUiThread(new Runnable() {
public void run() {
// modify Views here
createArticles();
}
});
});
Just use a Handler instead, so you'll have access to the UI Thread:
new Handler().post(new Runnable(){
#Override
public void run() {
try {
//Get my data and run createArticles();
} catch (Exception e) {
e.printStackTrace();
}
}
});
I am making an android app which requires it to fetch some information from a remote server and therefore i have to make a http request in a async task.Now the problem is that that the response sometimes take more than 2 secs and when it does it give http timeout exception but most of the time it works just fine .So i want to implement the functionality that when i recieve a http timeout exception i want to retry the request again(try the doinBackground again,because network call can only be made in thread other than the main thread) because chances are that it will be successful and all the things that need to be fetched from the remote server will occur in CallRemoteServer() method
Now in my program i have implemented something like this
new AsyncTask<Void, Void, Void>() {
private boolean httpResponseOK = true;
#Override
protected Void doInBackground(Void... params) {
try {
CallRemoteServer();
}
} catch (Exception e) {
httpResponseOK = false;
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(Void result) {
if (httpResponseOK == false) {
//Show an alert dialog stating that unable to coonect
}
else
{
//update UI with the information fetched
}
});
Can someone advice me how can i implement something which i have mentioned above ,i mean that if i get some other exception other than timeout than show an alert dialog otherwise retry atleast five time more CallRemoteServer method before showing the dialog that unable to connect.
I am not able to think of any good way to implement this logic.
Thanks in advance
You're probably getting a ConnectTimeoutException (or check in the logs what is the IOException you're getting). I would first try to extend the timeout. Some similar answers for this can be found here or here.
However, an auto-reconnect mechanism is a must to have. I would implement it using recursive code:
final int maxAttempts = 5;
protected MyServerData callRemoteServer(int attempt) throws IOException {
try {
// do the IO stuff and in case of success return some data
} catch (ConnectTimeoutException ex) {
if(attempt == maxAttempts) {
return callRemoteServer(attempt + 1);
} else {
throw ex;
}
}
}
Your doInBackground method should look like:
#Override
protected Void doInBackground(Void... params) {
try {
callRemoteServer(0);
}
catch (Exception e) {
e.printStackTrace();
}
return null;
}
In this way if the connection timeouts it will attempt to retry for 5 max times (you can set the max attempts to anything you like). Just make sure to return some data from this IO operation as that is the most valuable asset from that method anyway ...
For this reason I would change it to following:
private class MyAsynckTask extends AsyncTask<Void, Void, MyServerData> {
#Override
protected MyServerData doInBackground(Void... params) {
try {
return callRemoteServer(0);
}
catch (Exception e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(MyServerData result) {
if(result != null) {
// display data on UI
}
}
}
In my app I performing loading data from web and then displaying it to user. Before loading data app shows progress dialog. I have problem if user locks phone in the middle of loading operation, or server is overloaded and can't respond in time my application freezes, because it doesn't dismiss progress dialog, or in some cases it crashes because lack on needed data.
If some error happened while loading data I want show some dialog to user to let him know about error and ask him should application repeat last request. I tried to use AlertDialog for it, but I haven't succeed.
Here is code of one activity (There is no progress dialog here, but it demonstrates how I loading data):
#EActivity(R.layout.layout_splash)
#RoboGuice
public class SplashScreenActivity extends Activity {
#Inject
private AvtopoiskParserImpl parser;
#Bean
BrandsAndRegionsHolder brandsAndRegionsHolder;
#ViewById(R.id.splash_progress)
ProgressBar progressBar;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
loadData();
}
#Background
protected void loadData() {
publishProgress(10);
LinkedHashMap<String, Integer> brands = null;
try {
brands = parser.getBrands();
} catch (IOException e) {
Log.e(e.getMessage());
}
publishProgress(50);
LinkedHashMap<String, Integer> regions = null;
try {
regions = parser.getRegions();
} catch (IOException e) {
Log.e(e.getMessage());
}
publishProgress(70);
populateData(brands, regions);
}
#UiThread
protected void populateData(LinkedHashMap<String, Integer> brands, LinkedHashMap<String, Integer> regions) {
Intent intent = new Intent(SplashScreenActivity.this, SearchActivity_.class);
brandsAndRegionsHolder.brandsMap = brands;
brandsAndRegionsHolder.regionsMap = regions;
publishProgress(100);
startActivity(intent);
finish();
}
#UiThread
void publishProgress(int progress) {
progressBar.setProgress(progress);
}
}
parser.getBrands() and parser.getRegions() are loading data from the web.
I want to do something like this:
boolean repeatRequest = true;
while (repeatRequest) {
try {
brands = parser.getBrands();
repeatRequest = false;
} catch (IOException e) {
Log.e(e.getMessage());
repeatRequest = showErrorDialog();
}
}
But I didn't manage to do so because this code executes in background thread, but dialog should be shown in UI thread.
I believe that it should be standard approach of doing so, but didn't manage to find it.
Any ides how can I implement this?
The best way is to use AsyncTask.
private class LoadDataTask extends AsyncTask<Void, Integer, Object> {
private ProgressDialog mProgress;
protected Object doInBackground(Void... params) {
// This method runs in background
Object result = null;
try {
result = parser.parse();
} catch (Exception e) {
result = e.getMessage();
}
return result;
}
protected void onProgressUpdate(Integer... progress) {
// This method runs in UI thread
mProgress.setProgress(progress[0]);
}
protected void onPreExecute() {
// This method runs in UI thread
mProgress = new ProgressDialog(context);
mProgress.show();
}
protected void onPostExecute(Object result) {
// This method runs in UI thread
mProgress.dismiss();
if (result instance of String) {
// Here you can launch AlertDialog with error message and proposal to retry
showErrorDialog((String) result);
} else {
populateData(result);
}
}
}