get value of a variable “outside” of a callback in android - android

There is a String message as a parameter in an interface method:
public class Home extends AppCompatActivity {
private String globalStringResult = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.home_activity);
getMediaInfo();
Log.d("Result: ", globalStringResult); // Here result is Null
}//TODO OnCreate End
private void getMediaInfo() {
FFmpeg.getInstance(this).execute(new String[]{"-version"},
new ExecuteBinaryResponseHandler() {
#Override
public void onSuccess(String message) {
globalStringResult = message;
}
});
}
}
Here is this problem that I've faced many times but always ran from it. Now I want to deal with it if you help me.
I am executing getMediaInfo() method inside onCreate. When I log the result inside onCreate after getMediaInfo() execution , the result would be null. But if I run it inside an onClick button or something I get my desired result.
Is there any way that I could return callback message anywhere that I want?

Sounds like your function getMediaInfo is asynchronous which means it could take some time before the onSuccess block is called and your value is set. Instead of relying on a variable I would suggest to use a callback function. That way your message will be passed to the callback function and you could use it anywhere.
public interface MyCallback{
void success(String message);
}
Then you would need to modify your function as follows. Then where ever the callback is implemented you will receive the message and you can act on the value.
public void getMediaInfo(MyCallback callback){
FFmpeg.getInstance(this).execute(cmdArray, new ExecuteBinaryResponseHandler() {
#Override
public void onSuccess(String message) {
callback.success(message);
}
});

If your further actions depend on the value set in onSuccess callback then simply call a function from this callback method. You need to provide more info on what exactly you are trying to do with this variable.

Asynchronous calls can be tricky but you have to wait until it is finished before the variable is available. This means calling any methods that rely on the variable in the callback of the async call. There's really no way around it. You may want to make two version of the call; one for onCreate and one when you need to call it from other places.
public class Home extends AppCompatActivity {
private String globalStringResult = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.home_activity);
getMediaInfoOnCreate();
// move any code below this line into the new method
}//TODO OnCreate End
private void getMediaInfo() {
FFmpeg.getInstance(this).execute(new String[]{"-version"},
new ExecuteBinaryResponseHandler() {
#Override
public void onSuccess(String message) {
globalStringResult = message;
codeThatNeedsToBeRunDuringOnCreateButAfterSettingGlobalStringResult();
}
});
}
private void getMediaInfoOnCreate() {
FFmpeg.getInstance(this).execute(new String[]{"-version"},
new ExecuteBinaryResponseHandler() {
#Override
public void onSuccess(String message) {
globalStringResult = message;
}
});
}
private void codeThatNeedsToBeRunDuringOnCreateButAfterSettingGlobalStringResult() {
// put your moved code from onCreate here
Log.d("Result: ", globalStringResult); // Here correct result will be logged
}
}

Related

Detect if Firebase has read from the database in Android?

I'm playing around with Firebase and Android and I'm storing my data online in Firebase. I have an activity with 3 EditTexts and a button and I want it to essentially check that the 3 values in the textboxes are in the database and if so, move onto the next activity.
These values are static and so I'm using the .addListenerForSingleValueEvent method and using it as an anonymous function. I want this to work even if the device is offline but if any of the values come back as null then I want it to reject moving to the next activity.
Is there any way to detect when Firebase has either retrieved a value from the database or retrieved null from the database? This way I could check each value consecutively and if any return null then reject changing activities.
The only other thing I could think to do is to nest the anonymous functions for each listener but that sounds like it would be a bad idea.
Any advice would be much appreciated. Thanks!
Well, i understand you want to check for values in your database before moving to the next activity. My advice is that
1) create an ArrayList of DatabaseReference that point to the data locations in firebase in your activity.
Arraylist<DatabaseReference> list = new ArrayList<>();
list.add(FirebaseDatabase.getInstance().getReference().child("my_child_node_1"):
list.add(FirebaseDatabase.getInstance().getReference().child("my_child_node_2"):
list.add(FirebaseDatabase.getInstance().getReference().child("my_child_node_3"):
2) create an interface and a call back method.
public static interface DataCallback {
static void onDataAdded(String string); //Use the necessary data type
}
3) use the interface to create a constructor for your Event listener.
public static class DataListener implements ValueEventListener {
private DataCallback dataCallback;
public DataListener(DataCallback dataCallback) {
this.dataCallback = dataCallback;
}
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
String data = snapshot.getValue(String.class);
//This is step 4
if(dataCallback!=null) {
dataCallback.onContactAdded(data);
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
}
4) Pass the value from the listener to your activity as follows inside onDataChange() method of the Listener
if(dataCallback!=null) {
dataCallback.onContactAdded(data);
}
5) implement the interface in your activity and override its callback method
public class MyActivity extends AppCompatActivity implements DataCallback{
private EditText edittext1;
private EditText edittext2;
private EditText edittext3;
private ArrayList<String> my_list;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//do stuff...
}
#Override
public void onDataAdded(String data) {
}
}
6) Instantiate and add the listener in your activity's onResume() method
#Override
public void onResume(){
super.onResume();
DataListener listener = new DataListener(this);
list[0].addListenerForSingleValueEvent(listener);
list[1].addListenerForSingleValueEvent(listener);
list[2].addListenerForSingleValueEvent(listener);
}
7) get the values from firebase in your activity inside the Callback method as follows
#Override
public void onDataAdded(String data){
my_list.add(data);
}
8) you can check if the values gotten from firebase match the values gotten from the EditText inside the OnClicklistener for you button.
if (button != null) {
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(my_list.contains(edittext1.getText().toString)){
if(my_list.contains(edittext.getText().toString)){
if(my_list.contains(edittext.getText().toString)){
startActivity(new intent(MyActivity.this, NextActivity.class))
}
}
}
}
});
}
9) remove the listeners inside the onPause() method.
#Override
public void onPause(){
super.onPause();
list[0].removeEventListener(listener);
list[1].removeEventListener(listener);
list[2].removeEventListener(listener);
}

