I have a dialog which extends TrayDialog to collect some data from user. I want to pass the values collected to another class without closing the dialog. If I override the okPressed() method, data will be passed back but window will be closed.
public class MyDialog extends TrayDialog {
public MyDialog(final Shell shell, final MyData mydata) {
super(shell);
this.shell = shell;
this.mydata = mydata;
}
#Override
protected void okPressed() {
if (!validateData()) {
return;
}
super.okPressed();
}
//rest of the code for text box, buttons in the dialog
}
final MyDialog myDialog = new MyDialog(new Shell(), this.mydata);
if (myDialog.open() == Window.CANCEL) {
return null;
}
//here get the data that user has entered in the dialog after they press ok
If you don't call super.okPressed() dialog will not be closed. Source:
protected void okPressed() {
setReturnCode(OK);
close();
}
And in order to pass data back on okPressed action, I would suggest to provide a callback to MyDialog. Something like this:
public interface MyCallback {
void okPressed(MyData data);
}
public class MyDialog extends TrayDialog {
public MyDialog(final Shell shell, final MyData mydata, MyCallback callback) {
super(shell);
this.shell = shell;
this.mydata = mydata;
this.callback = callback;
}
#Override
protected void okPressed() {
if (!validateData()) {
return;
} else {
callback.onPressed(data);
}
//super.okPressed();
}
MyCallback callback = new MyCallback() {
void okPressed(MyData data) {
// handle data
}
}
final MyDialog myDialog = new MyDialog(new Shell(), this.mydata, callback);
if (myDialog.open() == Window.CANCEL) {
return null;
}
In this case you would need to manually close dialog at some point. Also, Dialog will not block the execution thread, if you use setBlockOnOpen(false);
Related
I've been trying to find a way to create a listener for a boolean on an android code reader. Essentially what I want to happen is, when it stops reading, perform action. So far I've based it off of this example, and have this:
Class:
public class scanStatusListener {
ScanManager scanManager;
private boolean scanStatus = scanManager.isReading(); //this returns if the reader is scanning or not
private ChangeListener listener;
public void setListener(ChangeListener listener) {
this.listener = listener;
}
public interface ChangeListener {
void onChange();
}
}
Activity:
public class ScanHook extends Service implements ScanManager.DataListener, scanStatusListener.ChangeListener{
private ScanManager _scanManager;
#Override
public void onCreate() {
super.onCreate();
_scanManager = ScanManager.createScanManager(getApplicationContext());
scanStatusListener ss = new scanStatusListener();
ss.setListener(new scanStatusListener.ChangeListener() {
public void onChange() {
//perform action
}
});
}
The issue I am getting is:
private boolean scanStatus = scanManager.isReading();
is getting an error saying that I cannot invoke on a null object reference.
I also tried using the LiveData suggestion:
MutableLiveData<Boolean> listen_bool=new MutableLiveData<>();
listen_bool.observe((LifecycleOwner) this, new Observer<Boolean>() {
#Override
public void onChanged(Boolean aBoolean) {
//perform action
}
});
listen_bool.setValue(_scanManager.isReading());
however I am getting an error saying I cannot cast to androidx.lifecycle.LifecycleOwner
Any suggestions?
I know this is a duplicate question but please hold on. I have read some similar questions and answer but none of them seems working for me.
What to do:
I have to do a search which will send a request to a web service and receive a response.
As i can't consume network on UI thread, I used AsyncTask.
What i tried:
I tried using task.execute() this returns immediately without even showing progressdialog box and i receive response as null (set in onPostExecute)
if i use task.execute.get() then it freezes screen and again no dialog box shows up (but i receive response correctly).
Below is my code with task.execute. Kindly correct me.
public class LookIn extends AppCompatActivity implements View.OnClickListener{
private Button btn=null;
private TextView txtPinCode=null;
private Service service=null;
private final static int timeout=20;
private String jsonResponse;
//private ProgressBar helperSearchProgressBar;
private String pincode="";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_look_in);
btn=(Button)findViewById(R.id.button);
btn.setOnClickListener(this);
txtPinCode=(TextView) findViewById(R.id.txtPinCode);
this.service=(Service) ParamFactory.getParam(ConstantLabels.SELECTED_SERVICE_ID);
// this.helperSearchProgressBar=(ProgressBar)findViewById(R.id.helperSearchProgressBar);
}
#Override
public void onClick(View v) {
String pincode= txtPinCode.getText().toString();
if(pincode==null || pincode.isEmpty() || pincode.length()!=6)
{
this.txtPinCode.setError("Please enter a 6 degit pin code from 700000 to 700200");
return;
}
ParamFactory.setParam(ConstantLabels.PINCODE_ID,pincode);
this.pincode=pincode;
loadHelper();
Intent intent= new Intent(LookIn.this,SearchResult.class);
startActivity(intent);
}
public void setJsonResponse(String jsonResponse)
{
this.jsonResponse=jsonResponse;
}
private void loadHelper()
{
Log.v("Callme", "Running thread:" + Thread.currentThread().getId());
ArrayAdapter<User> adapter=null;
String params=this.pincode+","+this.service.getId();
List<User> result=null;
try {
new CallmeGetHelperAsyncTask().execute(params); //my task.execute()
result= RestUtil.getUserList(jsonResponse);
adapter = new ArrayAdapter(this, android.R.layout.simple_list_item_1, result);
ParamFactory.setParam("getHelperForService", adapter);
}
catch(JSONException x)
{
Log.e("Callme", Log.getStackTraceString(x));
}
}
class CallmeGetHelperAsyncTask extends AsyncTask<String,Void,String > {
// private Context context=null;
private ProgressDialog dialog=null;
private String jsonResponse;
private LookIn activity;
public CallmeGetHelperAsyncTask(){}
public CallmeGetHelperAsyncTask(LookIn activity)
{
this.activity=activity;
}
#Override
protected void onPreExecute() {
this.dialog= new ProgressDialog(LookIn.this);
this.dialog.setMessage("Loading...");
this.dialog.show();
Log.v("Callme","Dialog Shown");
}
#Override
protected void onPostExecute(String s) {
if(s!=null)
{
this.activity.setJsonResponse(s);
}
else
{
Log.v("Callme","kill me");
}
if(this.dialog.isShowing())
{
Log.v("Callme","Closing Dialog");
this.dialog.dismiss();
}
}
#Override
protected String doInBackground(String... params) {
Log.v("Callme","From Background:"+Thread.currentThread().getId());
String pincode=params.clone()[0].split(",")[0];
String serviceId=params.clone()[0].split(",")[1];
String url=String.format(URL.GET_HELPER,serviceId,pincode);
jsonResponse= null;
try {
jsonResponse = RestUtil.makeRestRequest(url);
} catch (IOException e) {
e.printStackTrace();
}
return jsonResponse;
}
}
}
Note: I haven't tried using while loop to waiting for the asynctask, because i think that will also end up freezing my screen. Please correct me if i am wrong
I haven't tried using while loop to waiting for the asynctask
No need to use loop for waiting AsyncTask Result.
Because onPostExecute method execute after doInBackground so instead of using jsonResponse just after call of execute method, do it inside setJsonResponse method, because this method called from onPostExecute which always run on Main UI Thread:
public void setJsonResponse(String jsonResponse)
{
this.jsonResponse=jsonResponse;
//Create adapter object here
result= RestUtil.getUserList(jsonResponse);
adapter = new ArrayAdapter(...);
ParamFactory.setParam("getHelperForService", adapter);
}
I have an AsyncTask class SearchForQuestions that is called from an Activity QuizMap. When looping through an array in SearchForQuestions I can't find the correct context for toast to appear within the AsynTask.
The standard Toast.makeText(getApplicationContext(), "This is Toast!!!", Toast.LENGTH_SHORT).show(); gives error getApplicationContext() undefined.
I have tried some of the solutions to this offerred by SO, most of them are listed here and concern getting UiThread and running on that.
I can't get this to work however. Here's example code snippets of what i have tried. I have put a method in QuizMap and try calling it from SearchForQuestions but SearchForQuestions isn't recognised. How can I get around this? )Still a newbie at java...)
// QuizMap activity
public class QuizMap extends FragmentActivity
implements OnMarkerClickListener {
private GoogleMap map;
private static final String TAG = "QuizMap"; // debugging
...
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_quizmap);
map = ((SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map))
.getMap();
...
}
// make toast inside AsyncTask
public void showNotNearToast(final String toast) {
QuizMap.this.runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(QuizMap.this, "This is Toast!!!", Toast.LENGTH_SHORT).show();
}});
}
.
// SearchForQuestions class
private class SearchForQuestions extends AsyncTask<String, Void, DataHandler> {
// checks for proximity to question locations
Location location =
locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
#Override
protected DataHandler doInBackground(String... pointsList) {
String result = pointsList[0];
...
}
#Override
protected void onPostExecute(DataHandler result) {
ArrayList<String> resultsArray = result.results;
Integer numPoints = resultsArray.size();
for (int i =0;i<numPoints;i++){
String[] pointDetails = resultsArray.get(i).split("::");
...
// we can make use of the Android distanceTo function to calculate the distances
float distance = location.distanceTo(fixedLoc);
if (i > DIST) { // this is UCL
showNotNearToast("My Message"); // showNotNearToast undefined
if (distance < DIST) {
...
}
};
I'm going t close this question. I haven't solved my problem but the number of answers provided that apparently work in other situations suggest there's something else going on. I'm going to re-structure the classes to get around having to call from within AsyncTask.
Just Toast it, why do you want to create a function for it? onPostExecute() is already on UI thread.
You are not able to access because inner Class can not call functions of Outer class unless you pass instance of the outer class.
Call your toast in onPostExecute
Create an interface for a callback.
public interface ToastCallback {
public void invoke(String text);
}
Your AsyncTask constructor
private ToastCallback toastCallback;
public SearchQuestions(ToastCallback callback) {
this.toastCallback = callback;
}
// in doInBackground() {
toastCallback.invoke("Toast from background");
}
In Your Activity,
private void showNotNearToast(String text) {
runOnUiThread(new Runnable() {
#Override
public void run() {
Toast.makeText(getApplicationContext(), text, Toast.LENGTH_SHORT).show();
}
});
}
public class MyToastCallback implements ToastCallback {
#Override
public void invoke(String text) {
showNotNearToast(text);
}
}
// Asynctask call
new SearchQuestion(new MyTosatCallback()).execute(<Your params here>);
Try this from inside your AsyncTask:
myActivity.this.runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(activity, "Hello", Toast.LENGTH_SHORT).show();
}
});
Where you have your
showNotNearToast("My Message"); // showNotNearToast undefined
Replace myActivity with the name of your Activity.
(Ab)use the publishProgress method
private class ToastAsyncTask extends AsyncTask<Void, String, Void>{
#Override
protected Void doInBackground(Void... voids) {
SystemClock.sleep(1000);
publishProgress("Toast msg string");
SystemClock.sleep(1000);
return null;
}
#Override
protected void onProgressUpdate(String... values) {
Toast.makeText(getApplicationContext(), values[0], Toast.LENGTH_SHORT).show();
}
}
**UPDATE: ** since you are having problems with context for some reason, use this version. Tough the implementation above works for me.
private class ToastAsyncTask extends AsyncTask<Void, String, Void> {
private WeakReference<Context> contextRef;
public ToastAsyncTask(Context context) {
contextRef = new WeakReference<Context>(context);
}
#Override
protected Void doInBackground(Void... voids) {
SystemClock.sleep(1000);
publishProgress("Toast msg string");
SystemClock.sleep(1000);
return null;
}
#Override
protected void onProgressUpdate(String... values) {
if (contextRef.get() != null) {
Toast.makeText(contextRef.get(), values[0], Toast.LENGTH_SHORT).show();
} else {
// The context was destroyed.. check what you are doing
}
}
}
Use it like this
new ToastAsyncTask(MainActivity.this).execute();
Pass the activity into the AsyncTask. See below.
private class SearchForQuestions extends AsyncTask<String, Void, DataHandler> {
Activity activity;
public void SearchForQuestions(Activity activity){
this.activity = activity;
}
//... rest of the code
public class QuizMap extends FragmentActivity implements OnMarkerClickListener {
/*...*/
new SearchForQuestions(this).execute();
/*...*/
/*When calling the toast:*/
Toast.makeText(this.activity, "This is Toast!!!", Toast.LENGTH_SHORT).show();
I have a dialog that adds items to a listview, and when an item is added I need to reset the list adapter (because if not things get weird).
I read here that I can create an event listener and listen to it in the main activity. I tried doing so but it gives me errors.
AddMovieDialog.java:
public class AddMovieDialog extends DialogFragment {
private OnFinishListener onFinishListener;
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
builder.setView(inflater.inflate(R.layout.add_movie_dialog, null))
.setTitle("Add a movie")
.setPositiveButton("Add", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
// stuff
if (!movieName.isEmpty()) {
// stuff
if (AddMovieDialog.this.onFinishListener != null)
AddMovieDialog.this.onFinisheListener.finish();
}
}
});
// Create the AlertDialog object and return it
return builder.create();
}
public void setOnFinishListener(OnFinishListener listener) {
this.onFinishListener = listener;
}
public interface OnFinishListener {
void finish();
}
}
In the MainActivity:
AddMovieDialog addMovieDialog = new AddMovieDialog();
addMovieDialog.setOnFinishListener(new OnFinishListener() {
public void finish() {
}
});
But it gives me a compilation error: "The method setOnFinishListener(new OnFinishListener(){}) is undefined for the type AddMovieDialog"
You need to call a method which is non-static using the object. You can't call it using just the class name.
Change to this
AddMovieDialog addMovieDialog = new AddMovieDialog();
addMovieDialog .setOnFinishListener(new OnFinishListener() {
public void finish() {
}
});
Also shouldn't
if (AddMovieDialog.this.onCloseListener != null)
AddMovieDialog.this.onCloseListener.finish();
be
if (AddMovieDialog.this.onFinishListener != null)
AddMovieDialog.this.onFinishListener.finish();
EDIT
Seem your import statement in MainActivity is wrong. It should be something like com.yourpackagename.AddMovieDialog.OnFinishListener
Basically I have a loading splash screen which will be executed when button was clicked:
public void onClick(View v) {
// Load the loading splash screen
Intent loadingIntent = new Intent(context, LoadingScreen.class);
context.startActivity(loadingIntent);
}
});
And in the LoadingScreen class:
public class LoadingScreen extends Activity{
//A ProgressDialog object
private ProgressDialog progressDialog;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
//Initialize a LoadViewTask object and call the execute() method
new LoadViewTask().execute();
}
//To use the AsyncTask, it must be subclassed
private class LoadViewTask extends AsyncTask<Void, Integer, Void>
{
//Before running code in separate thread
#Override
protected void onPreExecute()
{
progressDialog = ProgressDialog.show(LoadingScreen.this,"Getting routes...",
"Loading data, please wait...", false, false);
}
//The code to be executed in a background thread.
#Override
protected Void doInBackground(Void... params)
{
try
{
//Get the current thread's token
synchronized (this)
{
//Initialize an integer (that will act as a counter) to zero
int counter = 0;
//While the counter is smaller than four
while(counter <= 4)
{
//Wait 850 milliseconds
this.wait(750);
//Increment the counter
counter++;
//Set the current progress.
//This value is going to be passed to the onProgressUpdate() method.
publishProgress(counter*25);
}
}
}
catch (InterruptedException e)
{
e.printStackTrace();
}
return null;
}
//Update the progress
#Override
protected void onProgressUpdate(Integer... values)
{
//set the current progress of the progress dialog
progressDialog.setProgress(values[0]);
}
//after executing the code in the thread
#Override
protected void onPostExecute(Void result)
{
finish();
//close the progress dialog
progressDialog.dismiss();
}
}
}
With these codes, the loading splash screen did came out. But I wonder is there any other way to show only the pop out dialogue for loading progress bar which on top on my previous screen?
Let's say my previous screen was event details. Then when user selected the button, only the dialogue box with loading progress bar will be shown instead of a new intent with a dialogue box.
Any ideas? Thanks in advance.
EDIT
public void onClick(View v) {
// Load the loading splash screen
new LoadViewTask().execute();
ENeighbourhoodActivity.tvDirection.setText("");
eventModel.setEventX(String.valueOf(eventModel.getEventX()));
eventModel.setEventY(String.valueOf(eventModel.getEventY()));
new GetEventDirectionAsyncTask(new GetEventDirectionAsyncTask.OnRoutineFinished() {
public void onFinish() {
//Hide the callout and plot user location marker
ENeighbourhoodActivity.callout.hide();
EventController.getUserLocation(context);
getActivity().finish();
}
}).execute(eventModel);
}
});
public class GetRegisteredEventAsyncTask extends
AsyncTask<String, Integer, Double> {
static EventController eventCtrl = new EventController();
public static ArrayList<Event> upcomingModel = new ArrayList<Event>();
public static ArrayList<Event> pastModel = new ArrayList<Event>();
public interface OnRoutineFinished { // interface
void onFinish();
}
private OnRoutineFinished mCallbacks;
public GetRegisteredEventAsyncTask(OnRoutineFinished callback) {
mCallbacks = callback;
}
public GetRegisteredEventAsyncTask() {
} // empty constructor to maintain compatibility
#Override
protected Double doInBackground(String... params) {
try {
upcomingModel = eventCtrl.getRegisteredUpcomingEvent(params[0]);
pastModel = eventCtrl.getRegisteredPastEvent(params[0]);
} catch (JSONException e) {
e.printStackTrace();
}
return null;
}
protected void onPostExecute(Double result) {
if (mCallbacks != null)
mCallbacks.onFinish(); // call interface on finish
}
protected void onProgressUpdate(Integer... progress) {
}
}
In your onClick() method you could write something like:
new LoadViewTask().execute();
and the progress dialog will be shown in that page itself.
what are you doing man, just call your AsyncTask not the intent
public void onClick(View v)
{
new LoadViewTask().execute();
}
});
do your intent in postExecute
#Override
protected void onPostExecute(Void result)
{
finish();
//close the progress dialog
progressDialog.dismiss();
//START YOUR ACTIVITY HERE
Intent loadingIntent = new Intent(context, LoadingScreen.class);
context.startActivity(loadingIntent);
}
Must read the documentation of AsynTask