Android calling class functions from second class - java

How can I call a function defined in class#A from class#B? Class#B extends AsynchTask and fetches remote data from a web service. The class#A function I am attempting to call from class#B is used to send the retrieved remote data for Class#A to display.
I am trying to pass the current instance of class#A to class#B using this but that just passes the context so the functions are not recognized.
I also tried using static but as the function runs a new thread, defining the function as static generates a compiler error.
The code I am trying to call is as follows:
public void test(List<DATA> Data){
this.Data = Data;
runOnUiThread(new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
for(DATA data : MainActivity.this.Data){
Toast.makeText(MainActivity.this, data.title, Toast.LENGTH_SHORT).show();
}
}
});
}

This is how you would do it:
In MainActivity:
ClassBAsyncTask mat = new ClassBAsyncTask(this, .., ..);
ClassBAsyncTask's contructor:
public ClassBAsyncTask(MainActivity context, .., ..) {
mContext = context;
....
....
}
To call MainActivity's method test(List<DATA>) from within ClassBAsyncTask:
((MainActivity)mContext).test(yourListVariable);
Look into weak references to make sure that the AsyncTask does not use mContext when the activity no longer exists.

From your question, I understood that u want to show the result of asynctask in another class. You can use onProressUpdate api of asynctask. You can do the work in doInBackground and then call publishProgress(value) whihc in turn calls onProgressUpdate and run on UI thred.
private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
protected Long doInBackground(URL... urls) {
int count = urls.length;
long totalSize = 0;
for (int i = 0; i < count; i++) {
totalSize += Downloader.downloadFile(urls[i]);
publishProgress((int) ((i / (float) count) * 100));
// Escape early if cancel() is called
if (isCancelled()) break;
}
return totalSize;
}
protected void onProgressUpdate(Integer... progress) {
setProgressPercent(progress[0]);
}
Other way:
You can define a handler in class#A and call it from class#B
Sorry if i mis understood your question.

as I understand you start from A an AsyncTask B, cause web fetching only works in async way in Android. You want the result of the fetch to be accessible for an object in A.
A would code something like this.
public class A extends FragmentActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
TextView fetch = (TextView) findViewById(R.id.fetch);
new B(getApplicationContext(),fetch).execute();
// This will update a TextView when fetching is done.
}
}
public class B extends AsyncTask<Void, Integer, Void> {
Context c;
TextView f;
public B(Context c, TextView f) {
super();
this.f = f;
this.c = c;
}
#Override
protected Void doInBackground(Void... params) {
// TODO: the fetching: fetch()
String t = fetch();
f.setText();
return null;
}
}
You can do other tricks with pre and post execute methods. I hope I could help!