Otto Subscribe method not called from Activity to Fragment in Another Activity

This is my first activity where Im making a post call. The bus provider is the default one in the otto sample app.
void openNextActivity()
{
manager.bus.post("Hi");
// Intent to my next Activity
}
This is my fragment in another activity where im subscribing for the data. The bus received is the same, however the subscribe method is not being called.
public class ProductListFragment extends BaseFragment {
String LOG_TAG = ProductListFragment.class.getCanonicalName();
public static ProductListFragment newInstance() {
ProductListFragment fragment = new ProductListFragment();
return fragment;
}
public ProductListFragment() {
// Required empty public constructor
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getActivity().invalidateOptionsMenu();
}
#Override
public void onResume() {
super.onResume();
BusProvider.getInstance().register(this);
}
#Override
public void onPause() {
super.onPause();
BusProvider.getInstance().unregister(this);
}
#Subscribe public void onPostRecived(String s) {
Log.d(LOG_TAG, s);
}
}
There are no errors on anything being received, however if I put a button onclick on the fragment and post some content from there, the subscribe method is being called. For eg.
#OnClick(R.id.makePostCall) void call() {
BusProvider.getInstance().post("Hi");
}
I'm getting the appropriate log on this call. Any idea where the code is going wrong?
it seems you subscribe your second activity's fragment after sending stuff to event bus. Consider changing your logic
u send msg before intent;the BusProvider id registered after intent;
just try:
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
BusProvider.getInstance().post("Hi");
}
},3000);

how to execute functions (with parameter )in parallel using AsyncTask in android

I am writing an Android app in which I made functions for each task to execute,
but at some point I wanted to have 3 functions that should start the execution in parallel. I know about AsyncTask class (it can execute task in parallel) but I am not sure how to implement it in my code. Below is my code design....(raw code)
public class MainActivity extends Activity implements OnClickListener {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
function101();
function103(String ef); // this 2 function should execute in parallel
}
private void function101(){
// some code
}
private void function102(String ab, int cd){
function101();
function103( String ef); // i want this 2 function should execute in parallel
}
private void function103(String ef){
// some code
}
private void function104(){
function101();
function102(String ab, int cd);
function103(String ef);
}
}
You need to have 2 or more instance of Asynctask depending on your needs.
public void function101(){
new AsyncTask<Void,Void,Void>(){
#Override
protected Void doInBackground(Void... params) {
// code here
return null;
}
}.execute();
}
And your other function Although it is should be called as method
public void function103(String ef){
new AsyncTask<Void,Void,Void>(){
#Override
protected Void doInBackground(Void... params) {
// code here
return null;
}
}.execute();
}

Pass different type as activity

