Use AsyncTask in multiple activities - java

I have a problem with proper use AsyncTask. I use AsyncTask to communicate with the server. I run server connection in AsyncTask doInBackground. My app listens in the background and as soon as captured message uses publishProgress. Then I can use message in my App. In my application I am doing login to the server and if it was successful new activity will start. I need to communicate with the server also in the new activity but the connection was created in the background AsyncTask. I don't know how I can communicate through established connection in new activity. Can anyone give me advice? Thank you a lot!
Please take a look on code. I have this code in LoginUser class and after succesful login to the server new Activity starts.
//init
private ConnectionClass mConnectClass;
private connectTask mTask;
//execute connectTask
mTask = new connectTask();
mTask.execute("");
public class connectTask extends AsyncTask<String, String, ConnectionClass> {
#Override
protected ConnectionClass doInBackground(String... message) {
Log.i("Terminal", "doInBackground.");
mConnectClass = new ConnectionClass(
new ConnectionClass.OnMessageReceived() {
#Override
// here the messageReceived method is implemented
public void messageReceived(String message) {
// this method calls the onProgressUpdate
publishProgress(message);
}
});
Log.i("Terminal", "Starting...");
mConnectClass.connectServer();
return null;
}
#Override
protected void onProgressUpdate(String... values) {
super.onProgressUpdate(values);
answerFromServer = Arrays.toString(values);
// serverMessage.append("S: " + Arrays.toString(values) + "\n");
}
}

Don't use AsyncTask for this. You seem to want to hold your connection open for an extended period of time. AsyncTask is only supposed to be used for tasks that last at most a few seconds. You might consider using a Service instead.

Related

Reset AsyncTask to multiple execution

