Executing thread only in one Android Activity - java

I have three java files in my Android project. Two are activities (MainActivity and GeoActivity) and one is a plain java file (PostHttp -> sends data to server via the HTTP POST)
I switch over to GeoActivity via a simple button on-click method. GeoActivity returns the co-ordinates of the current location in a TextView AND sends them to a remote server via the HTTP POST.
I have a Handler.class which executes sends the Post Message after a delay of 50s. Something like this below. The problem i have is that when i click the back button and switch over to MainActivity i can still see in LogCat the echoes receiving from the server that the data is still being sent. How can i stop that?
GeoActivity.class
public class GeoActivity extends Activity {
Location location;
private Handler mHandler = new Handler();
protected void onCreate(Bundle savedInstanceState) {
....
if(location != null){
mHandler.postDelayed(updateTask,0);
}
...
}
...
public Runnable updateTask = new Runnable(){
public void run(){
mlocListener.onLocationChanged(location);
//send coordinates with a delay of 50s
new PostHttp(getUDID(),latitude,longitude).execute();
mHandler.postDelayed(updateTask, 50000);
}

Try acting on the activity's life cycle.
For example:
#Override
protected void onStop() {
super.onStop(); // Always call the superclass method first
// Save the note's current draft, because the activity is stopping
// and we want to be sure the current note progress isn't lost.
ContentValues values = new ContentValues();
values.put(NotePad.Notes.COLUMN_NAME_NOTE, getCurrentNoteText());
values.put(NotePad.Notes.COLUMN_NAME_TITLE, getCurrentNoteTitle());
getContentResolver().update(
mUri, // The URI for the note to update.
values, // The map of column names and new values to apply to them.
null, // No SELECT criteria are used.
null // No WHERE columns are used.
);
}
This doesn't destroy the activity, it will reside in memory. However, you can always resume when needed.
Source:
Stopping and Restarting Android Activities

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.

Communicate between service and activity

I have a class in a service
MyClass m = new MyClass();
and inside my class I check if I have permission to overlay the view; if so, it's ok, otherwise I must start an activity
if (Settings.canDrawOverlays(mContext)) {
// draw over app
} else {
// start the activity
Intent i = new Intent(context,Calls.class);
context.startActivity(i);
}
When I start the activity I have a problem communicating between the class and the activity. I know how to use the interface but how can I register it in activity.
Some time I want to pass an object or data from the class to the activity or from the activity to the class... how can I do that?
I saw many examples in Stack Overflow about how to communicate between service and activity; they suggest to start the class from the activity but this does not work in my app because my class must be running all the time.
Perhaps you could use an event bus like mechanism where you can send or receive events through out your app, Though there are several libraries out there, I would recommend using Otto library for android.
Usage is pretty simple just register in your activity onCreate
Bus bus = new Bus();
bus.register(this);
For sending events
// example data to post
public class TestData {
public String message;
}
// post this data
bus.post(new TestData().message="Hello from the activity");
And subscribe to events like this
#Subscribe public void getMessage(TestData data) {
// TODO: React to the event somehow!
}
More info here
If you want to implement a communication pattern between a Service and an Activity, you should use a LocalBroadcastManager.
It will turn handy because, in case your Service is still on but your Activity
has been destroyed (very common situation), then the 'messagging' between the two will simply have no effect (no NPE or whatsoever will be thrown).
Step 1
Create a BroadcastReceiver in your Activity and define an ID / Filter
this.localBroadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// Do what you have to do here if you receive data from the Service / Background Task
}
}
public static final IntentFilter SIGNAL_FILTER = new IntentFilter("com.you.yourapp.MY_SIGNAL")
Step 2
In your Activity register the broadcast in onResume() and unregister it in onPause().
#Override
protected void onResume() {
// Listen if a Service send me some data
LocalBroadcastManager.getInstance(getApplicationContext()).registerReceiver(this.localBroadcastReceiver, SIGNAL_FILTER);
}
#Override
protected void onPause() {
// I'm going to the background / or being destroyed: no need to listen to anything anymore...
LocalBroadcastManager.getInstance(getApplicationContext()).unregisterReceiver(this.localBroadcastReceiver);
}
Your Activity is now ready to receive data from any other component in your Application.
If it's in the background, then there is no need to update the UI: in fact the Activity will not respond if in the background.
In the same way, if it's being garbage collected, the Receiver will be unregistered and the Activity will just not respond to anything.
If the Activity is resumed / restarted, onResume() will be triggered and the Receiver will be registered again.
Step 3
All you need to do right now, is send data from the Service.
Simply call
final Intent intent = new Intent();
intent.setAction(SomeActivity.SIGNAL_FILTER);
// put your data in intent
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intent);
and your Activity will accordingly respond to the signal.
It's surprising how few people know about the LocalBroadcastManager and instead use some self-implemented callback / singleton pattern, which increases complexity and non-readability.
This pattern is built-in in Android, so you don't need external libraries. As for security, this ensures that your signals stay internal to your application: no data can therefore be read by other apps.
I similarly answered to another question here.