I have several activities that need to perform HTTP requests (send a JSON request a get another JSON object back).
My idea was to share one AsyncTask for all these requests. I am passing the Activity as a parameter so that I can call method once the execution of the request is finished.
I would like to pass one more parameter to my AsyncTask that would be the class of my Activity (MainActivity.class, SecondActivity.class) and then use that information to cast the Activity to the correct type and then later call on the method (would be the same method name for all activities).
I could also create an interface with my call back method, but I am not sure if I that would work neither.
Could this work or is my approach wrong here ?
Thanks for your feed-back.
My code:
public class HTTPReq extends AsyncTask {
private MainActivity callerActivity;
#Override
protected String doInBackground(Object... params) {
String data = (String) params[0];
String cookie = (String) params[1];
callerActivity = (MainActivity) params[2];
...
}
#Override
protected void onPostExecute(String result) {
callerActivity.ProcessHTTPReqAnswer(result);
super.onPostExecute(result);
}
}
Aswins answer isn't terrible but it's still not the most efficient way.
Declare an Interface that has a method for callback. Pass an instance of that interface to your asynctask then have the async task invoke it if its there as per my examples below
Interface:
public interface IMyCallbackInterface {
void onCallback(String result);
}
Async Task:
public MyAsyncTask extends AsyncTask<..., String> {
private IMyCallbackInterface mCallback;
public MyAsyncTask(..., IMyCallbackInterface callback) {
mCallback = callback;
}
protected String doInBackground(Object... params) {
....
}
protected void onPostExecute(String result) {
super.onPostExecute(result);
if (mCallback != null) {
mCallback.onCallback(result);
}
}
Activity:
public MyActivity extends Activity {
private void someMethod(){
new MyAsyncTask(..., new IMyCallbackInterface() {
public void onCallback(String result) {
//TODO use the result to do whatever i need
//I have access to my aactivity methods and member variables here
}
}.execute();
}
}
It is a wrong approach to do it like that. You should use BroadcastReceiver. Once a AsyncTask is done, sent the result out as a Broadcast. Each of the activity will be listen to the results they are interested in. This way no one needs to keep a reference to the activity which is dangerous.
Here is an example.
IntentFilter filter = new IntentFilter();
filter.addAction("result1");
LocalBroadcastManager.getInstance(getSupportActivity()).registerReceiver(new CustomBroadcastReceiver(), filter);
In the AsyncTask, do this
#Override
protected void onPostExecute(String result) {
Intent intent = new Intent("result1").putExtra(
"data", result);
LocalBroadcastManager.getInstance(getSupportActivity()).sendBroadcast(intent);
super.onPostExecute(result);
}
Back in the activity, do this
private class CustomBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Bundle bundle = intent.getExtras();
if ("result1".equalsIgnoreCase(intent.getAction())) {
String result = bundle.getString("data");
// Process the result here.
}
}
}

Notify asyncTask progress via callback to main class

I have asyncTask class:
public class DownloadJar {
public DownloadJar(String serialnum)
{
if (serialnum!=null)
{
this.serialnum = serialnum;
new Download().execute();
}
}
private class Download extends AsyncTask<String, Integer, String>
{
#Override
protected String doInBackground(String... params) {
//Downloading stuff
return null;
}
#Override
protected void onProgressUpdate(Integer... values) {
//Need to notify main class
super.onProgressUpdate(values);
}
}
}
I activate it via main class:
public class FTPDownload extends Activity{
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_ftpdownload);
Bundle extras = getIntent().getExtras();
if (extras != null)
{
serialnum = extras.getString("serialnum");
}
if (serialnum!=null)
{
DownloadJar dj = new DownloadJar(serialnum);
}
}
}
How can I create callback from the DownloadJar to notify my main class about the progress?
If you need onProgressUpdate() inside your main class, override it there. like,
DownloadJar dj = new DownloadJar(serialnum){
#Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
}
};
Pass a handler created in the activity along with the serialnumString in the constructor of the DownloadJar Async and call it like this from your onProgressUpdate:
handler.sendEmptyMessage(0);
where you can pass data through messages from your AsyncTask, you can receive the events in your Activity like this
handler = new Handler() {
#Override
public void handleMessage(Message msg) {
//do something
}
};
For further info: http://www.vogella.com/articles/AndroidBackgroundProcessing/article.html
You can create interface ie:
interface UpdateProgress {
void progressUpdate(String s)
}
make your class FTPDownload (its your main class?) implement it. Then when creating DownloadJar, pass reference to your activity to it. Then you can call in onProgressUpdate from your DownloadJar.Download asynctask progressUpdate on main activity. You must remember to update this reference on configuration changes.
If on the other hand DownloadJar is your main class, then you already have access to it, your asynctask is internal to it.
you have make Interface so that you can set data in that interface method from onPostExecute method of AsyncTask. and pass interface method as Anonymous inner class as like onClickListner.
here you can find nice explanation.

Categories

Resources