I've 2 files: Core (extends Activity) and DwCore. I'm using AsyncTask in a Core subclass and I want to use Toast in DwCore subclass but I can't get properly the Core Context.
Core
class DwFiles extends AsyncTask<Void, Void, Long> {
protected Long doInBackground(Void... parms) {
long totalSize = 0;
dwCore.mainCounter(Core.this);
return totalSize;
}
}
DwCore subclass
public void mainCounter(Context c){
Integer count = 0;
for(int i=0;i<count;i++){
Toast.makeText(c, count.toString(), Toast.LENGTH_SHORT).show();
}
}
You can't do anything that affects the UI from worker threads - that includes showing toasts.
class DwFiles extends AsyncTask<Void, Void, Long> {
protected Long doInBackground(Void... parms) {
long totalSize = 0;
publishProgress(check_point);
return totalSize;
}
}
protected void onProgressUpdate(Integer integers) {
dwCore.mainCounter(Core.this);
}
public void mainCounter(Context c){
Integer count = 0;
for(int i=0;i<count;i++){
Toast.makeText(getActivity(), count.toString(), Toast.LENGTH_SHORT).show();
}
}
You can use getActivity() function or this.getActivity().
getActivity() can be used in a Fragment for getting the parent Activity of the Fragment (basically the Activity that displayed the Fragment).
can't be done as doInBackGround runs on a background thread which cant access the ui thread.
What you can do is ,Create an Custom interface implement it on your activity then push the ui related update from the onProgressUpdate().
Interface ProgUpdate{
void uiUpdate(int update)
}
BackGround theread :
ProgUpdate listener;
onProgressUpdate(Int i){
listener.uiUpdate(i)
}
Related
My code is
// Asynctask class to handle load data from database in background
private class SyncGetLocations extends AsyncTask<Void, Void, Void> {
#Override
protected void onPreExecute() {
super.onPreExecute();
mPrgLoading.setVisibility(View.VISIBLE);
mScrollView.setVisibility(View.GONE);
mToolbarView.setVisibility(View.GONE);
}
#Override
protected Void doInBackground(Void... voids) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// Get data from database
getLocationDataFromDatabase(mSelectedId);
return null;
}
… etc
Android studio report that this Asynctask class should be static else leaks might occur.
When change to static get a lots of errors like non-static methods and fields cannot be referenced from a static context.
I added:
MyActivity myactivity = new MyActivity();
myactivity.mPrgLoading.setVisibility(View.VISIBLE);
…
all look nice until I run application and get error because I try to access void fields.
Advices?
The problem is that when you make the inner class static you no longer have access to the Activity and its properties. One workaround would be to have a weak reference to your Activity inside the AsynkTask:
private static class YourTask extends AsyncTask<Void, Void, Void> {
private WeakReference<YourActivity> activityReference;
YourTask(YourActivity context) {
activityReference = new WeakReference<>(context);
}
#Override
protected String doInBackground(Void... params) {
return "task finished";
}
#Override
protected void onPostExecute(String result) {
YourActivity activity = activityReference.get();
if (activity == null || activity.isFinishing()) return;
activity.myVariable = "example";
TextView textView = activity.findViewById(R.id.textview);
textView.setText(result);
}
}
Anyway I think that creating the AsyncTask as a top level class instead of as an inner class would also solve your problem (as an inner class you have the risk of the class being alive more time than it needs to because of the AsyncTask).
I hate The application may be doing too much work on its main thread, skipped XXX frames.. warning, Also it degrades the users UI interaction experience. So trying it with proper way as android wants it to be...
MainActivity :
public class MainActivity extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener
{
public Button StartBg;
private static final String TAG = "TASK_FIRST";
private Handler mainHandler = new Handler();
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
StartBg = findViewById(R.id.StartBg);
StartBg.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View view)
{
ExampleRunner ExampleRunnerObj = new ExampleRunner(50000);
new Thread(ExampleRunnerObj).start();
}
});
}
}
When i keeps below class as inner class of MainActivity, It is able to access UI Components.
ExampleRunner :
public class ExampleRunner implements Runnable
{
int count;
public ExampleRunner(int count)
{
this.count = count;
}
#Override
public void run()
{
Handler threadHandler = new Handler(Looper.getMainLooper());
for(int i = 0; i < count; i++)
{
Log.d(TAG,"PERFORMING : "+i+"\n");
if(i == 25000)
{
threadHandler.post(new Runnable()
{
#Override
public void run()
{
// StartBg.setText("50k");
// OR RETURN SOMETHING..
}
});
}
}
}
}
But when i makes ExampleRunner as separate external class, it says StartBg can not be resolved...
So, How should I :
Make external java class which implements Runnable, Access Main Threads UI components...?
Or At least return something to mainActivity where i am starting it, so that from mainActivity i can access it?
Thanks in advance.
You need to pass the external class the Button as a reference:
public class ExampleRunner implements Runnable
{
int count;
Button startBg;
public ExampleRunner(int count, Button startBg) {
this.count = count;
this.startBg = startBg;
}
and create it with it:
ExampleRunner ExampleRunnerObj = new ExampleRunner(50000, StartBg);
then it will be able to use it in run().
Right now, the ExampleRunner is an anonymous class accessing the StargBg variable declared locally.
If, I right understood you, for your solution, AsyncTask it is good solution.
Check docs https://developer.android.com/reference/android/os/AsyncTask
Im using a webservice that get a data and stores in a String. I need to use this String but I cant take it. Global variables don't work in Threads. I'm using a traditional Thread new Thread() { public void run() {.
Example of AsyncTask:
public class Task extends AsyncTask<Params, Progress, String> {
// are you know how to use generic types?
protected String doInBackground(Params[] params){
// this code will run in seperate thread
String resultString;
return resultString;
}
protected void onPostExecute(String resultString){
// this code will call on main thread (UI Thread) in this thread you can update UI e.g. textView.setText(resultString);
}
}
Use LocalBroadcastManager to send and receive data.
This way you can avoid memory leak issues.
Here is code for activity
public class YourActivity extends Activity {
private void signal(){
LocalBroadcastManager.getInstance(YourActivity.this).registerReceiver(receiver, new IntentFilter("Your action name"));
Intent yourAction = new Intent(YourActivity.this, YourIntentService.class);
String string = "someData";
yourAction .putExtra("KEY_WITH_URL", string);
startService(yourAction);
}
private BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String string = intent.getStringExtra("KEY_WITH_ANSWER");
//Do your code
}
};
}
Here code for thread which download String or whatever
public class YourIntentService extends IntentService {
#Override
protected void onHandleIntent(Intent intent) {
// Download here
Intent complete = new Intent ("Your action name");
complete.putExtra("KEY_WITH_ANSWER", stringToReturn);
LocalBroadcastManager.getInstance(YourIntentService.this).sendBroadcast(complete);
}
}
You can use Thread instead of IntentService.
use a Handler created from the main thread. Then pass your data throuh it
use a weak reference of your activity in your thread; this way you can call directly the main thread - Activity.runOnUiThread(Runnable)
...
Activity activity = activityWeakReference.get();
if (activity != null && !activity.isFinishing() && !activity.isDestroyed()) {
activity.runOnUiThread(new Runnable() {
#Override
public void run()
{
// you are in main thread, pass your data
}
});
}
You can use Async task:
private class Whatever extends AsyncTask<Void, Void, String> {
protected String doInBackground(Void... void) {
// do your webservice processing
return your_string;
}
protected void onPostExecute(String result) {
// Retrieves the string in the UI thread
}
}
I have a main class
public class MainActivity extends Activity {
downloadTask downloadTask;
....
void updateProgress(int... progress) {
}
}
and an AsyncTask
public class downloadTask extends AsyncTask<Void, double[], Void> {
....
protected void onProgressUpdate(int... progress) {
}
}
Is there a way that I can set the onProgressUpdate & override it so that it uses updateProgress instead, from the MainActivity?
I'm aware I can create a new class that extends downloadTask and use #Override there. I'm just wondering if there's another way. For instance in javascript I could do something like
downloadTask.onProgressUpdate = updateProgress
Is something like this possible in java?
You can do something like this:
AsyncTask<Void, double[], Void> task = new AsyncTask<Void, double[], Void>(activity);
{
private WeakReference<Activity> activityReference;
public AsyncTask(Activity activity)
{
this.activityReference = new WeakReference<Activity>(activity);
}
protected void onProgressUpdate(int... progress)
{
Activity activity = activityReference.get();
if(activity != null)
{
activity.updateProgres(...);
}
}
}
Note that I use WeakReference inside the AsyncTask, this is very important to prevent memory leaks.
New programmer. Questions at the bottom.
I have an array of fleets that corresponds to vehicles. I would like to make successive calls to the server with each slot in my fleet array.
I wish to do this with an AsyncTask.
private class refreshTruckInformation extends AsyncTask<URL, Void, Void> {
#Override
protected void doInBackground(URL... urls) {
}
#Override
protected void onProgressUpdate(Integer... progress) {
}
#Override
protected void onPostExecute(Void... voids) {
}
}
**How do I pass in my array of fleets so that I can use them in my doInBackground?
I also want to have a progress bar that goes based on the percentage of fleets it has gone through. What is a good way to do this?**
Thanks!
**How do I pass in my array of fleets so that I can use them in my doInBackground?
Remember that refreshTruckInformation is still a class. So you can use any constructor or settier methods to pass your array.
I also want to have a progress bar that goes based on the percentage
of fleets it has gone through. What is a good way to do this?**
From your doInBackground method you can publis progress using publishProgress method. This progress parameter will be catched in onProgressUpdate method
For example
private class RefreshTruckInformation extends AsyncTask<URL, Void, Void> {
private int[] b;
public RefreshTruckInformation (int[] a){
// use array
b = a;
}
public void setArray(int[] a){
// use array
b = a;
}
#Override
protected void doInBackground(URL... urls) {
}
#Override
protected void onProgressUpdate(Integer... progress) {
}
#Override
protected void onPostExecute(Void... voids) {
}
}
And call using
RefreshTruckInformation r = new RefreshTruckInformation (yourArray);
or call method like
r.setArray(yourArray);
and execute like
r.execute();