I am pretty much new in Java (& android), hence I can't solve it with my limited knowledge despite searching extensively.
In the code below, I want to get a JASONArray from a weblink through AsyncTask. After that I want to populate my database from the array data.
To do that I created the RemoteConnectivity class where I can populate an ArrayList importdata with all the data from JASONArray. But the problem is, I cannot access my database class mylibmandbhandler from inside RemoteConnectivity class (I guess because that is not extended to Activity). And in ImportExport class, if I write the code to insert into database just after calling RemoteConnectivity().execute() [as in code below], it starts inserting before execution ends (very obvious because it is property of AsyncTask).
Now, can anybody please guide me through this? Or any link please to understand the whole process (I am lost in at least 50 pages I read about it :( ).
P.S. mylibmandbhandler is a Class I created (not activity) in my package src folder for my database operations.
public class ImportExport extends Activity {
public void webimport(View v){
new RemoteConnectivity().execute(); // START OF ASYNCTASK
//INSERT importdata INTO DATABASE AFTER EXECUTE
mylibmandbhandler db = new mylibmandbhandler(this);
for (String[] s : importdata){
db.addRecord(new mylibman(s));
}
}
final ArrayList<String[]> importdata = new ArrayList<String[]>();
private class RemoteConnectivity extends AsyncTask<Void, Void, Void>
{
#Override
protected Void doInBackground(Void... arg0) {
..................
..................
importdata.add(dataline); // POPULATE ARRAYLIST IMPORTDATA
return null;
}
#Override
protected void onPostExecute(Void result1)
{
// WHAT TO WRITE HERE
}
}
}
You should insert the data in the onPostExecute as follows:
public class ImportExport extends Activity {
public void webimport(View v){
new RemoteConnectivity().execute(); // START OF ASYNCTASK
}
final ArrayList<String[]> importdata = new ArrayList<String[]>();
private class RemoteConnectivity extends AsyncTask<Void, Void, Void>
{
#Override
protected Void doInBackground(Void... arg0) {
..................
..................
importdata.add(dataline); // POPULATE ARRAYLIST IMPORTDATA
return null;
}
#Override
protected void onPostExecute(Void result1)
{
//INSERT importdata INTO DATABASE AFTER EXECUTE FINISH (POST EXECUTE)
mylibmandbhandler db = new mylibmandbhandler(ImportExport.this);
for (String[] s : importdata){
db.addRecord(new mylibman(s));
}
}
}
}
The reason is because, onPostExecute is the method (callback) which is executed after the data has been done downloading in the doInBackground method.
Alternatively: You can also put the insert statements inside the doInBackground if you want the inserting to be done by background thread. This may be helpful, if inserting into the database is time consuming. In such a case the UI thread won't block. '
public class ImportExport extends Activity {
public void webimport(View v){
new RemoteConnectivity().execute(); // START OF ASYNCTASK
}
final ArrayList<String[]> importdata = new ArrayList<String[]>();
private class RemoteConnectivity extends AsyncTask<Void, Void, Void>
{
#Override
protected Void doInBackground(Void... arg0) {
..................
..................
importdata.add(dataline); // POPULATE ARRAYLIST IMPORTDATA
//INSERT importdata INTO DATABASE. NOW DONE IN THE BACKGROUND THREAD (Alternate method)
mylibmandbhandler db = new mylibmandbhandler(ImportExport.this);
for (String[] s : importdata){
db.addRecord(new mylibman(s));
}
return null;
}
#Override
protected void onPostExecute(Void result1)
{
}
}
}
Update: The important this to highlight in my answer is that I used new mylibmandbhandler(ImportExport.this); instead of new mylibmandbhandler(this); as this refers to AsyncTask which is not what the constructor supports.
You need to use method onPostExecute to insert data to datatable. Like this:
private class RemoteConnectivity extends AsyncTask<Void, Void, Void>
{
#Override
protected Void doInBackground(Void... arg0) {
..................
..................
importdata.add(dataline); // POPULATE ARRAYLIST IMPORTDATA
return null;
}
#Override
protected void onPostExecute(Void result1)
{
//INSERT importdata INTO DATABASE AFTER EXECUTE FINISH (POST EXECUTE)
mylibmandbhandler db = new mylibmandbhandler(ImportExport.this);
for (String[] s : importdata){
db.addRecord(new mylibman(s));
}
}
}
Related
I am quite new to Android Development. I am working in a app where i need to make a lot of async calls to api. For each and every API call, I have to write the similar looking AsyncTask class over and over again. So, is there any way to make these Async Calls modular?
yes it is possible use Listener and AsyncTask with parameterized constructor
Check it
Create an interface
public interface OnTaskCompletListerner {
void oncompleteListerner(String name);
}
create an AsyncTask class as follows
public class AsyncTaskModuler extends AsyncTask<Void, Void, String> {
private Context context;
private HashMap<String, String> data;
private String URL;
private OnTaskCompletListerner taskdone;
public AsyncTaskModuler(Context ctx,HashMap<String, String> data,String url,OnTaskCompletListerner taskdone){
this.context=ctx;
this.data=data;
this.URL=url;
this.taskdone=taskdone;
}
#Override
protected String doInBackground(Void... params) {
//Do the task here and return the value if needed
return null;
}
#Override
protected void onPostExecute(String result) {
taskdone.oncompleteListerner(result);
}
and call it in your activity like this
public class CallAync extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
String url="";
HashMap<String, String> data=new HashMap<String, String>();
AsyncTaskModuler moduler=new AsyncTaskModuler(CallAync.this, data, url, completListerner);
moduler.execute();
}
OnTaskCompletListerner completListerner=new OnTaskCompletListerner() {
#Override
public void oncompleteListerner(String name) {
}
};
}
Create an general async task and pass your url as param to it .Hence you can reuse the same async task for all your api calls
public class myTask extends AsyncTask<Void, Void, Void> {
String muUrl;
public myTask(Context context, Activity activity,
String url) {
contxt = context;
myUrl=url;
}
#Override
protected Void doInBackground(Void... params) {
makeApiCalls();
return null;
}
}
Start the task in the following way :
new myTask(this, this, urlStr).execute();
EDIT
How can I perform different logic onPostExecute() ?
You can add another param in the constructor of myTask.
Ex.
public MyTask(Context context, Activity activity,
String url,String postExecuteAction) {
}
In your post executes just check of each case in if else and perform the respective task
Dummy Background class
private class BackGroundClass extends AsyncTask<String, Void, Bitmap> //<arg to do InBackground,,returntype of do inBackground and arg of onPostExecut>
{
public BackGroundClass()
{
}
#Override
protected void onPreExecute() //forground work in UI thread prior to doInbackground
{
super.onPreExecute();
}
#Override
protected Bitmap doInBackground(String... urls) //background work in parallel thread
{
Bitmap b=null;
// your background work
return b;
}
#Override
protected void onPostExecute(Bitmap result) //forground work in UI thread post to doInbackground
{
super.onPostExecute(result);
if(result!=null)
{
//use bitmap image in result
}
else
{
//Image is not available
}
}
}
Calling for one parellel execution
new BackGroundClass().execute(StringArg1,stringArg2,StringArg3);
Calling for multiple parellel execution
when tou need to call more than one background task at same time
new BackGroundClass().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,StringArg1,stringArg2,StringArg3);
Called from single activity
use this as an inner class to your activity for making it easy to share variable if not called from more than one activity
Called from more than one activity
use constructor to pass activity context,and other variable
new BackGroundClass(constructor arguments).execute(StringArg1,stringArg2,StringArg3);
new BackGroundClass(constructor arguments).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,StringArg1,stringArg2,StringArg3);
I need to load a data coming from a service in a table on the SplashScreenActivity. I've followed this tutorial and everything works just fine. I have also added a custom AsyncTask to run the insert loop in the background.
The problem is that if a configuration change happens in the middle of the insert (e.g. screen rotation) everything blows up and I get corrupted data saved on the database.
I've read stuff about CursorLoader but that's only for querying the database. I've also looked at ContentProviders but they don't solve the problem.
Any ideas on how to handle this problem?
What I basically need is:
Access database from a background thread to keep the UI responsive.
Handle configuration changes when doing inserts on the database.
UPDATE:
public class SplashScreenActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_splash_screen);
...
// Create a Volley Request and fetch data
}
When I get the Response object I start the AsyncTask:
new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
if (response.optString("lastrunstatus").equals(
"success")) {
JSONObject results = response
.optJSONObject("results");
JSONArray objects = results
.optJSONArray("objects");
new HandleResponseAsyncTask().execute(objects);
}
}
In the AsyntTask, I insert all objects:
private class HandleResponseAsyncTask extends
AsyncTask<JSONArray, String, Void> {
#Override
protected void onPreExecute() {
mDataSource.open();
}
#Override
protected Void doInBackground(JSONArray... params) {
publishProgress("Deleting data...");
mProductosDataSource.deleteAll();
publishProgress("Saving data...");
JSONArray objects = params[0];
for (int i = 0; i < objects.length(); i++) {
JSONObject object = objects.optJSONObject(i);
// Get each column value from JSON
...
mDataSource.insert(id, name, description);
}
return null;
}
#Override
protected void onProgressUpdate(String... messages) {
mTextViewLoading.setText(messages[0]);
}
#Override
protected void onPostExecute(Void result) {
mDataSource.close();
// Go to main
startMainActivity();
}
}
NOTE: mDataSource holds an instance of a helper class that calls the methods in my custom SQLiteOpenHelper class.
I know how to use AsyncTask to download file, create a zip file or so.. as I call publishProgress() in my loop.
I got stuck when doInBackground() has a single slow line, no loops here, just creating an object where its constructor has slow loops.
I'm not sure about the reasonable way of updating progress in such case.
Here's a sample code:
public class Session {
private QQActivity activity;
public int createdParts;
public DailyClass daily;
private void checkDaily() {
if(!isDailyReady){
new SetAsyncQQDaily().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
}
class SetAsyncQQDaily extends AsyncTask<Void, Void, String> {
#Override
protected String doInBackground(Void... params) {
String sdq = null;
daily = new DailyClass(Session.this); //Very very Slow!
// Do other network http
sdq = new String(Base64.encode(bos.toByteArray(),Base64.DEFAULT));
// Do some work
return sdq;
}
#Override
protected void onPostExecute(String sdq) {
//Never mind
}
#Override
protected void onPreExecute() {
Toast.makeText(activity,"Preparing the daily. Get ready!",Toast.LENGTH_LONG).show();
}
#Override
protected void onProgressUpdate(Void... values) {
//TODO: Update Value of leftBar
activity.leftBar.setProgress((100*createdParts)/Utils.DAILY_PART_COUNT);
}
}
}
In the slow constructor class, I can set-back an integer of the current progress: createdParts, but cannot call publishProgress.
public class DailyClass implements Serializable {
public DailyClass(Session session){
for(int i=1;i<=partCount;i++ ){ //Very slow loop
session.createdParts = i; //TODO: reflect value to progress bar!?
for(int j=0;j<questionsCount;j++){
objects[i-1][j] = createDefined(i);
}
Log.d("Daily","created part"+i);
}
}
//Bla .. !
}
I also though of passing the object of the AsyncTask to the slow constructor in order to call publishProgress() from there, but cannot. As publishProgress() is accessible only from doInBackground()
What's the best practice?
In my main activity I got an arraylist called data. I call an asynctask and do some stuff that gives me a different arraylist called values.
In the post execute of the asynctask I want to use items in 'values' to add some objects to 'data'. However, when debugging I noticed that the objects dont get added.
public class MainActivity extends Activity
{
ArrayList<DataItem> data;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
data = new ArrayList<DataItem>();
update();
}
public void update()
{
AsyncCallAWS thisTask = new AsyncCallAWS();
thisTask.execute();
}
private class AsyncCallAWS extends AsyncTask<String, Void, Void>
{
ArrayList<String> values = new ArrayList<String>();
protected void onPostExecute(Void result)
{
Log.i(TAG, "onPostExecute");
DataItem d;
for(String s : values)
{
d = new DataItem();
d.setValue(s);
d.setDataStreamName("test");
data.add(d);
}
}
//code to fill array
I'm guessing it's because I try to add items from the asynctask? Idk how to solve this, I need the data arraylist for a listview.
In AsyncTask class override method onProgressUpdate(), where you will add elements to array. Then in doInBackground() call publishProgress() for sending elements to onProgressUpdate(). Here http://developer.android.com/reference/android/os/AsyncTask.html -is great example.
private class TestAsyncTask extends AsyncTask<Object, String, Object> {
#Override
protected Object doInBackground(Object... params) {
String item = "";
//Do some stuff
publishProgress(item);
return null;
}
#Override
public void onProgressUpdate(String... value) {
data.add(value[0]);
}
#Override
protected void onPostExecute(Object result) {
}
}
I dont think you should create objects in the onPostExecute-method. Instead create it in the doInBackground-method of the class that extends AsyncTask, and then use set-methods in the onPostExecute-metod.
Hi I'm having problem refreshing my listview after Async operation.
I have a simplecursoradapter, and custon listview and a button. Initially when application starts, it sets the listview from the data read from database. Then when user clicks a button, it starts a async code to download some data which gets inserted into a database. When async task start, I'm displaying a progressdialog, which I dismiss in postexecute(). Data is getting downloaded fine, but now how do I requery the cursor and update listview on the main thread after background job is done?
A Method "refreshRemoteData" gets called via a menu button.
This is how my AsyncTask looks like.
public class MyActivity extends ListActivity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
public void onStart() {
myDBAdapter = new DBAdapter(this);
myDBAdapter.open();
populateMyList();
}
private void populateMyList() {
myCursor = myDBAdapter.fetchAllItems();
startManagingCursor(myCursor);
getListView().setAdapter(myDBAdapter);
}
private void refreshRemoteData() {
mPleaseWaitDialog = ProgressDialog.show(ExpirationDateTrackingActivity.this,
"Data", "Downloading data", true, true);
download_task = new InfoDownloaderTask();
download_task.execute();
}
private class InfoDownloaderTask extends AsyncTask<Object, String, Boolean> {
private static final String DEBUG_TAG = "InfoDownloaderTask";
protected DBAdapter mylocalDBAdapter=null;
#Override
protected void onPreExecute() {
Log.e(DEBUG_TAG, "onPreExecute: ");
mylocalDBAdapter = new DBAdapter(this);
mylocalDBAdapter.open();
}
#Override
protected void onPostExecute(Boolean result) {
Log.i(DEBUG_TAG, "onPostExecute: " );
mPleaseWaitDialog.dismiss();
mlocalDBAdapter.close();
}
#Override
protected Boolean doInBackground(Object... arg0) {
Log.v(DEBUG_TAG, "doInBackground");
///...
//Update the database
mylocalDBAdapter.insertData(....);
return true;
}
} //AsyncTask
}
I don't see my listview getting updated with new list data right after async operation is complete. But If I invoke another ativity and comeback to the listview then I see all new items (list update).
What am I missing?
You're inserting data through mylocalDBAdapter, but you aren't telling myDBAdapter about it. Try calling myDBAdapter.notifyDataSetChanged(); at the end of onPostExecute().