I created an application which is asynchronously communicating with the server. When the application makes a server request a new dialog (activity) with "loading" notification is created. The main activity implements methods for handling server responses and I would like to close the foreground activity when the main activity receives the answer from the server.
Notification dialog is created the following way:
private void showServerRequestDialog(String actionLabel){
Intent intent = new Intent(this, DlgServerRequest.class);
intent.putExtra(SERVER_REQUEST_ACTION, actionLabel);
startActivity(intent);
}
so when the user tries to authenticate the following method is called:
private void authenticateUser(String IMEI, String username, String password){
mEncoderConnection.authenticateRequest(IMEI, username, password);
showServerRequestDialog("Authenticating...");
}
and onAuthenticateResponse handles authentication response:
public void onAuthenticateResponse(AuthenticateResponse pkg) {
//code for response handling
//TODO: close ServerRequestDialog
}
}
I would appreciate if anyone could suggest a way to close the notification dialog (DlgServerRequest) when the onAuthenticateUser() is executed.
Why not use a real ProgressDialog or some other Dialog? Then, all you need to do is dismissDialog(), and you're done?
If that is unacceptable, you have two main courses of action that I can see:
Move your authentication logic into the DlgServerRequest class, so it can finish() itself.
Put your instance of your DlgServerRequest class into a static data member so your main activity can call finish() on it
If you choose option #2, it is really important to null out that static data member to avoid memory leaks.
Related
So, we have this existing App with a MainActivity, with whole bunch of interface implementations. I want to implement IBranchSessionInterface. I have followed the documentation as given here: https://docs.branch.io/pages/apps/xamarin/
Have BranchActivity and BranchErrorActivity
One thing I can't seem to understand in the following sequence:
ApplicationClass calls:
BranchAndroid.GetAutoInstance(this.ApplicationContext);
MainActivity that Implements IBranchSessionInterface has this code in OnCreate()
BranchAndroid.Init(this, Resources.GetString(Resource.String.branch_key), this);
When the Branchsession is successfully initiated, it calls the IBranchSessionInterface, InitSessionComplete callback.
Here is the full method impl:
public void InitSessionComplete(Dictionary<string, object> data)
{
var intent = new Intent(this, typeof(BranchActivity));
intent.PutExtra("BranchData", JsonConvert.SerializeObject(data));
StartActivity(intent);
}
After this, what needs to happen? Because after Starting branch activity I see nothing but empty screen. How is it suppose to come back to MainActivity?
The Branch activity is simply an example of how you can use Branch link data. You don't actually need that activity, or the intent to redirect to it.
You may simply delete all of that code and replace it with the following to view the data upon app open:
public void InitSessionComplete(Dictionary<string, object> data)
{
Console.WriteLine("Branch Link Data: " + JsonConvert.SerializeObject(data));
}
I need to run the following when i get a message from my GCM listner:
public void GetInfo1 (Bundle data){
Log.d("Get Messages", "Data: " + String.valueOf(data));
final String uid = data.getString("uid");
final String infoid = data.getString("infoid");
GetInfo(uid, infoid); // This is another activity that does a Json Post and returns a array that i use to populate my Listview
}
This is how i call the function :
if (activityName.equals(MyActivity.class.getName())) {
// Execute that special method from ActivityListView
Log.d(TAG, "Activity is running");
MyActivity myActivity = new MyActivity();
myActivity.Getinfo1(data);
} else {
// Show the notification
sendNotification(message);
}
but i am always getting this error :
Can't create handler inside thread that has not called
Looper.prepare()
I have tried everything, and am out of ideas now,
I need to call the function and pass the vars but if i make it static i get a error that you cant call non static methods from a static ....
Please any help will be fantastic
T-
In general, to start a new activity, you should not instantiate the activity directly but rather use an Intent to trigger the activity, using either startActivity() or startActivityForResult(). However, in this case, it would appear that you are doing an operation that is intended to run in the background (without user interaction). Activity is an application component intended for direct interaction with the user. For background processing, you should be using a Android Service, instead. As with an Activity, you do not create services directly, but rather invoke them by firing off appropriate Intents.
What is the best way to use volley? First I used volley as they provided so sometime it throws
java.lang.IllegalStateException because the activity has been finish till the response from volley return.
So I went online and find a solution using event bus. So right know I am using event bus, register a event on onResume and unregister it on onPause, and on onResponse post the registered event.
But I want some generic and better approach.
PS: There is also a library doing the same thing OttoVolleyDoneRight I don't want to use that too.
You should have a singleton instance of Volley - which holds all volley parts there (such as RequestQueue). You should init this singleton as part of your application object (or event as part of your main activity, and then destroy it in onDestroy).
Here's a sample of how to create a Volley singleton:
https://developer.android.com/training/volley/requestqueue.html
I don't think that working with events and volley is correct. You should have a concrete listener for each request you make. What you can do is simple: Create a class (or an inner static class) that implements Volley Listener/ErrorListener and holds your activity in a WeakReference - once callbacks from volley are called just check if your activity reference still exists and do what you want. If it doesn't exist then it was probably was closed (and GC picked up the WeakReference).
This way you avoid memory leaks (leaking the activity) and handle your callbacks correctly.
** I don't know what your app is doing but I'm pretty sure that you don't really need to handle network callbacks in your activity but rather in some adapter you have (of a ListView for example).
Pass a new instance of this listener to Volley as a callback.
public class MyImageListener extends implements Response.Listener<T>, Response.ErrorListener {
private WeakReference<Activity> mActivity;
private final String mUrl;
public MyImageListener(String url, Activity activity) {
mUrl = url;
mActivity = new WeakReference<>(activity);
}
#Override
public void onErrorResponse(VolleyError error) {
Activity activity = mActivity.get();
if (activity != null) {
// Activity is alive, do what you need with it
}
}
#Override
public void onResponse(T result) {
Activity activity = mActivity.get();
if (activity != null) {
// Activity is alive, do what you need with it
}
}
}
Cheers!
I have a class in my Android app, called Main.java, to validate a user login (user name + password) against the data in my server. At first, I succeeded; I used an AsyncTask thread to do it plus a library which handles the Http connection, call HttpPostAux.java (in fact, I found the library's code here in this forum). In the onPostExecute method of AsyncTask, I was creating and starting a new activity instead of modifying the current one and it worked.
But now I want to do things different. I want to save the validated data (user name + password) into a SQLite table in the AsyncTask thread and then in the UI thread, recover that data and use it to open the mentioned activity. The insertion occurs but when I'm trying to access the database from UI thread: it says that the table is empty. So I looked in the logcat and I found that UI thread executes before AsyncTask thread.
So my question is how to insert data in the AsyncTask thread and then recover it inside UI thread? Can anybody help here? I'm kind of lost!
I will appreciate a code example! Thanks in advance!
Greetings from Venezuela!
UI thread is your applications main thread. When you create an AsyncTask, your long time-taking task will be executed(inside doInBackground function) on a separate thread. When doInBackground completes, onPostExecute() will be called from the UI thread. So you simply need to execute your UI thread task(="recover that data and use it to open the mentioned activity") from inside onPostExecute().
I think the way you did it before is correct. I would recommend to make a sort of SplashScreen activity which checks if the user has been logged in before, i.e. if there is a username/password in the database. If this is the case, use this data to login the user and then proceed to your main activity. If the user hasn't been logged in before, promp them with a login screen, store this data for future use and continue to your main activity.
You can implement a BroadcastReciever in your UIThread that listens to Intents sent from your AsyncTask when the insert to the database is done.
fire from AsyncTask:
Intent intent = new Intent("DATABASE_INSERTION_DONE");
context.sendBroadcast(intent );
register in UiThread:
IntentFilter intentFilter = new IntentFilter("DATABASE_INSERTION_DONE");
registerReceiver(myIntentsReceiver, intentFilter);
class:
class MyIntentReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if ("DATABASE_INSERTION_DONE".equals(intent.getAction())) {
//do something
}
}
}
You have to keep in mind that once you start an AsyncTask, it will run on another thread and your UI thread will keep moving forward. For example:
x="foo";
new SampleAsyncTask().execute();
txtView.setText(x);
Class SampleAsyncTask extends AsyncTask<...>{
.....
public Void doInBackground(...){
//LOTS OF CALCULATIONS
x="bar";
}
}
Your txtView will most definitely show "foo" rather than "bar". To make sure that your AsyncTask is finished there are lots of options. You can call a method to start the rest of your operations in PostExecute of your AsyncTask. You can also use intents and a broadcastreceiver like Jelgh said. But my favorite is using a simple callback:
public class LoginActivity extends Activity implement SampleAsyncTask.asyncCallback{
#Override
protected void onCreate(Bundle savedInstanceState){
x="foo";
new SampleAsyncTask().execute();
Class SampleAsyncTask extends AsyncTask<...>{
asyncCallback mCallback;
public SampleAsyncTask(Context c){
mCallback; = (asyncCallback) c
}
public interface asyncCallback{
void servedMyPurposeYouCanGoOn();
}
public Void doInBackground(...){
//LOTS OF CALCULATIONS
x="bar";
mCallback.servedMyPurposeYouCanGoOn;
//REST OF THE WORK
}
}
}
#Override
public void servedMyPurposeYouCanGoOn(){
runOnUIThread(
//rest of the work
)
}
}
Despite similar question was asked, I have differnet situation:
My app consists mostly of a background Service. I want to start external activities and get results back.
I see several options:
Create dummy Activity and keep reference to it for using its startActivityForResult. This consumes quite a lot of memory, as we know.
Use Broadcast Intents instead of Android's results infrastructure: ask client activities to broadcast their results before closing. This kind of breaks the idea and not so performance-efficient.
Use Instrumentation directly - try to copy code from startActivityForResult into my Service.
Use Service interfaces - serialize and add AIDL connection to the Intent for starting an Activity. In this case Activity should call Service directly instead of providing result.
The third approach feels closer to Android for me, but I'm not sure if it's possible to do - Service does not have its Instrumentation, and default implementation seems to always return null.
Maybe you have any other ideas?
I’ve been thinking about this recently when implementing account authenticators with three-legged authorisation flows. Sending a result back to the service for processing performs better than processing it in the activity. It also provides a better separation of concerns.
It’s not that clearly documented, but Android provides an easy way to send and receive results anywhere (including services) with ResultReceiver.
I’ve found it to be a lot cleaner than passing activities around, since that always comes with the risk of leaking those activities. Additionally, calling concrete methods is less flexible.
To use ResultReceiver in a service, you’ll need to subclass it and provide a way to process the received result, usually in an inner class:
public class SomeService extends Service {
/**
* Code for a successful result, mirrors {#link Activity.RESULT_OK}.
*/
public static final int RESULT_OK = -1;
/**
* Key used in the intent extras for the result receiver.
*/
public static final String KEY_RECEIVER = "KEY_RECEIVER";
/**
* Key used in the result bundle for the message.
*/
public static final String KEY_MESSAGE = "KEY_MESSAGE";
// ...
/**
* Used by an activity to send a result back to our service.
*/
class MessageReceiver extends ResultReceiver {
public MessageReceiver() {
// Pass in a handler or null if you don't care about the thread
// on which your code is executed.
super(null);
}
/**
* Called when there's a result available.
*/
#Override
protected void onReceiveResult(int resultCode, Bundle resultData) {
// Define and handle your own result codes
if (resultCode != RESULT_OK) {
return;
}
// Let's assume that a successful result includes a message.
String message = resultData.getString(KEY_MESSAGE);
// Now you can do something with it.
}
}
}
When you start an activity in the service, create a result receiver and pack it into the intent extras:
/**
* Starts an activity for retrieving a message.
*/
private void startMessageActivity() {
Intent intent = new Intent(this, MessageActivity.class);
// Pack the parcelable receiver into the intent extras so the
// activity can access it.
intent.putExtra(KEY_RECEIVER, new MessageReceiver());
startActivity(intent);
}
And finally, in the activity, unpack the receiver and use ResultReceiver#send(int, Bundle) to send a result back.
You can send a result at any time, but here I've chosen to do it before finishing:
public class MessageActivity extends Activity {
// ...
#Override
public void finish() {
// Unpack the receiver.
ResultReceiver receiver =
getIntent().getParcelableExtra(SomeService.KEY_RECEIVER);
Bundle resultData = new Bundle();
resultData.putString(SomeService.KEY_MESSAGE, "Hello world!");
receiver.send(SomeService.RESULT_OK, resultData);
super.finish();
}
}
I think option 2 is the most idiomatic way on android. Using startActivityForResult from an Activity is a synchronous/blocking call, i.e., the parent activity waits and does not do anything until the child is done. When working from a Service and interacting with activities your primarily doing asynchronous/non-blocking calls, i.e., the service calls out for some work to be done and then waits for a signal to tell it that it can continue.
If you are using the android local service pattern then you can have your activities acquire a reference of the Service and then call a specific function after it has performed its work. Attempting your option 3 would be counter to what the framework provides for you.