I have the following snippet:
public class SocketActivity extends Activity {
.
.
.
EditText textView;
Socket socket = new Socket(name,ip);
out = new PrintWriter(socket.getOutputStream());
out.flush();
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
.
.
.
}
Now, I have other lines to allow this activity to converse with a java server. But what I would like to do, is create a thread that constantly listens for a message from the server. Currently, it only listens for a response after I send a message. How would I set the textView from the thread? Is this the best way to do this? If not, where else should I do this?
======================
So, here is a more complete description of what I want to do, the textView is too primitive for what I want. So I have a MainActivity that creates a superclassed SurfaceView which has a superclassed Renderer that contains a Cube object with buffers, so it can be drawn. I also have a SocketActivity to connect to a server
What I want to do is wait for the server to send a packet of points to the client. Then, as each point is received it is put into the buffer. Then, once it completes, it waits again for the next packet. How should I use Asynctask be used to put a point to a buffer everytime I receive one. So to get a map of what's going on:
public class MainActivity extends Activity {
OpenGLSurfaceView view;
.
.
.
}
public class OpenGLSurfaceView extends SurfaceView {
OpenGLRenderer renderer;
.
.
.
}
public class OpenGLRenderer extends Renderer {
Cube cube;
.
.
.
}
public class Cube{
private FloatBuffer vertexBuffer;
.
.
.
}
public class SocketActivity extends Activity {
Socket socket;
BufferedReader in;
PrintWriter out;
.
.
.
}
Now where should the Asynctask be instantiated? Should I structure my program this way, or is there a better way? (For those that do not know, to put a primitive into a buffer you use buffer.put(/*primitive*/), but this is trivial.)
You cannot modify UI (in this case TextView) from non-UI thread. Try using AsyncTask. The UI can be modified ONLY in onPreExecute() and onPostExecute() methods. If you need example of how to use AsyncTask, please ask for.
There is another way to use Runnable with the method runOnUiThread() but, I recommend AsyncTask.
Example:
private class Surgery extends AsyncTask<String, Void, String> {
private String dataSurgery=null;
private File fileSurgery=null;
public Surgery (String data1, File data) //constructor
{
this.dataSurgery = data1; //this is just example here you can put anything you want
this.fileSurgery = data;
}
#Override
protected String doInBackground(String... params) {
//OPERATION WHICH IS UI-INDEPENDENT LET'S SAY SOMETHING LIKE THIS:
Socket socket = new Socket(name,ip);
out = new PrintWriter(socket.getOutputStream());
out.flush();
in = new BufferedReader(new InputStreamReader(socket.getInputStream())); return "here you return data for the textview or anything you need";
}
#Override
protected void onPostExecute(String result) {
// HERE YOU UPDATE YOUR TEXTVIEW i.e HERE YOU UPDATE ANYTHING WHICH IS ON THE UI
}
#Override
protected void onPreExecute() {
// This is OPTIONAL, you might find you dont need to use it.
}
}
}
Related
I'm a beginner in Android development. I'm trying to learn multi-threading and working with the internet so I'm doing that by downloading a PDF file from a link through the background thread using AsyncTask. I have confusions about what the best way is to go about it.
Do I create the URI and other necessary connectivity objects in the onCreate or in the doInBackground method of the AsyncTask class?
To download just a single PDF file, what sort of objects do I need to call?
I have checked the documentation but I couldn't really understand it. I'd appreciate a layman's explanation and possibly pseudo-code.
Here is the code I have so far:
public class MainActivity extends AppCompatActivity {
Button downloadPDF;
DownloadingClass downPDF;
private static final String TAG = "omar.asynctaskdemo;";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
String urlExample = "https://doc.lagout.org/programmation/Actionscript%20-%20Flash%20-%20Flex%20-%20Air/Flash%20Development%20for%20Android%20Cookbook%20-%20Labrecque%20-%20Packt%20%282011%29/Flash%20Development%20for%20Android%20Cookbook%20-%20Labrecque%20-%20Packt%20%282011%29.pdf");
downloadPDF = findViewById(R.id.download_pdf);
downPDF = new DownloadingClass();
downloadPDF.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
downPDF.execute();
}
});
}
private class DownloadingClass extends AsyncTask<String, Integer, Void>{
#Override
protected Void doInBackground(String... strings) {
return null;
}
}
}
AsyncTask just runs your code in the background thread. To download a pdf file is like any other file.
You will require to use HttpUrlConnection, Create a FileOutputStream and write the inputstream. Refer this
Have the above code executed in doInBackground of AsyncTask class and better pass the url in the constructor and do everything inside the doInBackground method. Since you don't want to block the UI thread.
I'm running httpsCommand (shown below, via clientTask() from MainActivity) and downloading about 1KB of data from a webserver. I plan to update a ListView in MainActivity (I think that's possible, but I recall it being a bit annoying last time I did it) with the downloaded data inside myListAllDoneListener(). I'd like to run this in a loop every 5 minutes to check for new data.
I've tried running new myCLientTask().execute()... inside a while loop (using Thread.sleep and try/catch) but it only seemed to run one loop and crashed after 15 seconds or so. Found a similar question but it's not quite answered. How can I background this data download?
// ** MainActivity.java **
public class MainActivity extends AppCompatActivity
{
...
#Override
protected void onCreate(Bundle savedInstanceState)
{
new clientTask(getApplicationContext(), myListAllDoneListener, ...);
...
private AsyncTaskCompleteListener myListAllDoneListener = new AsyncTaskCompleteListener()
{
#Override
public void onComplete(ArrayList<String> data, String msg, int statuscode)
{
// update listview with new data
...
//** clientTask.java **
public class clientTask extends Activity
{
ArrayList<String> mData;
...
public clientTask (Context ctx, AsyncTaskCompleteListener ... String cmd, ...)
{
...
new myClientTask().execute();
...
private class myClientTask extends AsyncTask<Object, Object, Object>
{
...
protected Object doInBackground (Object... params)
{
mData = httpsCommand (mCmd);
...
You can't use Thread.sleep in activity. It will block your UI. To run a periodic task
Look this stackoverflow answer using Handlers.
Also, there are some things wrong with your code. You shouldn't create object of an Activity class and use it for such things.
I've got an AsyncTask class that will do a HttpGet-request. I want to do something after this AsyncTask is done, but from within my MainActivity.
Here is my TaskGetAPI class:
public class TaskGetAPI extends AsyncTask<String, Void, String>
{
private TextView output;
private Controller controller;
public TaskGetAPI(TextView output){
this.output = output;
}
#Override
protected String doInBackground(String... urls){
String response = "";
for(String url : urls){
HttpGet get = new HttpGet(url);
try{
// Send the GET-request
HttpResponse execute = MainActivity.HttpClient.execute(get);
// Get the response of the GET-request
InputStream content = execute.getEntity().getContent();
BufferedReader buffer = new BufferedReader(new InputStreamReader(content));
String s = "";
while((s = buffer.readLine()) != null)
response += s;
content.close();
buffer.close();
}
catch(Exception ex){
ex.printStackTrace();
}
}
return response;
}
#Override
protected void onPostExecute(String result){
if(!Config.LOCALHOST)
output.setText(result);
else
controller = Controller.fromJson(result);
}
public Controller getController(){
return controller;
}
And here is the method from my MainActivity where I use this class:
private void sendGetRequest(){
...
// Web API GET-request
if(!get_url.equals("") && get_url != null){
TaskGetAPI task = new TaskGetAPI(output);
task.execute(new String[] { get_url });
// TODO: When AsyncTask is done, do:
controller = task.getController();
Log.i("CONTROLLER", controller.toString());
}
}
As you can see I set the Controller that I use later on in the onPostExecute-method of the AsyncTask.
Since this counters the entire purpose of Async tasks I first thought of removing the extends AsyncTask and just make a regular class & method of my HttpGet, but then I get a android.os.NetworkOnMainThreadException, meaning I need to use an AsyncTask (or something similar) to use HttpGet from within a different thread than my MainThread.
So, does anyone know what I should put at the // TODO?
I did try adding a boolean field (isDone) to the TaskGetAPI class with a getter and then use:
while(true){
if(task.isDone()){
Controller controller = task.getController();
Log.i("CONTROLLER", controller.toString());
}
}
But then the following steps occur:
doInBackground of the TaskGetAPI class is completely done.
Now we are stuck in this while(true)-loop..
and onPostExecute which sets the isDone to true is never called.
When the task will get finish then it will call onPostExecute, So you can use LocalBroadcast to send the broadcast message to main activity. You can use sendBroadcast which uses asynchronous manner i.e. send broadcast to all listener at a time rather than sendOrderedBroadcast.
Assuming that you only use TaskGetAPI inside your Activity, you can just define TaskGetAPI as an inner class, like the example in https://developer.android.com/guide/components/processes-and-threads.html#AsyncTask
public class MainActivity extends Activity {
public class TaskGetAPI extends AsyncTask<String, Void, String> {
/*
* This object is instanced inside the MainActivity instance,
* so it has access to MainActivity methods and members
* (including private ones).
* Remember to only access to UI elements like views from the main thread,
* that is, only from onPreExecute, onProgress or onPostExecute
* In this class "this" makes reference to the TaskGetAPI instance,
* if you need a refeence to the MainActivity instance, use MainActivity.this
*
*/
protected String doInBackground(String... urls){ ... }
protected void onPostExecute(String result){
mMyTextView.setText(result);
}
}
private TextView mMyTextView;
public void onCreate(Bundle savedInstanceState) {
setContentView(R.layout.main);
mMyTextView = (TextView) findViewById(R.id.view);
new TaskGetAPI().exec();
}
}
If you need to use TaskGetAPI you can define it outside MainActivity and define a subclass as inner class of MainActivity.
There are other options, though, like defining listeners (like the onClickListeners) and call them in onPostExecute, but that is unnecesarily complex.
You can send a broadcast with your result from onPostExecute with the response. The activity will listen to it and execute the code you want.
while(true) is never a good idea, especially on mobiles where battery life is important.
I'm trying to make an application that uses Asynctask. Particularly, I want to make different http petitions with different JSON in different activities without the activity being frozen while the communication is done.
At first I thought to use asynctask as a private inner class in those activities, but I saw that they share a lot of code. So I thought to make a single class and play with broadcast receivers as I need to monitorize when I receive the result of the http petition, and isn't good to interfere with activity directly in the onPostExecute while in a different class.
What I want to know is, what is more efficient and better practice. Make a class that has the shared code and extends asynctask, then doing inner classes for each activity that extends that one or make a single asynctask that sends broadcast and receive them with each activity when needed.
Excuse my poor english, if needed I'll try to specify more clearly.
Thanks in advance
Background
What I want to know is, what is more efficient and better practice. Make a class that has the shared code and extends asynctask, then doing inner classes for each activity that extends that one or make a single asynctask that sends broadcast and receive them with each activity when needed.
I'm unclear as to why these are your only two options. Create a single AsyncTask, such as JsonPetitionTask, then push a new JsonPetitionTask.Data object. This object would contain your URL, your JSON, and any other data you need.
Setting up the AsyncTask
Something like this:
public class JsonPetitionTask extends AsyncTask<JsonPetitionTask.Data, Integer, Boolean> {
protected Boolean doInBackground(JsonPetitionTask.Data... args) {
for (int i = 0; i < args.length; i++) {
JsonPetitionTask.Data data = args[i];
// Send your JSON; check for errors, and return false if needed.
if (isCancelled()) break;
}
return true;
}
protected void onProgressUpdate(Integer... progress) {
// Show progress?
}
protected void onPostExecute(Boolean result) {
// result is your success true/false.
}
public static class Data {
public String jsonContent;
public String petitionUrl;
public Data(String content, String url) {
jsonContent = content;
petitionUrl = url;
}
}
}
Calling the JsonPetitionTask
Then you can call it like so:
JsonPetitionTask.Data data = new JsonPetitionTask.Data(myJSON, myURL);
new JsonPetitionTask().execute(data);
And voilĂ , you've executed your AsyncTask using only one class with no receivers.
Implementing a callback
Now, if you want to register a callback (something to execute that is specific to the calling code), that's a bit trickier. If this is part of what you're looking for, I'll be glad to edit this post and explain it.
To add a callback, we can use the Runnable class to execute some code after the job is done.
Firstly, we need to add a new field in the Data inner class:
public Runnable callback;
Next, before we call execute(), we need to add a new callback to our data object.
data.callback = new Runnable() {
public void run() {
// Whatever code you want to run on completion.
}
};
Third, in the JsonPetitionTask class, we need a list of things to run:
private ArrayList<Runnable> mRunnables = new ArrayList<Runnable>();
Make sure, in each iteration of the doInBackground() loop, that you do mRunnables.add(data.callback);.
Lastly, in onPostExecute(), we need to call this:
protected void onPostExecute(Boolean result) {
for (Runnable r : mRunnables)
if (r != null) r.run();
}
I do realize I didn't send result to the Runnable, however I didn't feel like implementing a new Runnable type just to handle that. If you need this, I guess that's a bit of homework for you!
The way I found the best is just simply create public class that extends AsyncTask and then you just override onPostExecute function in every activity you use it.
Example:
MyDataTask dataTask = new MyDataTask() //you can add your parameters in class constructor
{
#Override
protected void onPostExecute(Object result) //replace Object with your result type
{
MyActivity.this.doStuff(result); //use result in current activity
}
};
you can also create some custom functions to set private variables in datatask
dataTask.AddParam("user", username);
dataTask.AddParam("pass", pass);
and then just execute it with your args...
dataTask.execute(myArgs);
I have used Async task class as single class. And for every Webservice call i have used unique IntentFilter to Broadcast response.
Put that Broadcast receiver in every class. You have perfect solution.
Its working well.
I have the following problem.
I have a class named "A" in which I create a list "List dStruct" .
I modify this object in the "A" class and I want to pass it to an Activity for further use.
Also the "A" class extends AsyncTask.
In this case,how do I pass an object to an Activity?
Here is the Activity Code:
List dStruct; //the object I want to access
btnPlanTrip.setOnClickListener(new OnClickListener() {
tripReq = new TripRequest(MainActivity.this);
tripReq.execute(request);
dStruct=tripReq.dStruct;
String str= dStruct.get(0).name;
}
Here is the code for the class "A"
public class TripRequest extends AsyncTask {
List dStruct;
public TripRequest(MainActivity activity) {
this.activity = activity;
dStruct=new ArrayList <DirectionsStruct>();
progressDialog = new ProgressDialog(activity);
}
protected void onPostExecute(Long result) {
code for dStruct
}
}
I solved this issue using Handlers. In my custom AsyncTask, I pass a Handler from an Activity to the constructor. In the AsyncTask's onPostExecute, I call Handler.sendMessage and it sends whatever data back to the Activity.
AsyncTask Code (your "A" class)
public class MyAsyncTask extends AsyncTask<RestClient, Void, RestResponse> {
Handler handler;
public MyAsyncTask(Handler handler) {
this.handler = handler;
}
#Override
protected RestResponse doInBackground(RestClient... rc) {
// Get data from web service or whatever...
}
#Override
protected void onPostExecute(RestResponse response){
Message msg = Message.obtain();
msg.obj = response;
this.handler.sendMessage(msg);
}
}
Handler declared in Activity
private Handler activityHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
// Do something with msg.obj
};
Call to AsyncTask from Activity passing in Handler to ctor (do this in your button click event handler)
MyAsyncTask async = new MyAsyncTask(activityHandler);
async.execute(...);
Arbitrary Java objects aren't really first-class constructs form an Android point of view.
The "main" thread enters your code though an Activity/Broadcast Receiver/Service/Content Provider/View...well, you get the idea. Application code can then control flow as it wishes, spawning new threads, sending intents for the OS to route appropriately, and utilizing other arbitrary classes (like your class A). However, your activity has to ask A, A can't tell your activity.
That being said, if your activity instantiates A, and A creates the List called dStruct in an instance method, you could do something like this.
public partial Class A {
public List createDStruct(){
List dStruct = new List()
//Do stuff to dStruct
return dStruct
}
public partial Class MyActivity {
public List retrieveDstruct(){
A a = new A()
return a.createDStruct()
}
}