Is there any way to use AsyncTask.execute() multiple times?
Im using AsyncTask to check, if User exist in my Room Database.
My Login.class looks like this:
public class Login extends AsyncTask<String, Boolean, Boolean> {
public Login(Context context, LoginListener listener){
db = ApplicationDatabase.getDatabase(context); //i get Room here
this.context = context; //context of app
this.listener = listener; //my interfece for observe Boolean, works ok
}
#Override
protected Boolean doInBackground(String... body){
try {
user = db.userDao().getUser(body[0], body[1]);
if (user != null)
return Boolean.TRUE; //we find user with credentials
else {
return Boolean.FALSE; //we not find user with that credentials (from body)
}
}
catch(Exception e){
return null;
}
}
protected void onPostExecute(Boolean result) {
listener.onLoginPerformed(result); //Boolen to activity
selfRestart(); //i want to restart task here
}
private void selfRestart(){
//maybe something to do here? its my own method
}
private ApplicationDatabase db;
private User user;
private LoginListener listener;
private Context context;
I call Task in this way (my Activity.class):
login = new Login(getApplicationContext(), this);
//this is an interface that i implements in Activity definition
loginButton.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View v){
//execute() here, i cuted some not necesery code from here
try {
// im using get because i want to get valu from AsyncTask
login.execute(email, password).get();
}
catch(Exception e){ }
}
I Read, that we can reset AsyncTask by making new AsyncTask (Task = new Login()) StackOverflow Thread but it dont work for me. When i try to make something like this in my Login class:
private void selfRestart(){
Login task = new Login(context, listener);
task.execute("");
//im calling it in onPostExecute()
}
My android app crashes. My question is, what is the best way to reset AsyncTask that is implemented in diffrent file then my Activity class? Or maybe there is better way to make Login activity than implemented whole logic for login in AsyncTask?
EDIT:
Logcat:
2019-01-24 15:45:31.407 1048-1048/com.example.admin.keystroke_dynamics E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.admin.keystroke_dynamics, PID: 1048
java.lang.NullPointerException: Attempt to invoke virtual method 'boolean java.lang.Boolean.booleanValue()' on a null object reference
at com.example.admin.keystroke_dynamics.Activities.LoginActivity.onLoginPerformed(LoginActivity.java:62)
at com.example.admin.keystroke_dynamics.Login.onPostExecute(Login.java:38)
at com.example.admin.keystroke_dynamics.Login.onPostExecute(Login.java:14)
at android.os.AsyncTask.finish(AsyncTask.java:692)
at android.os.AsyncTask.-wrap1(AsyncTask.java)
at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:709)
at android.os.Handler.dispatchMessage(Handler.java:105)
at android.os.Looper.loop(Looper.java:156)
at android.app.ActivityThread.main(ActivityThread.java:6523)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:942)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:832)
You say,
I call Task in this way (my Activity.class):
login = new Login(getApplicationContext(), this);
//this is an interface that i implements in Activity definition
loginButton.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View v){
//execute() here, i cuted some not necesery code from here
try {
// im using get because i want to get valu from AsyncTask
login.execute(email, password).get();
}
catch(Exception e){ }
}
, but no, you are not "calling" your task that way. You are creating a single instance of the task, and setting up an event handler that executes that task -- that specific instance -- whenever the loginButton is clicked. Since each AsyncTask instance may be executed only once, that will fail the second time the login button is clicked (if not sooner, for some other reason).
You also say,
I Read, that we can reset AsyncTask by making new AsyncTask (Task = new Login())
, but no, that does not reset anything, and indeed AsyncTask objects cannot be reset. The advice you read was to replace the used AsyncTask with a fresh instance. Instantiating a new AsyncTask has no particular effect on others. If you want to pursue that approach then it might look something like this:
loginButton.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View v){
Login myLoginTask = login; // keep a reference to the current task
login = new Login(... arguments ...); // create a new task for the next click
try {
// use the original task
myLoginTask.execute(email, password).get();
}
catch(Exception e){ }
}
That specific implementation requires login to be non-final, so probably an instance variable of the containing class, not a local variable of the method from which your code was excerpted.
HOWEVER, your best way forward might very well be to ditch AsyncTask altogether. When you use it like this:
login.execute(email, password).get();
... you defeat the entire purpose. You are making the thread in which that runs block until the task completes (that's what AsyncTask::get is for), so the task is effectively synchronous. If that's what you require then you should just do the wanted work more directly instead of wrapping it up in an AsyncTask.

Toast in not showing in asynctask

I am trying to get message from the server to show in toast but it does not appear. The client receives the message from the server without any errors.I have tried opening UI thread in onpost but it didn't work
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
new test().execute();
}
public class test extends AsyncTask<String,String,String>{
#Override
protected String doInBackground(String... params) {
try
{
socket = new Socket("ip", port);
OutputStream outToServer = socket.getOutputStream();
DataOutputStream out = new DataOutputStream(outToServer);
Log.i(debugString, "Connected_reg!");
out.writeUTF("3");
InputStream inFromServer = socket.getInputStream();
DataInputStream in = new DataInputStream(inFromServer);
Log.i(debugString, in.readUTF());
string= in.readUTF();
}
catch (Exception e) {
Log.e(debugString, e.getMessage());
}
return null;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected void onPostExecute(String s) {
//super.onPostExecute(s);
Context context = getApplicationContext();
CharSequence text = string;
int duration = Toast.LENGTH_SHORT;
Toast toast = Toast.makeText(context, text, duration);
toast.show();
}
}
It might be to do with the context.
I've had issues in the past with getApplicationContext not working for certain things, although can't remember what form the top of my head.
Instead of using getApplicationContext, in the activity where you call your async task put this in the constructor call. For example, assuming you are going from MainActivity change the line new test().execute(); to new test(MainActivity.this).execute();
Then in the async class create the constructor as
public test(Context context) and set a global class variable to be the value of context, and then use this in your toast.makeText instead of what is returned from getApplicationContext.
Also take a look in the logcat, see if there are any errors or exceptions being thrown, it might also be worth adding a log line in the onpostexecute method just to double check you're definetely going in there.
Create a constructor in the test class which receive a context and use that context in the Toast.makeText. Pass the host activity context to that constructor.
getApplicationContext() is a Context class method, AsyncTask does not inherent from that class. I suppose you are in a scope where you can invoke that method but that scope context is not valid in the scope that you are invoking the Toast.makeText method.

Architecture of android custom library

I am building an android library.
The main class includes methods like connect,getUserSession .Workflow includes few steps-
Step 1 :
In getUserSession method. I need to send a Http POST request to external api and
recieve the response data(sessionKey,id,name etc). It is like an authentication method.
Step 2 :
In connect method. It uses the response data from Step 1 then I need to connect to websocket server recieve the response data(userdetails,profilepic etc).
Step3 :
Pass the response data from Step 2 in Activity.
I want to be step 1 and step 2 to be synchrounous because step 2 won't work without step 1. And i dont want to block the app while processing.After doing some research i found this can be done using AsyncTask class. But it seems i cannot return values from doInBackground and onPostExecute methods. How to do this task?
You have to set listener (interface) for first AsyncTask Please try below code
interface AsyncTaskListener{
public void onTaskCompleted(Object<Type> value);
}
public class DemoAsyncTask extends AsyncTask<String,Void,Void>{
AsyncTaskListener listener;
public DemoAsyncTask(AsyncTaskListener listener){
this.listener = listener;
}
#Override
protected String doInBackground(Void... params) {
///do some task
return someResult;
}
#Override
protected void onPostExecute(String result) {
listener.onTaskCompleted(result);
}
//Calling Async task from activity or fragment
DemoAsyncTask task = new DemoAsyncTask(new AsyncTaskListener(){
#Override
public void on onTaskCompleted(Object<Type> value);{
//do your second step here
})
};
task .execute();

Android sending data to Activity via Local Service [duplicate]

This question already has answers here:
How can I update information in an Android Activity from a background Service
(5 answers)
Closed 9 years ago.
I have an app that receives gcm push notifications. I also have a check in place that if the app is currently open, it does not create the notification. In Android, is it possible in my push service to tell the current activity (IF Available/connected), that a new notification has arrived, refresh your list with the new content? If this is possible, I believe I am on the right path with using IBinders on my service. The thing about that is I am confused on how the Service Calls the Activity (I understand vice verse). Thanks in advance if anyone could help!
Just to be clear. I am trying to tell the activity about a new push message.
Service
public class LocalBinder extends Binder {
GcmIntentService getService() {
return GcmIntentService.this;
}
}
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
private final IBinder mBinder = new LocalBinder();
Client (Activity)
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
// This is called when the connection with the service has been
// established, giving us the service object we can use to
// interact with the service. Because we have bound to a explicit
// service that we know is running in our own process, we can
// cast its IBinder to a concrete class and directly access it.
mBoundService = ((GcmIntentService.LocalBinder)service).getService();
// Tell the user about this for our demo.
Toast.makeText(MainActivity.this, "Connected", Toast.LENGTH_SHORT).show();
}
public void onServiceDisconnected(ComponentName className) {
// This is called when the connection with the service has been
// unexpectedly disconnected -- that is, its process crashed.
// Because it is running in our same process, we should never
// see this happen.
mBoundService = null;
Toast.makeText(MainActivity.this, "Disconnected",
Toast.LENGTH_SHORT).show();
}
};
void doBindService() {
// Establish a connection with the service. We use an explicit
// class name because we want a specific service implementation that
// we know will be running in our own process (and thus won't be
// supporting component replacement by other applications).
bindService(new Intent(MainActivity.this,
GcmIntentService.class), mConnection, Context.BIND_AUTO_CREATE);
mIsBound = true;
}
void doUnbindService() {
if (mIsBound) {
// Detach our existing connection.
unbindService(mConnection);
mIsBound = false;
}
}
#Override
protected void onDestroy() {
super.onDestroy();
doUnbindService();
}
Yes it's possible.
In your service class have a variable of type YourActivity
MyActivity myActivity = null;
In your onServiceConnected method set this myActivity variable on the service, obtained through the binder.
mBoundService.myActivity = MyActivity.this; // or something similar
Now your service has a pointer to your activity!!! YEah!!
Inside your activity, create a function, the body of this function should refresh the UI with data.
Finally, when the service detects new data, call:
if (myActivity)
myActivity.refreshMyData();
When unbinding, remember to set the myActivity variable to null, otherwise the previous code will fail.