You can make an interface ie.:
public interface RecieveDataDelegate {
public void receiveData(Object dataFromWebService, boolean success);
}
Have Class#A implement the interface. And when calling the asyncTask from Class#A pass itself to a contructor for the AsyncTask that has a parameter of type ReceiveDataDelegate.
new AsyncTask1 (this).execute();
And setup AsyncTask with a constructor and send data back to Class#A onPostExecute() so you can update ui.
class AsyncTask1 extends AsyncTask<Void, Void, Boolean> {
Object dataReceived ;
protected RecieveDataDelegate delegate;
public AsyncTask1 (RecieveDataDelegate delegate) {
this.delegate = delegate;
}
protected Boolean doInBackground(Void... params) {
//do your service request and set dataRecieved
}
protected void onPostExecute(Boolean result) {
super.onPostExecute(result);
delegate.RecieveDataDelegate (dataReceived, result.booleanValue());
}
That way any class that implements the interface can use the same asyncTask.

Related

Update ListView asynchronously using Realm

My applications hang for a bit when I populate data from realm database to my listview.
So I planned to do it using Asynchronously so meanwhile data is collected I display a Loading dialogue here is the Code.
Already referred to this question by not able to implement in my case.
private class YourAsyncTask extends AsyncTask<String, String, RealmResults> {
ProgressDialog progressDialog;
#Override
protected void onPreExecute() {
// start loading animation maybe?
progressDialog = ProgressDialog.show(DictionarySscWords.this,
"ProgressDialog",
"Loading all words!");
}
#Override
protected RealmResults doInBackground(String... params) {
RealmConfiguration realmConfig = new RealmConfiguration.Builder(context).build();
Realm.setDefaultConfiguration(realmConfig);
realm = realm.getDefaultInstance();
RealmQuery<Word> query = realm.where(Word.class);
for (int i = 0; i < words_for_ssc[Integer.parseInt(params[0])].length; i++) {
if (i == words_for_ssc[Integer.parseInt(params[0])].length - 1) {
query = query.equalTo("word", words_for_ssc[Integer.parseInt(params[0])][i]);
} else {
query = query.equalTo("word", words_for_ssc[Integer.parseInt(params[0])][i])
.or();
}
}
sscresult = query.findAll(); //error 1
return sscresult;
}
#Override
protected void onPostExecute(RealmResults r) {
progressDialog.dismiss();
list.setAdapter(new MyAdapter(sscresult)); //error 2
realm.close();
}
}
ok so there are two problems if anyone can be solved my application would be error-free
if I try to run list.setAdapter(new MyAdapter(sscresult)); in background process the error is:-
this can run only in UI thread
if try to run in postExecute error is :-
Realm access from incorrect thread. Realm objects can only be accessed on the thread they were created.
I am not able to solve this issue please help
You can have your query evaluated on a background thread using asynchronous query API in Realm.
private OrderedRealmCollectionChangeListener<RealmResults<User> callback = new OrderedRealmCollectionChangeListener<>() {
#Override
public void onChange(RealmResults<User> results, OrderedCollectionChangeSet changeSet) {
if (changeSet == null) {
// The first time async returns with an null changeSet.
} else {
// Called on every future update.
}
}
};
private RealmResults<User> result;
public void onStart() {
result = realm.where(User.class).findAllAsync();
result.addChangeListener(callback);
}
But if you give the RealmResults to a RealmRecyclerViewAdapter, then this is all automatic.
P.S. not closing Realm instance in doInBackground() is like, S-class horrible mistake. Please close your Realm instance on non-looping background threads.
Specifically the following:
// private class YourAsyncTask extends AsyncTask<String, String, RealmResults> {
//
// ProgressDialog progressDialog;
// #Override
// protected void onPreExecute() {
// // start loading animation maybe?
// progressDialog = ProgressDialog.show(DictionarySscWords.this,
// "ProgressDialog",
// "Loading all words!");
// }
//
// #Override
// protected RealmResults doInBackground(String... params) {
// RealmConfiguration realmConfig = new RealmConfiguration.Builder(context).build();
// Realm.setDefaultConfiguration(realmConfig);
// realm = realm.getDefaultInstance();
// RealmQuery<Word> query = realm.where(Word.class);
//
// for (int i = 0; i < words_for_ssc[Integer.parseInt(params[0])].length; i++) {
// if (i == words_for_ssc[Integer.parseInt(params[0])].length - 1) {
//
// query = query.equalTo("word", words_for_ssc[Integer.parseInt(params[0])][i]);
// } else {
// query = query.equalTo("word", words_for_ssc[Integer.parseInt(params[0])][i])
// .or();
//
// }
//
// }
// sscresult = query.findAll(); //error 1
// return sscresult;
//
// }
//
// #Override
// protected void onPostExecute(RealmResults r) {
// progressDialog.dismiss();
// list.setAdapter(new MyAdapter(sscresult)); //error 2
// realm.close();
// }
//}
and
public class MyActivity extends AppCompatActivity {
private RealmResults<Word> words;
private Realm realm;
private WordAdapter wordAdapter;
#BindView(R.id.recycler_view)
RecyclerView recyclerView;
#Override
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
setContentView(R.layout.my_activity);
ButterKnife.bind(this);
realm = Realm.getDefaultInstance();
words_for_ssc = ...
RealmQuery<Word> query = realm.where(Word.class);
String[] array = words_for_ssc[Integer.parseInt(params[0])];
for (int i = 0; i < array.length; i++) {
query = query.equalTo("word", array[i]);
if (i != array.length - 1) {
query = query.or();
}
}
words = query.findAllSortedAsync("word");
wordAdapter = new WordAdapter(words);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setAdapter(wordAdapter);
}
#Override
public void onDestroy() {
super.onDestroy();
realm.close();
realm = null;
}
}
public class WordAdapter extends RealmRecyclerViewAdapter<Word, WordViewHolder> {
public class WordAdapter(OrderedRealmCollection<Word> words) {
super(words, true);
}
#Override
public WordViewHolder onCreateViewHolder(...) {
...
}
#Override
public void onBindViewHolder(WordViewHolder holder, int position) {
holder.bind(getData().get(position));
}
public static class WordViewHolder extends RecyclerView.ViewHolder {
public WordViewHolder(View view) {
super(view);
ButterKnife.bind(this, view);
}
public void bind(Word word) {
...
}
}
}
I think a cleaner solution to your problem without changing much of the code can be written below. In this case, everything that realm does happen on the background thread inside doInBackground. The realm instance is also closed on the thread it was created.
Now what I did basically is that I extracted a deep copy of the list of Words from RealmResult from realm.copyFromRealm(sscresult) which is completely detached from realm and can be moved around and modified inside any thread. All these objects are now free from realm and can be used in onPostExecute without any worries. The only thing you need to modify is the MyAdapter constructor which doesn't take a RealmResult but instead a List of Words which is exactly what you need and can be iterated the same way as RealmResult was.
The only downside of this approach is that the list of Words will not get synced automatically since they're detached and their value won't change automatically if they get altered inside Realm from somewhere else. But I'm pretty sure though that it won't bother you.
I'm also going to attach an official reference for realm.copyFromRealm() which is here.
private class YourAsyncTask extends AsyncTask<String, String, List<Word>> {
ProgressDialog progressDialog;
#Override
protected void onPreExecute() {
// start loading animation maybe?
progressDialog = ProgressDialog.show(DictionarySscWords.this,
"ProgressDialog",
"Loading all words!");
}
#Override
protected List<Word> doInBackground(String... params) {
RealmConfiguration realmConfig = new RealmConfiguration.Builder(context).build();
Realm.setDefaultConfiguration(realmConfig);
try(realm = realm.getDefaultInstance()) {
RealmQuery<Word> query = realm.where(Word.class);
for (int i = 0; i < words_for_ssc[Integer.parseInt(params[0])].length; i++) {
if (i == words_for_ssc[Integer.parseInt(params[0])].length - 1) {
query = query.equalTo("word", words_for_ssc[Integer.parseInt(params[0])][i]);
} else {
query = query.equalTo("word", words_for_ssc[Integer.parseInt(params[0])][i])
.or();
}
}
// Here's the sort. Use findAllSorted instead.
// You can change Sort.ASCENDING to Sort.DESCENDING to reverse
// the order.
sscresult = query.findAllSorted("word", Sort.ASCENDING);
// This is where the magic happens. realm.copyFromRealm() takes
// a RealmResult and essentially returns a deep copy of the
// list that it contains. The elements of this list is however
// completely detached from realm and is not monitored by realm
// for changes. Thus this list of values is free to move around
// inside any thread.
ArrayList<Word> safeWords = realm.copyFromRealm(sscresult);
realm.close();
return safeWords;
}
}
#Override
protected void onPostExecute(List<Word> words) {
progressDialog.dismiss();
// Please note here MyAdaptor constructor will now take the
// list of words directly and not RealmResults so you slightly
// modify the MyAdapter constructor.
list.setAdapter(new MyAdapter(words));
}
}
Hope it helps!