Proper way to refresh multiple tab in backround thread

I have implemented dynamic tab navigation with fragments. Fragments are stored on the stack and when user change tab, new fragment should replace existing content to show new items.
But first, data must be refreshed (they will be downloading from rest webservice) and it takese some time, so there is also BusyFragment, indicating data loading process.
I implemented background refreshing data with AsyncTask and I have separate AsyncTask object that is called to refresh specific tabs, this way:
private void RefreshShopsMainMenuFragment(Fragment f)
{
if (refreshAsyncTaskShops != null && refreshAsyncTaskShops.getStatus() != AsyncTask.Status.FINISHED)
return;
final ListFragment fragmentToRefresh = (ListFragment) f;
refreshAsyncTaskShops = new AsyncTask<Void, Void, ArrayList<ListDataDef>>()
{
#Override
protected void onPreExecute()
{
ShowBusyFragment(true, Global.TAB_SHOPS); //for other tabs, other tab identifiers from Global
}
#Override
protected ArrayList<ListDataDef> doInBackground(Void... voids)
{
return ShopsTabDataProvider.GetNewData(); //For other tabs, different data provider call
}
#Override
protected void onPostExecute(ArrayList<ListDataDef> result)
{
fragmentToRefresh.mainData = result;
fragmentToRefresh.DisplayNewData();
ShowBusyFragment(false, Global.TAB_SHOPS); //for other tabs, different tab indentifier
}
};
refreshAsyncTaskShops.execute();
}
So, basically as shown above: to refresh shops tab, refreshAsyncTaskShops will be called, there are also other async task object, I marked lines where they are different.
Is there any more elegant solution, without declaring multiple AsyncTask objects? I'm not fully satisfied with my current implementation, because my all async tasks objects are basically the same.
Also, as you can see, there is no any queue so don't need to wait for first tab refreshing and to refresh another one. However, refreshing the same tab multiple times simultaneously should never happen so I added if condition to prevent the same task to be executed if previous one is not finished yet.

Android: Logout system and the android lifecycle

