I was looking for answer for hours but without result.
My app is using cameraCaptureSessions.setRepeatingRequest and saving/refreshing into TextureView privateTextureView.
I want to take a picture from TextureView -> apply filter using AsyncTask -> save it to the ImageView. But getting warning "unchecked call to execute(Params...) as a member of the raw type AsyncTask"
Application falls on button click(AsyncTask execute). Where am I wrong?
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
.
.
.
privateTextureView = (TextureView)findViewById(R.id.textureView);
privateTextureView.setSurfaceTextureListener(textureListener);
myTask = new ApplyFilterTask();
privateBtnGetCapture.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
pictureBitmap = privateTextureView.getBitmap();
//Start MyTask
myTask.execute(pictureBitmap);
}
});
}
protected class ApplyFilterTask extends AsyncTask<Bitmap, Bitmap, Bitmap> {
#Override
protected void onPreExecute() {
int color = Color.parseColor("#ffa500");
privateImageView.setColorFilter(color);
}
#Override
protected Bitmap doInBackground(Bitmap... bitmaps) {
Bitmap bmp = bitmaps[0];
try {
ImageFilters filter = new ImageFilters();
bmp = filter.applyContrastEffect(bmp, 5);
publishProgress(bmp);
} catch (Exception e) {
//System.out.println("Error!!!! " + e);
}
return bmp;
}
#Override
protected void onProgressUpdate(Bitmap... bm) {
System.out.println("TestProgress");
privateImageView.setImageBitmap(bm[0]);
}
/*
protected void onPostExecute(Bitmap... bm) {
System.out.println("TestExecude");
privateImageView.setImageBitmap(bm[0]);
}*/
}
The application failure mentioned by you seems to be due to multiple usages of the same AsyncTask. An Asynctask can be used only once. As mentioned in the official documentation :
The task can be executed only once (an exception will be thrown if a second execution is attempted.)
Your code creates a single myTask object that is used every time in the OnClick event listener. Instantiate a new AsyncTask everytime to avoid the application failures, as shown below.
privateBtnGetCapture.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
pictureBitmap = privateTextureView.getBitmap();
AsyncTask<Bitmap, Bitmap, Bitmap> myTask = new ApplyFilterTask();
//Start MyTask
myTask.execute(pictureBitmap);
}
});
The warning mentioned by the IDE is however a separate issue that has to do with the declaration of myTask. You seem to have declared myTask as AsyncTask and not as AsyncTask<Bitmap, Bitmap, Bitmap> or ApplyFilterTask. Change the declaration and the warning would disappear.
Instead of using a unique instance of ApplyFilterTask for all your tasks, you can create new instance every time you click on privateBtnGetCapture and that can be done easily this way:
privateBtnGetCapture.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
pictureBitmap = privateTextureView.getBitmap();
//apply the filter this way
new ApplyFilterTask().execute(pictureBitmap);
}
});
Related
I have the following code. My problem is, that I can't get the JSON.execute() to stop/cancel. I spend quite some time looking up possible answers but I wasn't able to find anything that really worked (e.g. JSON.cancel(true)). As soon as I turn the trackerswitch on, the AsnycTask starts running every 3 seconds just like it's supposed to. Is there a way to easily stop the AsyncTask from executing as soon as the trackerswitch is turned off?
private boolean tracking = false;
private Switch trackerswitch;
private final Timer timer= new Timer();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.table_layout);
final Handler handler=new Handler();
final int delay = 4000;
trackerswitch=findViewById(R.id.trackerswitch);
trackerswitch.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
NetworkAccess JSON = new NetworkAccess();
if(trackerswitch.isChecked()){
trackerswitch.setText("Tracking...");
tracking=true;
handler.postDelayed(new Runnable() {
#Override
public void run() {
NetworkAccess JSON = new NetworkAccess();
JSON.execute();
handler.postDelayed(this, delay);
}
},delay);
}
else{
tracking=false;
trackerswitch.setText("Start Tracking");
}
}
});
}
}
This is what's called in the network class:
public class NetworkAccess extends AsyncTask<Void, Void, Void> {
public ArrayList<String> alldata = new ArrayList<>();
public ArrayList<String> locationlist = new ArrayList<>();
int stride;
String data;
#Override
protected Void doInBackground(Void... voids) {//4B4ADC
SOME CODE WHICH ISN'T IMPORTANT FOR MY PROBLEM
alldata.addAll(elementlist);
locationlist.addAll(loctrack);
}
}
catch(IOException | JSONException e){
MainActivity.field1.setText(e.getClass().getCanonicalName());
}
return null;
}
#Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
MainActivity.field1.setText(String.format("%20s %20s", alldata.get(0), alldata.get(1)));
COUPLE MORE OF THESE SETTEXT COMMANDS TO FILL A TABLE WITH DATA
}
}
Thanks for your help!
handler.postDelayed() adds objects of the Runnable you provide to the message queue, to be run at the specified interval. You need to remove all the queued objects from the message queue in order to cancel the execution. Calling JSON.cancel(true) does not affect other objects that are already added to the queue.
You'll have to retain a reference to your Runnable implementation and then call handler.removeCallbacks(r) to prevent further executions. Instead of using an anonymous class in handler.postDelayed().
This documentation page sheds more light on the matter.
Also refer this page for what happens when you call cancel(true) on an AsyncTask.
I've created an interface which holds a reference to an interfaces instantiated from an activity.
This is the interface:
public interface Calback {
void fun();
}
This is the activity which instantiates the calback and binds it to asincktask.
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final TextView txt = findViewById(R.id.helloTxtv);
txt.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Calback call = new Calback() {
#Override
public void fun() {
Log.d("tag","text of destroyed activity: "+((TextView)findViewById(R.id.helloTxtv)).getText());
}
};
Worker worker = new Worker(call);
worker.execute();
}
});
}
}
What's strange is that using that calback I can access textview even if the activity was destroyed.
This is the code from asyncktask:
public class Worker extends AsyncTask<Void, Void, Void> {
private final Calback call;
public Worker(Calback call) {
this.call = call;
}
#Override
protected Void doInBackground(Void... voids) {
try {
sleep(5000);
Log.d("tag","done");
} catch (InterruptedException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
call.fun();
}
}
To ensure that the activity it's destroyed I've just rotated the screen.(But I've got the same result after starting another activity and finish the current one)
And here is the log result.
PS: I've used Android Studio 3.0
If you are able to access the text of the TextView after the parent Activity has been destroyed, then you have a memory leak.
However, I'm not convinced that is what is going on here. I think it is more likely that either the activity has not been destroyed, or the activity's state was persistent and you are now looking at the state in the new (reincarnated) activity.
Why? Because, it seems that the callback is being called via an onClick listener for the text view. And that can only occur if the specific text view is still visible. It can't be visible if it is a component of a destroyed activity.
Update
My small showcase is stored on Bitbucket
https://bitbucket.org/solvapps/animationtest
I have an Activity with a view in it. Contentview is set to this view.
public class MainActivity extends AppCompatActivity {
private MyView myView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
myView = new MyView(this);
setContentView(myView);
startMovie();
}
public void startMovie(){
MovieTask movieTask = new MovieTask(myView, this);
movieTask.doInBackground(null);
}
}
A MovieTask is an Asynctask and refreshes the view periodically.
But invalidate() doesn't refresh the view.
public class MovieTask extends AsyncTask<String, String, String> {
MyView drawingView;
MainActivity mainActivity;
public MovieTask(MyView view, MainActivity mainActivity){
this.mainActivity = mainActivity;
this.drawingView =view;
}
#Override
protected String doInBackground(String... strings) {
for(int i=20;i<100;i++){
drawingView.myBall.goTo(i,i);
publishProgress();
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return null;
}
#Override
protected void onProgressUpdate(String... values) {
super.onProgressUpdate(values);
mainActivity.runOnUiThread(new Runnable() {
#Override
public void run() {
Log.v("DEBUG_DRAW","in onProgressUpdate()");
drawingView.invalidate();
}
});
}
}
Can someone help ?
See how you are launching the AsyncTask:
public void startMovie() {
MovieTask movieTask = new MovieTask(myView, this);
movieTask.doInBackground(null);
}
You are manually calling a method inside some class called MovieTask, thus you are running a code on the same thread. Obviously, that is not your intention, you intended to run the computation code on a background thread.
Correct way to launch AsyncTask is using execute(Params...):
public void startMovie() {
MovieTask movieTask = new MovieTask(myView, this);
movieTask.execute("");
}
Now you will get the desired effect.
P.S.
Please, do not use that code: you do not need to launch a background thread in order to do that kind of stuff. As an alternative consider Animators API.
Declare setBall(int pos) method inside MyBall class:
public class MyView extends View {
...
public void setBall(int pos) {
myBall.setX(pos);
myBall.setY(pos);
invalidate();
}
}
Then change startMovie() to following:
public void startMovie() {
// "ball" means, that Animators API will search for `public setBall(int)` method inside MyView.java and call that method
ObjectAnimator ball = ObjectAnimator.ofInt(myView, "ball", 20, 100);
ball.setDuration(1000);
ball.start();
}
You'll get the same animation without a nasty code.
There is two possible case, first as described in documents:
void invalidate ()
Invalidate the whole view. If the view is visible,
onDraw(android.graphics.Canvas) will be called at some point in the
future.
So try to run your code in onResume, there is a chance that View is not visible yet.
Secondly View#invalidate tells the system to redraw the view as soon as the main UI thread goes idle. That is, calling invalidate schedules your view to be redrawn after all other immediate work has finished.
If you'd like to have your view updated periodically use Handler#postDelay or run it in a separate thread and use View#postInvalidate to update the View and trigger the call to onDraw.
So I'm just trying to create an Alert Dialog that is just a message (no buttons or titles). I want to display an alert dialog when a background task is running. The alert dialog will run on the UI thread.
Here's what I have done so far:
protected void onPreExecute() {
super.onPreExecute();
AlertDialog altDlg;
altDlg = new AlertDialog.Builder(AlertDialogActivity.this).create();
altDlg.setMessage("Retrieving Information. Please Wait");
altDlg.show();
}
I also tried doing this:
AlertDialog.Builder builder = new AlertDialog.Builder(this)
.setMessage("Retrieve Info. Please Wait").show();
The error I am getting with the first one is:
cannot find symbol 'AlertDialogActivity'
symbol: class AlertDialogActivity
location: class com.example.Device.Activity
The second attempt error says:
incompatible types: com.example.Device.Activity cannot be converted to android.content.Context
I'm not sure what I am doing wrong in either scenario. I just want to display a basic message when a background task is running and I was hoping the closest thing I can use is AlertDialog.
EDIT for how to set up AsyncTask properly:
Small background of what I want to do. I just want to read in a file, deserialize it and save it's contents to a db.
Right now I'm assuming I only need two activities.
One is my main activity:
public class MainActivity extends Activity {
/**
* Called when the activity is first created.
*/
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.setup);
final Button setup_button = (Button) findViewById(R.id.setup_button);
setup_button.setOnClickListener (new View.OnClickListener() {
public void onClick(View view){
setContentView(R.layout.retrieve_info);
}
});
}
}
Now the onClick event just moves to the new view that is supposed to display the message or alert dialog that says retrieving information. Please Wait. It displays the message while reading a file and saving to db. Once the file is read and saved, The message should disappear and say something like setup complete.
My second activity so far is:
public class RetrieveInfoActivity extends AsyncTask<Void,Void,Void> {
private ProgressDialog progressBar;
private void retrieveInfo(String fileName) {
try {
File file = new File(fileName);
Scanner scanner = new Scanner(file);
//Read all the lines until there are no more lines
while (scanner.hasNextLine()) {
scanner.nextLine();
//TODO: deserialize and save to db
}
scanner.close();
}
catch (FileNotFoundException e) { e.printStackTrace(); }
}
#Override
protected Void doInBackground(Void... params) {
retrieveInfo("test.txt");
return null;
}
protected void onPreExecute() {
super.onPreExecute();
progressBar.setIndeterminate(true);
progressBar.setCancelable(false);
progressBar.setMessage("Retrieve Information.Please wait");
progressBar.show();
}
#Override
protected void onPostExecute() {
progressBar.dismiss();
}
}
That's all I really have so far. I just need to understand how to set up this in Android conceptually.
Hope this makes sense.
Try this:
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
Instead of using an AlertDialog use a ProgressBar, it will do the trick for you.
private ProgressDialog progressBar;
#Override
protected void onPreExecute() {
super.onPreExecute();
progressBar.setIndeterminate(true);
progressBar.setCancelable(false);
progressBar.setMessage("Your message");
progressBar.show();
}
#Override
protected void onPostExecute(final String error_code) {
progressBar.dismiss();
}
Looks like you are extending AsyncTask and trying to use it as a context. That won't work as AsyncTask itself is nothing but an abstract class.
You need to create a custom constructor for your AsyncTask to fetch the Context:
public class MyTask extends AsyncTask<Void, Void, Void> {
private Context mCtx;
public MyTask(Context context) {
mCtx = context;
}
...
Then when starting your AsyncTask, pass the context:
new MyTask(this).execute();
Another way would be to make the AsyncTask an inner class and use YourActivity.this when creating the dialog. Example:
public class YourActivity extends Activity {
...
private class MyTask extends AsyncTask<Void, Void, Void> {
#Override
protected void onPreExecute() {
super.onPreExecute();
AlertDialog dialog = new AlertDialog.Builder(YourActivity.this).create();
}
#Override
protected Void doInBackground(Void... params) {
...
}
}
}
I would like to enable a few buttons from my main activity once the stuffs from doInBackground() is finished! Can someone please let me know how to do that?
I can't use findViewByID() for making he button visible from the AsyncTask class as it's not an activity class! :/
Do Like this...
Define a method which enables the Buttons.
Then on PostExecute() on AsyncTask, call that method
there is one callback onPostExecution(...) { } of AsynTask class use this method to UI stuff,for enable,disable button just write this way in onPostExcustion(...)
runOnUiThread(new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
}
});
also make sure this method only available in activity class
thank you
Follow this way:
[1] Create your AsyncTask :
public class performBackgroundTask extends AsyncTask<Void, Void, Void> {
ProgressDialog Dialog = new ProgressDialog(HotUsers.this);
protected void onPreExecute() {
Dialog.setMessage("Loading Hot Users...");
Dialog.show();
}
protected void onPostExecute(Void unused) {
if(Dialog.isShowing())
Dialog.dismiss();
set_details_on_screen();
}
#Override
protected Void doInBackground(Void... params) {
get_details_from_server(); // get data like userid,username,userdesc etc...
return null;
}
}
[2] That will call function to proceed for UI changes.
public void set_details_on_screen()
{
if(userid > 0 )
handler_default.sendEmptyMessage(0);
else
handler_default.sendEmptyMessage(1);
}
[3] At last your UI changes will be reflected on screen with this Handler.
private Handler handler_default = new Handler() {
public void handleMessage(Message msg) {
switch (msg.what) {
case 0: {
textuserid = (TextView) findViewById(R.id.userid);
textusername = (TextView) findViewById(R.id.username);
textuserdesc = (TextView) findViewById(R.id.userdesc);
textuserid.setText(userid);
textusername.setText(username);
textuserdesc.setText(userdesc);
break;
}
case 1: {
Toast.makeText(getApplicationContext(),"Error",Toast.LENGTH_LONG).show();
break;
}
}
}
};
Thanks.
your class which extends AsyncTask you can push your context into it, when calling the execute().
private class RegisterUser extends AsyncTask<String,String,String> {
private ListActivity activity;
public RegisterUser(ListActivity activity) {
this.activity = activity;
}
protected void onPostExecute(JSONObject json) {
activity.editText = (EditText)activity.findViewById(R.id.editText1);
//or
activity.enableButton();
}
}
and call the execute from the Activity like this:
new RegisterUser(this).execute(new String[] {"param"});
or you can define the AsyncTask class inside your Activity class - where you can reach everything.
more info Lars Vogel - Android Threads, Handlers and AsyncTask