How to stop my app from crashing using AsyncTask in Android Studio?

I have built a user interface in Android Studio to test the PSO algorithm in Java. I took this project on from someone else who did it last year, the person before me used AsyncTask with Boolean[] parameters to execute his application. Below is his version of this class, this is because he used a checkbox in his MainActivity that the user can check, so it can either be one or the other.
public class runTests extends AsyncTask<Boolean, Void, Void> {
#Override
protected Void doInBackground(Boolean... params) {
boolean one = params[0];
boolean custom = params[1];
if (one)
results = runTest("TestOne");
else if (custom) {
double[] re = runTest("customTest");
if (re != null) results = re;
}
return null;
}
#Override
protected void onPostExecute(Void v) {
// execution of result of Long time consuming operation
pd.dismiss();
if (results[0] != -1 || results != null) {
loadIntent(results);
}
}
#Override
protected void onPreExecute() {
pd = ProgressDialog.show(MainActivity.this, "Busy", "Algorithm is currently executing");
}
}
Whereas my code doesn't have a checkbox it only needs to implement one test rather than having the option of two. I just want to run "CustomUseCase" and nothing else. I don't want to use a boolean parameter however I still want to have AsyncTask. Please help me!
public class runTests extends AsyncTask<Boolean, Void, Void> {
#Override
protected Void doInBackground(Boolean... params) { //sort this out
boolean one = params[0];
boolean custom = params[1];
if (one)
results = runTest("CustomUseCase"); //i only want to run this one!!!
else if (custom) {
double[] re = runTest("testOne"); //I don't need this, I dont want to run this test
if (re != null) results = re;
}
return null;
}
#Override
protected void onPostExecute(Void v) {
// execution of result of Long time consuming operation
if(pd!=null){
pd.dismiss();
pd = null;
}
if (results[0] != -1 || results != null) {
loadIntent(results);
}
}
#Override
protected void onPreExecute() {
pd = ProgressDialog.show(ParticleActivity.this, "Busy", "Algorithm is currently executing");
}
}
First, you need to change
if (results[0] != -1 || results != null) {
loadIntent(results);
}
to
if (results != null && results.length > 0 && results[0] != -1) {
loadIntent(results);
}
That is an example of a "short circuiting" if statement. The logical AND (&&) operator will cause the entire statement to fail if results is null, otherwise it will evaluate the next logic statement results[0] != -1 with no chance of a NullPointerException.
Try this as well
public class runTests extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... params) { //sort this out
results = runTest("CustomUseCase"); //i only want to run this one!!!
}
...
}
UPDATE
do I return null when executing the doInBackground?
To clarify how the Template Type List (ie, <Void,Void,Void>) works, here is an example. Here, we have <URL, Integer, Long>. Notice how doInBackground takes an array of URL (urls) and returns a Long, onProgressUpdate takes an Integer array, and onPostExecute takes a Long.
private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
protected Long doInBackground(URL... urls) {
long totalSize = urls.length;
...
return totalSize;
}
protected void onProgressUpdate(Integer... progress) {
setProgressPercent(progress[0]);
}
protected void onPostExecute(Long result) {
showDialog("Downloaded " + result + " bytes");
}
}
For <Void, Void, Void> we would have (empty function argument list "()" corresponds to Void):
private class DownloadFilesTask extends AsyncTask<Void, Void, Void> {
protected Void doInBackground() {
...
return;
}
protected void onProgressUpdate() {
setProgressPercent("hi");
}
protected void onPostExecute() {
showDialog("bye");
}
}