Managing a mysql connection after button clicked

my goal is to insert to a certain db 2 values, id and pass.
I have a registeration page which asks for that data and a button to complete the action.
So on the button listener what should I do?many told me to use AsyncTask (which I don't know to use) instead of Thread.
Remember that this class needs to get 2 parameters id and pass .. and as far as I know threads starts after using the start() method which invoke the run method, and the run method has no parameters.. so how can I pass those 2 parameters?
Anyway I'm very confused.
Another thing is that if I get any kind of error on the catch block I will put the error on a certain string something like : String error = exceptionInstance.toString(); and then I can take see that string from the registeration page and print the error.
myThreadInstance.start();
textViewInstance.setText(myThreadInstance.getError());
It's some kind of a marathon.. I'M CONFUSED!!!!!!!
According to me use AsyncTask instead of an Thread because it's easy to use and you have better control on Background thread without doing extra code for creating separate logic for updating Ui when Thread execution complete, calculate progress units to so user how much time take by an operation to done etc
Your First question how you send username and password to AsyncTask on button click .for this use AsyncTask Constructor as:
LoginOperation loginopertion=new LoginOperation(strusername, strpassword);
loginopertion.execute("");
Your Second answer how we receive username and password in AsyncTask and update Ui when Task complete for this use onPostExecute of AsyncTask to update Ui when doInBackground execution complete for example :
public class LoginOperation extends AsyncTask<String, Void, String> {
String strusername,strpassword;
public LoginOperation(String strusername, String strpassword){
this.strusername=strusername;
this.strpassword=strpassword;
}
#Override
protected void onPreExecute() {
//show progressbar here
}
#Override
protected String doInBackground(String... params) {
string result="";
try
{
result=="success or fail";
//do your network opertion here
}
catch(SQLException e)
{
result="ERROR";
}
return result;
}
#Override
protected void onPostExecute(String resultmsg) {
// show error here and update UI
//or other opertion if login success
textViewInstance.setText(resultmsg);
}
}
For more information about AsyncTask method's see
http://developer.android.com/reference/android/os/AsyncTask.html

Categories

Resources