First of all I must say I'am new at Android but not at Java.
I did HttpRequest With AsyncTask.
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Thread th = new Thread(new Runnable() {
#Override
public void run() {
new RequestTask().execute("http://www.url.com/ajaxrequest/?kategori=27");
}
});
th.start();
}
Created Another Class ( Name : RequesTask )
class RequestTask extends AsyncTask<String, String, String>{
private void RequestTask(String URL){
HttpClient httpclient = new DefaultHttpClient();
HttpResponse response;
// Some Codes Here...
return responseString;
}
#Override
protected String doInBackground(String... uri) {
HttpClient httpclient = new DefaultHttpClient();
HttpResponse response;
String responseString = null;
// Some Codes Here...
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
// My Result is 'result'
}
I want to send and write this string value to TextView In MainActivty. How can i send 'result' ?
Thanks in advance..
Don't open a new thread to run the async task from this thread. It won't work (will fail on internal handler). The async task by himself open for you a new thread.
This is the right code:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView) findViewById(R.id.your_text_view);
new RequestTask().execute("http://www.url.com/ajaxrequest/?kategori=27");
}
And in your RequestTask
#Override
protected void onPostExecute(String result) {
textView.setText(result);
}
Edit: To your question, how to access TextView from AsyncTask
You can do it in many ways. These are part of them:
Define AyncTask as an inner class inside your Activity. You can access members of Activity within AsyncTask. This option is very coupled, means async task which apparently the logic of your app is part of your ui. Like this:
class YouActivity extends Activity {
TextView textView;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView) findViewById(R.id.your_text_view);
new RequestTask().execute("http://www.url.com/ajaxrequest/?kategori=27");
}
class RequestTask extends AsyncTask<String, String, String> {
...
#Override
protected void onPostExecute(String result) {
textView.setText(result);
}
}
}
Deliver the TextView to AsyncTask by constructor or setter method. This option is less coupled, since this AsyncTask can be used by many consumers who want to update their TextView, but the is still coupling by holding reference from AsyncTask to your views.
Your AsyncTask:
class RequestTask extends AsyncTask<String, String, String> {
TextView textView = null;
public void setTextView(TextView textView) {
this.textView = textView;
}
...
#Override
protected void onPostExecute(String result) {
if (textView != null) {
textView.setText(result);
}
}
}
And your activity:
class YouActivity extends Activity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView textView = (TextView) findViewById(R.id.your_text_view);
RequestTask requestTask = new RequestTask();
requestTask.setTextView(textView);
requestTask.execute("http://www.url.com/ajaxrequest/?kategori=27");
}
}
To make your program more loosely coupled and to make better separation of controller from your views, use Handlers:
class RequestTask extends AsyncTask<String, String, String> {
Handler handler = null;
public void setHandler(Handler handler) {
this.handler = handler;
}
...
#Override
protected void onPostExecute(String result) {
if (handler != null) {
Message message = new Message();
message.obj = result;
handler.sendMessage(message);
}
}
}
And your activity:
class YouActivity extends Activity {
TextView textView;
Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
String value = (String) msg.obj;
textView.setText(value);
}
};
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView) findViewById(R.id.your_text_view);
RequestTask requestTask = new RequestTask();
requestTask.setHandler(handler);
requestTask.execute("http://www.url.com/ajaxrequest/?kategori=27");
}
}
Handlers cave tons of options. You can 'send message' from any thread and you can decouple your app very good with this tool.
You can either pass the TextView to RequestTask's constructor or make it a global member. And in your onPostExecute method:
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
yourTextView.setText(result);
}
That's it :)
Edit: Whoops. As sromku correctly pointed out, AsyncTask already performs the doInBackground() method in a separate thread (in background) so you should not be wrapping it in another thread. So, remove that Thread-ception.
best solution
Instead of using so many classes for different types of asynctask , I suggest you use this library
you can have a look at here
http://loopj.com/android-async-http/
your code will become very very less , instead of declaring so may asynctask seperately writing bulk of code , you can just use 4 lines of code
AsyncHttpClient client = new AsyncHttpClient();
client.get("http://www.google.com", new AsyncHttpResponseHandler() {
#Override
public void onSuccess(String response) {
System.out.println(response);
}
});
I is very efficient in geting the response very quickly.
I hope this will help you out. :)
Related
I'm trying to build a demo app with 2 buttons, one downloads a video and the other downloads a PDF. I want to take care of the downloading in the background thread through AsyncTask. So far I have starter code with implemented methods. I haven't added the code for what I want to download yet because I want to figure out the logic behind separate downloads so for now, I have Log messages.
This is the code:
public class MainActivity extends AppCompatActivity {
Button downloadVideo, downloadPDF;
DownloadingClass downloadingClass = new DownloadingClass();
private static final String TAG = "omar.asynctaskdemo;";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
downloadVideo = findViewById(R.id.download_video);
downloadPDF = findViewById(R.id.download_pdf);
downloadVideo.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {}
});
downloadPDF.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {}
});
}
private class DownloadingClass extends AsyncTask<Void, Void, Void>{
#Override
protected void onPreExecute() {
super.onPreExecute();
Log.d(TAG, "doInBackground: Before");
}
#Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
Log.d(TAG, "doInBackground: After");
}
#Override
protected void onProgressUpdate(Void... values) {
super.onProgressUpdate(values);
Log.d(TAG, "doInBackground: Progress");
}
#Override
protected Void doInBackground(Void... voids) {
Log.d(TAG, "doInBackground: Content to download");
return null;
}
}
}
I'd appreciate a concise explanation on how to go about it.
Don't do this
DownloadingClass downloadingClass = new DownloadingClass();
Always create just before you kick of the task:
new DownloadingClass().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
This is because you can't reuse the AsyncTask. It has status and will not run again once status is "Finished".
if you have same input/output type in both download methods u can use same DownloadingClass by Declaring an object for each methods , like :
DownloadingClass downloadPDF = new DownloadingClass();
DownloadingClass downloadVideo = new DownloadingClass();
then just call downloadPDF.execute();/downloadVideo.execute();
or u can manage them by ExecutorService :
How to wait for all threads to finish, using ExecutorService?
So i got a project with the following activities : MainActivity/GetJson/ TimerActivity.
GetJson activity :
public class GetJson extends AppCompatActivity {
String JSON_STRING;
String json;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void getJSON(View view){
new BackgroundTask().execute();
}
public class BackgroundTask extends AsyncTask<Void,Void,String> {
String json_url;
#Override
protected void onPreExecute() {
json_url="http://10.10.103.36/projet/php/fichier.php";
}
#Override
protected String doInBackground(Void... params) {
try {
URL url=new URL(json_url);
HttpURLConnection httpURLConnection=(HttpURLConnection)url.openConnection();
InputStream inputStream=httpURLConnection.getInputStream();
BufferedReader bufferedReader=new BufferedReader(new InputStreamReader(inputStream));
StringBuilder stringBuilder=new StringBuilder();
while ((JSON_STRING= bufferedReader.readLine())!=null){
stringBuilder.append(JSON_STRING+"\n");
}
bufferedReader.close();
inputStream.close();;
httpURLConnection.disconnect();
return stringBuilder.toString().trim();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onProgressUpdate(Void... values) {
super.onProgressUpdate(values);
}
#Override
protected void onPostExecute(String result) {
json=result;
}
}
}
Timer Activity
public class TimerActivity extends Activity {
private TextView test;
String msg = "Hey";
private Handler mHandler = new Handler();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
test = (TextView) findViewById(R.id.compteur);
Timer timer = new Timer();
TimerTask tt = new TimerTask()
{
#Override
public void run()
{
test.setText(msg);
}
};
timer.scheduleAtFixedRate(tt,5000,1000); // Delay 5 seconds on the first run
// then run every second
test.setText(msg);
setContentView(R.layout.activity_main);
}
}
In my xml main activity i got 2 textview :
- compteur : to display a text from my timeractivity
- textViewJson : to display my json
I think my methods to get json( from GetJson) and display text(from TimerActivity) are correct. But the problem is that i can't setText from others activities to my main activity.
I don't have any compilation problem bu my textView aren't getting updated.
I tried both in GetJson and TimerActivity to just do :
TextView test;
test = (TextView) findViewById(R.id.compteur);
test.setText(msg);
In order to check if i can change the textview text without even using the returned values and nothing happens.
Any ideas ?
Have a good day !
Once you have the information you want to show in your TVs you should save it somewhere and load it when your Activity is created. You can't change the state of Views in a destroyed Activity. Use Intents (putExtra();) to pass data between your Activies or use SharedPreferences
I am well aware that blocking the UI is not a good idea in general but there are some scenarios where my app simply cannot do any other work until some long running operations (e.g. loading data from a server) are complete.
Assume the user clicks the "Load Data" button. To indicate that no UI interaction is possible until the data is loaded I would like to grey out the screen and show some kind of activity indicator. This is no problem at all, I simply overlay the screen with a new Fragment.
The question is: How can I present this overlay fragment?
public void onLoadDataClick() {
// grey out the screen by simple showing a new Fragment
showActivityIndicatorOverlay();
// Start the long running opeartion
doVeryMuchWork();
dismissActivityIndicatorOverlay();
}
public void showActivityIndicatorOverlay() {
FragmentTransaction ft = context.getSupportFragmentManager().beginTransaction();
ActivityIndicatorOverlayFragment overlayFragment = ActivityIndicatorOverlayFragment.newInstance("Loading Data");
overlayFragment.show(ft, "activityIndicator");
}
This does NOT work. The overlay does not show up. If I remove dismissActivityIndicatorOverlay() the overlay shows up after the long running operation completed. This is not too suprising: I assume that the showing the new fragment is handeled at the end of the current run-loop or at the start of the next loop. Of course the long running operation has to complete before the run-loop ends and thus the overlay is displayed too late...
The obvious solution is of course to run the operation in a background thread using an AsyncTask:
public void onLoadDataClick() {
LoadDataTask loadTask = new LoadDataTask();
loadTask.execute();
}
private class LoadDataTask extends AsyncTask<Void, Void, Void> {
#Override
protected void onPreExecute() {
showActivityIndicatorOverlay();
}
#Override
protected Void doInBackground(Void... params) {
doVeryMuchWork();
}
#Override
protected void onPostExecute() {
dismissActivityIndicatorOverlay();
}
}
I was surprised, that this solution doesn't work either. It behaves exactly like the first approach: The overlay does not appear. When onPostExecute() is removed the overlay appears after the operation is complete. the Why is that?
What is the correct solution to present such an activity indicator?
I'd suggest the use of a ProgessDialog.
Declare a ProgressDialog as an instance variable. Something like : ProgressDialog pDialog;
then inside onCreate() :
pDialog = new ProgressDialog(this);
//The next two methods will ensure that the user is unable to
//cancel the Progress Dialog unless you explicitly
//do so by calling `pDialog.dismiss();`
pDialog.setCancelable(false);
pDialog.setCanceledOnTouchOutside(false);
Modify AsyncTask somewhat like this :
private class LoadDataTask extends AsyncTask<Void, Void, Void> {
#Override
protected void onPreExecute() {
pDialog.setMessage("Loading Data.. Please Wait.");
pDialog.show();
}
#Override
protected Void doInBackground(Void... params) {
doVeryMuchWork();
}
#Override
protected void onPostExecute() {
pDialog.dismiss();
}
}
A ProgressDialog is very much the canonical solution for these cases...
private class LoadDataTask extends AsyncTask<Void, Void, Void> {
private ProgressDialog mProgress;
#Override
protected void onPreExecute() {
mProgress = new ProgressDialog(context);
mProgress.setTitle("So much to do");
mProgress.setMessage("Doing very much work");
mProgress.setIndeterminate(true);
mProgress.setCancelable(false);
mProgress.show();
}
#Override
protected Void doInBackground(Void... params) {
doVeryMuchWork();
}
#Override
protected void onPostExecute() {
mProgress.dismiss();
}
}
As for your attempted solutions, the first one does not work for the very reasons you state. The second should, though.
You can do something like this, if you're not doing heavy stuff precisely on setContentView(R.layout.main)
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.splash);
handler = new Handler();
new AsyncTask<Void, Void, Void>() {
#Override
protected Void doInBackground(Void... params) {
//Do some heavy stuff
return null;
}
#Override
public void onPostExecute(Void result){
handler.post(new Runnable(){
#Override
public void run(){
setContentView(R.layout.main);
}
});
}
}.execute();
}
OR you can use progress dialog
private class LongTask extends AsyncTask<Void, Void, Void> {
private ProgressDialog pd;
Context context;
public LongTask(Context c)
{
this.context = c;
}
#Override
protected void onPreExecute() {
pd = new ProgressDialog(context);
pd.setTitle("Please wait...!");
pd.setMessage("Loding the information");
pd.setIndeterminate(true);
pd.setCancelable(false);
pd.show();
}
#Override
protected Void doInBackground(Void... params) {
// do your heavy tasks here
}
#Override
protected void onPostExecute() {
if (pd.isShowing())
pd.dismiss();
}
}
Call AsyncTask like this
new LongTask(your_activity.this).execute();
Hey i have a problem with my android application.I'm trying to download text from given url to Editable box but when i'm running application and hit the button it suddenly stops working.I am using asynctask to download, also eclipse tells me that class DownloadTask is not used locally
public void sendMessage(View view) throws IOException {
new DownloadTask().execute();
}
private class DownloadTask extends AsyncTask{
protected Object doInBackground(Object... params) {
// TODO Auto-generated method stub
try {
EditText tf = (EditText) findViewById(R.id.editText1);
String kupa = tf.getText().toString();
Document doc;
doc = Jsoup.connect(kupa).get();
String title = doc.text();
TextView tv = (TextView) findViewById(R.id.textView1);
tv.setText(title);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
protected void onPostExecute(String result) {
TextView tv = (TextView) findViewById(R.id.textView1);
tv.setText(result);
}
}
Also i added two lines of code to my onCreate method
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
If this helps min api is 10,target is 16
cheers guys
you can't run UI code in doInBackground.
you try run bellow code on doInBackground, delete that or move it to onPostExecute
tv.setText(title);
and you don't need following line:
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
if you need value in AyncTask you can pass data, if you need tf.getText().toString() you can change your code with following code:
new DownloadTask().execute(tf.getText().toString());
and change AsyncTask class with:
public static class DownloadTask extends AsyncTask<String, Void, Void>
{
#Override
protected Void doInBackground(String... params)
// use params array, in this example you can get tf.getText().toString() with params[0]
String kupa = params[0] // if you pass more data you can increase index
}
for more info see documentation of AsyncTask
:( Now, we can talk about Thread.
hmm...
You are using AsyncTask to download text from url.
It mean you are using another thread to do.
And another thread could not change UI. You must change UI in main thread. But if you want to change UI in other thread you can use runOnUIThread method.
I can give you a solution for your issue.
A child of AsyncTask
public class AsyncLoadData extends AsyncTask<String, Void, String> {
private Context mContext;
private ILoadDataListener mListener;
public AsyncLoadData(Context context, ILoadDataListener listener) {
this.mContext = context;
this.mListener = listener;
}
#Override
protected String doInBackground(String... params) {
String url = params[0];
String result = doGetStringFromUrl(url); // You can write your own method;
return result;
}
#Override
protected void onPostExecute(String result) {
mListener.complete(result);
}
#Override
protected void onPreExecute() {
mListener.loading();
}
public interface ILoadDataListener {
void loading();
void complete(String result);
}
}
In your activity
public class MainActivity extends Activity implements AsyncLoadData.ILoadDataListener {
/// Something...
public void getData() {
new AsyncLoadData(this, this).execute(url);
// or new AsyncLoadData(getBaseContext(), this).execute(url);
}
#Override
public void loading() {
// Do something here when you start download and downloading text
}
#Override
public void complete(String result) {
TextView mTextView = (TextView) findViewById(R.id.your_text_view);
mTextView.setText(result);
// EditText is the same.
}
}
I am trying to make a simple task in background and show a progress bar while it is being done.
This is the code for the main (and the only) Activity:
public class Login extends Activity {
public static ProgressDialog progressDialog;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
(...)
this.getWindow().requestFeature(Window.FEATURE_PROGRESS);
this.getWindow().setFeatureInt(Window.FEATURE_PROGRESS, Window.PROGRESS_VISIBILITY_ON);
progressDialog = new ProgressDialog(activity);
progressDialog.setMessage("Sending data...");
progressDialog.setCancelable(false);
(...)
// In some onClick Eevent..
JSONObject result = new Urltasks().execute(...).get();
(...)
}
}
This is the code for the activity:
class Urltasks extends AsyncTask<String, Integer, JSONObject>{
protected void onPreExecute() {
System.out.println("Inicia onPreExecute");
Login.progressDialog.show();
}
protected void onPostExecute(String result) {
Login.progressDialog.dismiss();
}
protected JSONObject doInBackground(String... arg0) {
// Some work being done. I do not use Login.progressDialog here
}
}
With this code the ProgressDialog shows up when the task ends, and it doesn't dismiss.
Problem is here:
JSONObject result = new Urltasks().execute(...).get();
Calling get() on an AsyncTask blocks the current thread, i.e. your UI thread, until the AsyncTask is executed. Therefore the progress dialog cannot run. Remove the get().
To obtain the result of the AsyncTask, you can e.g. pass in a listener callback to the asynctask that gets notified when the result is available:
class YourAsyncTask extends AsyncTask<ParamType, ProgressType, ResultType> {
private YourResultListener mListener;
interface YourResultListener {
void onResultAvailable(ResultType result);
}
YourAsyncTask(YourResultListener listener) {
mListener = listener;
}
#Override protected ResultType doInBackground(ParamType... params) {
//...
}
#Override protected void onPostExecute(ResultType result) {
mListener.onResultAvailable(result);
}
}
You can use it like:
mProgressDialog.show();
new YourAsyncTask(new YourResultListener() {
#Override void onResultAvailable(ResultType result) {
mProgressDialog.dismiss();
// use result
}).execute(params);
Personally I like to keep user interface elements such as progress dialogs decoupled from async tasks.
Don't put your progress dialog in your log in class. Keep it in the async task
this is how you show your dialog
progressDialog = ProgressDialog.show(yourActivityHERE.this, "",
"Loading... please wait.");
Edited this for you:
class Urls extends AsyncTask<String, Integer, JSONObject>{
ProgressDialog progressDialog;
protected void onPreExecute() {
progressDialog = ProgressDialog.show(yourActivityHERE.this, "",
"Loading... please wait.");
}
protected void onPostExecute(String result) {
progressDialog.dismiss();
}
protected JSONObject doInBackground(String... arg0) {
// Some work being done. I do not use Login.progressDialog here
}
}
create the constructor in your Urltasks sending the context of the calling class.
then use that context to create the progress dialog in the preExecute of your Urltasks
class Urltasks extends AsyncTask<String, Integer, JSONObject>{
Context mContext;
public static ProgressDialog progressDialog;
public UrlTasks(Context c){
mContext=c;
}
protected void onPreExecute() {
progressDialog = new ProgressDialog(mContext);
progressDialog.setMessage("Sending data...");
progressDialog.setCancelable(false);
progressDialog.show();
}
protected void onPostExecute(String result) {
progressDialog.dismiss();
}
protected JSONObject doInBackground(String... arg0) {
// Do your work here
}
}