on the weekend I started to build my first android app. As I need to ask the user of my app for user credentials [which are used for further webservice usage] I want to simulate a "login system". On the start of my app the user should be told to enter his credentials. When the user is inactive for too long I want to dismiss the entered credentials and to "log out" the user.
While coding and afterwards while testing I realized that the way I thought I could go doesn't work. After reading the docu and several SO-questions again and again I question myself more and more if I have understand the app / activity life cycle and its possibilites fully. So I wanted to ask for help in understand the life cycle and its linked influences on my app. So yes this might be several questions in one :/
For the moment my app consists of the following activities:
a search activity (which is opened once the app is started)
a settings acitivy (which can be accessed from the search dialog and has a link back to the search dialog)
After the user has entered an ID in the search dialog I want to open an activity regarding to the search result (NYI).
When starting to implement the user auth, my idea was the following:
Everytime onResume() of an activity is called I need to check a) if user credentials are already stored and b) if the last action of the user is less then X minutes ago. If one these fails I want to show a "log in panel" where the user can enter his credentials, which are then stored in the SharedPreferences. For that I did the following:
I first build an parent activity which has the check and a reference for the SharedPreferences in it
public class AppFragmentActivity extends FragmentActivity {
protected SharedPreferences sharedPref;
protected SharedPreferences.Editor editor;
protected String WebServiceUsername;
protected String WebServicePassword;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_appfragmentactivity);
}
#Override
protected void onResume () {
super.onResume();
// Check if user is "logged in".
// Meaning: Are there given user credentials and are they valid of was the user inactive for too long?
// We only do this "onResume" because this callback is the only one, which is called everytime an user
// starts/restarts/resumes an application
checkForUserCredentials();
// Set new "last action" now "now"
setLastAction(new Date().getTime());
}
#Override
protected void onStart () {
// Fill content
super.onStart();
// Set global sharedPreferences
sharedPref = this.getSharedPreferences(getString(R.string.FILE_settings_file), Context.MODE_PRIVATE);
}
/*
* Checks if user credentials are valid meaning if they are set and not too old
*/
private void checkForUserCredentials() {
long TimeLastAction = sharedPref.getLong(getString(R.string.SETTINGS_USER_LAST_ACTION), 0);
long TimeNow = new Date().getTime();
// Ask for User credentials when last action is too long ago
if(TimeLastAction < (TimeNow - 1800)) {
// Inactive for too long
// Set back credentials
setUsernameAndPassword("", "");
}
else
{
WebServiceUsername = sharedPref.getString(getString(R.string.SETTINGS_USER_USERNAME), "");
WebServicePassword = sharedPref.getString(getString(R.string.SETTINGS_USER_PASSWORD), "");
}
}
/*
* Saves the given last action in the sharedPreferences
* #param long LastAction - Time of the last action
*/
private void setLastAction(long LastAction) {
editor = sharedPref.edit();
editor.putLong(getString(R.string.SETTINGS_USER_LAST_ACTION), LastAction);
editor.commit();
}
/*
* Saves the given username and userpassword sharedPreferences
* #param String username
* #param String password
*/
private void setUsernameAndPassword(String username, String password) {
editor = sharedPref.edit();
editor.putString(getString(R.string.SETTINGS_USER_USERNAME), username);
editor.putString(getString(R.string.SETTINGS_USER_PASSWORD), password);
editor.commit();
WebServiceUsername = username;
WebServicePassword = password;
}
/*
* Method called when pressing the OK-Button
*/
public void ClickBtnOK(View view) {
// Save User-Creentials
EditText dfsUsername = (EditText) findViewById(R.id.dfsUsername);
String lvsUsername = dfsUsername.getText().toString();
EditText dfsPassword = (EditText) findViewById(R.id.dfsPassword);
String lvsPassword = dfsPassword.getText().toString();
if(lvsUsername.equals("") || lvsPassword.equals("")) {
TextView txtError = (TextView) findViewById(R.id.txtError);
txtError.setText(getString(R.string.ERR_Name_or_Password_empty));
}
else
{
// Save credentials
setUsernameAndPassword(lvsUsername, lvsPassword);
setLastAction(new Date().getTime());
// open Searchactivity
Intent intent = new Intent(this, SearchActivity.class);
startActivity(intent);
}
}
The "log in mask" is setContentView(R.layout.activity_appfragmentactivity);.
The two other activites I created are then extending this parent class. This is one of it:
public class SearchActivity extends AppFragmentActivity {
SearchFragment searchfragment;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_search);
}
#Override
protected void onResume() {
super.onResume();
if(WebServiceUsername.equals("") && WebServicePassword.equals("")) {
// Username not set. Re"login".
Intent intent = new Intent(this, AppFragmentActivity.class);
startActivity(intent);
}
}
#Override
protected void onStart() {
super.onStart();
}
// ...
}
As far as I understand the lifecycle now this should work as the following: When my app starts (the SearchActivity is set for LAUNCH) the app should step into the onResume() of my parent class. There it sees that the credentials are not yet stored and opens the layout of the AppFragmentActivity which is the login. When entered, the user is redirected to the SearchActivity which now sees "ok credentials are there, lets move forward". But this doesnt't happen as the login is not shown up. So I think my onResume() might be wrong. Perhaps my full idea is bad? Up to here I thought I also understand the life cycle, but obviosly I don't?
I then had a look around on SO for similar problems. One thing I saw here was a comment to an user which wanted to build a similar "logout" mechanism as mine, that he has to implement this in every activity. I thought about that and ask myself "Why do I have to override the onResume() in every of my activites, when they are all from the same parent? When theres no onResume() in the child, the one of the parent should be called". The user in the SO-question was advised to use services as background threads to count down a timer in there for the logout. I then read the services article in the docu and then fully got disoriented:
There are two types of services: Started and bounded ones. A started service is once started by an activity and then runs in the background until hell freezes when it doesn't get stoped. So it's fully independed of any app, but the programmer has to / should stop it when it's not longer needed. A bounded services is bounded to one or many app components and stops when all bounded components end. I thought this might be a good alternative for me, but when I thought further I ask myself how: If one of my starts it (let's say the login dialog) and then is closed the service is stoped and the other activites always start there own ones which can't be the sense of it. So this service must be bounded not to any component but to my app. But whats the life cycle of an android app? How can I keep information "global" inside my app. I know I can switch data between actitivites using 'Intents'.
This more and more "foggy cloud" lead to ask myself: "Shall I use only one activity and try to switch in/out everything using fragments?"
So my questions are (I think that's all of them, but I'm not sure anymore):
Does my idea of writing an parent class which does the checks for all extended childs ok or bad AND does it work as I understood it?
Do I have to override every onResume() in the childs just to call the parent one for the checks?
Can you give me a tip why my "login systems" doesn't work?
What's the life cycle of an android app and how can I interact with it?
Shall I only use one activity and switch in/out everything using fragments or is it a good way to have several activities and some of them use fragments (to reuse often used parts)?
Thanks in advise
What I've done in the end is the following:
I removed the "login" thing from the parent class into a stand alone activity. This activity is called when the credentials are not valid together with an finish() of the calling one. So I don't build a loop and drop unused activites.