Original thread lost because of changed reference

In my android app I'm trying to extend the Thread class to easy pass my values between the original thread and a another one. So I can easily update my UI.
To do this I extended the Thread class:
public class ThreadUpdateUI extends Thread {
AppCombatActivityExtended activity;
Map<?,?> values;
public ThreadUpdateUI(AppCombatActivityExtended activity, Map<?,?> values){
this.activity = activity;
this.values = values;
}
public void UpdateUI(Map<?,?> values){
this.activity.UIThreadFinished(values);
}
public Map<?,?> GetValues()
{
return this.values;
}
}
Not only did I extend Threads, but I also extended the class for Activity so I have a main function I can call in every activity to update my UI:
public class AppCombatActivityExtended extends AppCompatActivity {
protected void UIThreadFinished(Map<?,?> values){}
}
In my activity I use the ThreadUpdateUI class to run a thread in which I can pass all my own values to use in the other thread:
public class MainActivity extends AppCombatActivityExtended {
static final String carlooking_key = "text_carlooking";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//init views
final TextView text_carlooking = (TextView) findViewById(R.id.main_text_carlooking);
//init parameters for thread
HashMap<String, String> UIThreadParameters = new HashMap<>();
UIThreadParameters.put(carlooking_key, text_carlooking.getText().toString().replace(".", ""));
//ThreadUpdateUI
ThreadUpdateUI TU_UI = new ThreadUpdateUI(this, UIThreadParameters) {
#Override
public void run() {
try {
Integer counter = 0;
while (true) {
sleep(1000);
Map values = GetValues();
String text = values.get(carlooking_key).toString();
text += "_test";
Map result = new HashMap<String,String>();
result.put(carlooking_key, text);
UpdateUI(result);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
TU_UI.start();
}
#Override
protected void UIThreadFinished(Map<?, ?> values) {
super.UIThreadFinished(values);
final TextView text_carlooking = (TextView) findViewById(R.id.main_text_carlooking);
text_carlooking.setText(values.get(carlooking_key).toString());
}
}
My code crashes at:
UpdateUI(result);
Saying: "Only the original thread that created a view hierarchy can touch its views."
In my trace I can see the following:
at MainActivity.UIThreadFinished(MainActivity.java:56)
at ThreadUpdateUI.UpdateUI(ThreadUpdateUI.java:21)
at MainActivity$1.run(MainActivity.java:42)
Which could indicate that the reference changed in my ThreadUpdateUI causing to call ThreadUpdateUIFinished in a different thread than the original.
Is it possible to make this code return to the original thread to update my UI in a loop?

Object listener inside asyncTask and publish updates (Android)

I am pretty new at android developing(only 2 months)
I am trying to create an asyncTask which receives a user id and creates the user object, and after it finishes to replace fragment.
every thing went well, until I tried to add publish updates.
Inside my user object it creates days object when creating the user,
I want the asyncTast to change textView text according to the number of days created so far.
So I created an interface inside my User object which call dayCreated() function everytime day is created and pass to it the number of days so far.
Inside my asyncTask in doInBackground I tried to set the listener and call publishUpdates each time but it crashes.
Here is my AsyncTask code:
class CreateUserTask extends AsyncTask<Integer, Integer, User> {
private int uid = -1;
#Override
protected User doInBackground(Integer... params) {
uid = params[0];
try {
User user;
user = new User(MainActivity.this, uid);
user.setEventHandler(new User.EventHandler() {
#Override
public void dayCreated(int dayCounter) {
publishProgress(dayCounter);
}
});
return user;
} catch (ParseException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPreExecute() {
fragmentsReplace(loadingFragment, "Loading");
}
#Override
protected void onPostExecute(User userRecieved) {
if(userRecieved != null) {
fragmentsReplace(mainFragment, TAG_MAIN_FRAGMENT);
user = userRecieved;
login();
}
else{
fragmentsReplace(loginFragment, TAG_LOGIN_FRAGMENT);
}
}
#Override
protected void onProgressUpdate(Integer... values) {
loadingFragment.setDayCounter(values[0]);
}
}
And inside my User object this is how I call using interface:
int dayCounter = 0;
Cursor result = myDataBase.getDaysData(this.uid);
while (!result.isAfterLast()) {
try {
Calendar date = Calendar.getInstance();
date.setTimeInMillis(Long.parseLong(result.getString(result.getColumnIndex(DataBaseHelper.DB_DATE_COLUMN))));
DayOfWork day = new DayOfWork(this.uid, date, this.context);
this.daysOfWorkArray.add(day);
dayCounter++;
eventHandler.dayCreated(dayCounter++);
}catch (Exception e)
{
Log.e("error" , e.getMessage());
}
result.moveToNext();
And the eventHandler code:
EventHandler eventHandler = null;
public interface EventHandler{
void dayCreated(int dayCounter);
}
public void setEventHandler(EventHandler eventHandler){
this.eventHandler = eventHandler;
}
Does publishProgress() interact with anything in your UI? If so your issue is that you're calling it from a background thread in your async task. All UI interactions need to execute on the main/UI thread.

Modifying data from an Async task in an entirely different class

I would like to know just out of curiosity if there are any convenient ways of pulling data out of an async task created inside a class, and then modifying the data in another class (Without extending classes)
I have a way to do it, but it involves making methods static along with the Async task itself
for example, here I'm just making a string "text" in the Async task
public class Main extends Activity{
//Context ctx;
static class MyAsyncTask extends AsyncTask<Void,String,String>{
static String result;
private static Context context;
public MyAsyncTask(Context m)
{
this.context = m;
}
#Override
protected String doInBackground(Void... noArgs) {
result = "text";
return result;
}
protected void onPostExecute(String result)
{
super.onPostExecute(result);
}
public static String getStr()
{
return result;
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final EditText et = (EditText)findViewById(R.id.editText1);
Button btn = (Button)findViewById(R.id.button1);
MyAsyncTask task = new MyAsyncTask(this);
task.execute();
final Test t = new Test();
btn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v)
{
et.append(t.modifiedString());
}
});
}
}
and in a new class I make a simple String method to modify that data from the async task
public class Test{
public String modifiedString()
{
// Main main = null;
// MyAsyncTask task = new MyAsyncTask(main.ctx);
// task.execute();
String s = (String)Main.MyAsyncTask.getStr();
return "modified " + s + "\n";
}
}
I'm wondering, is there a way I can do this without having to make the async task static? Perhaps with sharing contexts or something?
by the way I'm not doing this to solve any particular problem, I'm only doing it out of curiosity
Just create a singleton
public class Main extends Activity{
public static Main instance;
public static String thestring;
public class MyAsyncTask extends AsyncTask<Void,String,String>{
static final String result = "text";
Context context;
public MyAsyncTask(Context m)
{
this.context = m;
}
#Override
protected String doInBackground(Void... noArgs) {
return result;
}
protected void onPostExecute(String result)
{
super.onPostExecute(result);
}
public String getStr()
{
return result;
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final EditText et = (EditText)findViewById(R.id.editText1);
Button btn = (Button)findViewById(R.id.button1);
MyAsyncTask task = new MyAsyncTask(this);
task.execute();
thestring = task.getStr();
instance = this;
final Test t = new Test();
btn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v)
{
et.append(t.modifiedString());
}
});
}
public String pulledFromAsyncTask()
{
return thestring;
}
public static Main getInstance(){
return instance;
}
}
and then in the another class
public class Test{
public String modifiedString()
{
Main main = Main.getInstance();
//so with main.something.. you can call the methods you want
//a good solution is to make a singleton class only for MyAsyncTask setting the
//functions get/set so you can take the values from other classes
return "modified " + main.pulledFromAsyncTask() + "\n";
}
}
Reference to a Context in a static way is generally bad idea, it can cause memory leaks
Why don't you simply pass MyAsyncTask object to Test and then do whatever modifications you want, i.e. non-static fashion?
When it comes to testable code static/ singleton is a tough choice.
Depending upon your requirement on the state of data you can however start with an Observer pattern or producer-consumer pattern.
Check out Event bus library for probably an out of the box solution for this use case

Categories