How do I run an AsyncTask over and over?

I have an onCreate method that runs the code below. In a nutshell the code retrieves data from the server and shows it on the screen for a messaging program. It only does it once, but I would like it to run the AsyncTask every 3 seconds (to try to simulate a chat). I'm pretty sure this is not the way to go about having a chat system but, I just need something that works for now (as a proof of concept) and I'll focus on the correct way of implementing it later.
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.chat_box);// sd
final Functions function = new Functions();
final SharedPreferences prefs = PreferenceManager
.getDefaultSharedPreferences(getBaseContext());
whatroom = prefs.getString("chat", "null");
new AsyncTask<String, Void, String>() {
#Override
protected String doInBackground(String... args) {
return function.getInbox(args[0]);
}
#Override
protected void onPostExecute(String result) {
TextView inbox = (TextView) findViewById(R.id.inbox);
ProgressBar progressBar = (ProgressBar) findViewById(R.id.progressBar1);
progressBar.setVisibility(View.GONE);
inbox.setText(result);
}
}.execute(whatroom);
}
I've tried putting a simple while statement around the asynctask but, it just force closes.
You cannot reuse an AsyncTask instance. You would need to create fresh instances each pass of your loop.
Without additional information, it's difficult to give you a specific answer. However look into abstracting everything using a Loader, using a Service, etc
Regarding Loaders:
They are available to every Activity and Fragment.
They provide asynchronous loading of data.
They monitor the source of their data and deliver new results when the content changes.
They automatically reconnect to the last loader's cursor when being recreated after a configuration change. Thus, they don't need to re-query their data.

Categories

Resources