Calling UI thread method from AsyncTask - android

I have a problem with calling the setadapter() method from the inside of AsyncTaskActivity onPostExecute() method. I've read docs about AsyncTask: http://developer.android.com/reference/android/os/AsyncTask.html#onPostExecute(Result) but found no answer how to achieve that. Should I use an Intent to do so? I'm new to a Android development so please forgive me if it's a kind of stupid question.
MainActivity
public class MainActivity extends ListActivity {
private String[] columns = new String[] {"foreign_word", "native_word"};
private int[] target = new int[] { R.id.foreign_word, R.id.native_word };
private Cursor cur = null;
#Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
new AsyncTaskActivity(this).execute();
}
public void setadapter(Cursor cur) {
SimpleCursorAdapter aaa = new SimpleCursorAdapter(this.getApplicationContext(), R.layout.list_entry, cur, columns, target, 0);
this.setListAdapter(aaa);
}
}
AsyncTaskActivity
public class AsyncTaskActivity extends AsyncTask<Void, Void, Cursor> {
Activity activity = null;
private SQLiteDatabase db = null;
private String[] selection = {"_id", "native_word", "foreign_word"};
Cursor cur = null;
public AsyncTaskActivity(Activity activity) {
this.activity = activity;
}
#Override
protected Cursor doInBackground(Void... params) {
DbAdapter mSQLadapter = new DbAdapter(activity);
db = mSQLadapter.getWritableDatabase();
Cursor cur = db.query("words", selection, "foreign_word='car'", null, null, null, null);
return cur;
}
protected void onPostExecute(Cursor cur) {
// I'd like to call setadapter() ,passing it Cursor as a parameter
}
}

Assuming that your AsyncTask is always called by MainActivity, do this
protected void onPostExecute(Cursor cur) {
MainActivity mActivity = (MainActivity) activity;
mActivity.setadapter();
}
You can specify more parameters for your setAdapter method so you can pass off the Cursor, String Array, etc.
However an even better method if the AsyncTask is only called from MainActivity is to make this AsyncTask a private inner class inside MainActivity. This will allow it to access all the global variables and methods of MainActivity

Your approach is a little unusual, but to answer the question asked:
Change activity to a ListActivity:
ListActivity activity = null;
And use:
protected void onPostExecute(Cursor cur) {
activity.setListAdapter(new SimpleCursorAdapter(activity, R.layout.list_entry, cur, columns, target, 0));
}
You should look into using the LoaderManager class, it creates and handles background threads for you. You should also consider using a ContentProvider, it handles a lot of busy work for you as well.
Lastly AsyncTaskActivity is not an Activity, so this class name is a little confusing...

Related

How do i add onClick listener that would return the value of the clicked list from this code? (this is my first time coding andorid)

I've found this code from here
github
I've already created a Class with a method that would take the returned value from the list and retrieve appropriate value from database based on the value.
All i need right now is an onClick handler for this code that would return me a value of the clicked item on the list.
public class MainActivity extends ListActivity {
private Cursor employees;
private MyDatabase db;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
db = new MyDatabase(this);
employees = db.getDisease(); // you would not typically call this on the main thread
ListAdapter adapter = new SimpleCursorAdapter(this,
android.R.layout.simple_list_item_1,
employees,
new String[] {"FirstName"},
new int[] {android.R.id.text1});
getListView().setAdapter(adapter);
}
#Override
protected void onDestroy() {
super.onDestroy();
employees.close();
db.close();
}
}

How to show ProgressiDialog when using LoaderCallbacks

I have a class that loads the images on the device. This is an example of my activity:
public class MediaListActivity extends AppCompatActivity implements LoaderCallbacks<Cursor> {
private ProgressDialog progressDialog;
#Override
protected void onCreate(Bundle savedInstanceState) {
...
progressDialog.show();
getSupportLoaderManager().initLoader(1, null, this);
}
#Override
public android.support.v4.content.Loader<Cursor> onCreateLoader(int id, Bundle args) {
CursorLoader cursorLoader = new CursorLoader(this, MediaStore.Images.Media.EXTERNAL_CONTENT_URI, null, null, null, null);
return cursorLoader;
}
#Override
public void onLoadFinished(android.support.v4.content.Loader<Cursor> loader, Cursor cursor) {
progressDialog.dismiss();
}
}
Of course, I can't put progressDialog.show() inside the onCreate() method, since if the ContentObserver find a change in MediaStore.Images.Media.EXTERNAL_CONTENT_URI and the Cursor is reloaded the method progressDialog.show() will not be called.
How can I solve this problem?
Thank you in advance
Try showing the dialog in onLoaderReset() callback. It is called anytime a loader is restarted, despite the onCreateLoader() that may not be called every time because the loader might already be created.

ProgressDialog with LoadManager

I checked questions asked in StackOverflow but couldnt make to solve my issue.
I am trying to get some data in ListView in asynchronous way (to not overload UI Thread) and while i get the data i want to show a ProgressDialog. I am getting the data using ContentProvider and it loads the data successfully in ListView, however the progressDialog is not spinning, but after the list is shown with data it starts spinning and never stops (Keeps spinning).
How can i make ProgressDialog spin and dismiss() after the ListView is Visible.
Here is the activity which implements LoaderCallbacks:
public class AttractionsActivity extends Activity implements LoaderManager.LoaderCallbacks<Cursor> {
DatabaseHelper dbHelper;
private SimpleCursorAdapter cursorAdapter;
private ListView attractionsListView;
private ProgressDialog progressDialog;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.custom_listview);
attractionsListView = (ListView)findViewById(R.id.lvCustom);
progressDialog = new ProgressDialog(this);
progressDialog.setMessage("Loading");
progressDialog.setCancelable(false);
progressDialog.setIndeterminate(true);
progressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
dbHelper = new DatabaseHelper(this);
dbHelper.open();
populateAttractionsListView();
dbHelper.close();
}
private void populateAttractionsListView() {
//final ImageView image = (ImageView) findViewById(R.id.ivAttImage);
//Initialize Loader
getLoaderManager().initLoader(0, null, this);
String[] from = {PoisContract.COLUMN_POI_MAIN_PIC, PoisContract.COLUMN_POI_NAME};
int[] to = {R.id.ivAttImage, R.id.tvAttName};
//Initialize CursorAdapter
cursorAdapter = new SimpleCursorAdapter(this, R.layout.attractions_listview_row, null, from, to, 0);
ViewBinder viewBinder = new ViewBinder() {
#Override
public boolean setViewValue(View view, Cursor cursor, int columnIndex) {
boolean binded = false;
if(view != null){
String imgName = cursor.getString(columnIndex);
int imgResId = getResources().getIdentifier(imgName, "drawable", getPackageName());
((ImageView) view).setImageResource(imgResId);
binded = true;
}
return binded;
}
};
//Set Adapter but there is no cursor right now
attractionsListView.setAdapter(cursorAdapter);
//Set Binder to the adapter
cursorAdapter.setViewBinder(viewBinder);
//Hide ListView as there is no data returned
attractionsListView.setVisibility(View.GONE);
}
private Cursor getAllAttractions(){
ContentResolver resolver = getContentResolver();
return resolver.query(PoisContract.CONTENT_URI, PoisContract.PROJECTION, null, null, null);
}
#Override
public Loader<Cursor> onCreateLoader(int i, Bundle bundle) {
progressDialog.show(this, "Please wait...", "Loading List...");
CursorLoader cursorLoader = new CursorLoader(AttractionsActivity.this, PoisContract.CONTENT_URI, PoisContract.PROJECTION, null, null, null);
return cursorLoader;
}
#Override
public void onLoadFinished(Loader<Cursor> cursorLoader, Cursor cursor) {
cursorAdapter.swapCursor(cursor);
progressDialog.dismiss();
attractionsListView.setVisibility(View.VISIBLE);
}
#Override
public void onLoaderReset(Loader<Cursor> cursorLoader) {
//Data is not available anymore, delete reference
cursorAdapter.swapCursor(null);
}
however the progressDialog is not spinning, but after the list is
shown with data it starts spinning
This is happening because, despite (correctly)using a Loader to load the data, you also manually query the provider on the main UI thread through the call to the getAllAttractions() method(in the onCreate() method) which will block the UI thread. In fact I don't know why you did that as the returned Cursor is not used at all. Remove the:
Cursor cursor = getAllAttractions();
line from your activity's onCreate() method to solve this issue.
...and never stops (Keeps spinning).
This is happening because you call dismiss on the wrong ProgressDialog reference so you don't cancel the currently showing ProgressDialog. In the onCreate() method of the Activity you create a ProgressDialog reference, however in the onCreateLoader() callback you use the show() method which creates a new instance of a ProgressDialog(the method is static) so when you try to dismiss it in onLoadFinished() you dismiss the previously created ProgressDialog(which isn't even showing). To solve it use:
progressDialog = ProgressDialog.show(this, "Please wait...", "Loading List...");
in the onCreateLoader() callback.
As a side note you should always call a static method of a class by using the class name and not some object reference of that class, this will make thing more clear for you and also anyone who would later read your code.
Ok #Luksprog thank you very much for helping. I found the issue. The problem was in the ContentProvier AUTHORITY declaration. I misspelled the AUTHORITY String in one place. It took a day to figure out that stupid mistake.
I really appreciate your help

Android AsyncTask, Pass view from UI Activity

I have a web browser application.
A AutoCompleteTextView act as a Url textbox, and being fetch a list (Cursor Type) when application start.
Below code is work well, but i don't know it correct to use AsyncTask or not.
So, did the AutoCompleteTextView will freeze will application launch?
And i monitor the thread via Eclipse thread monitor, the AsyncTask#1 thread keep in wait status when done.So how can i close the thread???
Code:
public class BrowserActivity extends StandOutWindow {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//Build the layout
LayoutInflater inflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);
View v = inflater.inflate(R.layout.activity_browser, frame, true);
AutoCompleteTextView txtUrl = (AutoCompleteTextView) v.findViewById(R.id.txtUrl);
//Run the async task
BrowserDataTask bdTask = new BrowserDataTask();
bdTask.execute(txtUrl);
}
//A method belong to BrowserActivity class and reusable.
public Cursor getBrowserData() {
String[] projection = new String[] { "_id", Browser.BookmarkColumns.TITLE,
Browser.BookmarkColumns.URL };
Cursor mCur = getContentResolver().query(android.provider.Browser.BOOKMARKS_URI,
projection, null, null, null);
return mCur;
}
//Sub Class of BrowserActivity
private class BrowserDataTask extends AsyncTask<AutoCompleteTextView, Integer, Cursor>
{
private AutoCompleteTextView m_acText;
#Override
protected Cursor doInBackground(AutoCompleteTextView...params) {
m_acText = params[0];
return getBrowserData();
}
#Override
protected void onProgressUpdate(Integer... progress) {
super.onProgressUpdate(progress);
}
#Override
protected void onPostExecute(Cursor result) {
//UrlAdapter, custome Cursor Adapter from other class.
UrlAdapter adapter = new UrlAdapter(BrowserActivity.this, result);
m_acText.setAdapter(adapter);
}
}
}
Why is it waiting?
AyncTask uses ThreadPoolExecutor and hence you they might not get destroyed but rather kept, because destroying and reinitializing them would be a definite waste. In case you really want to close it, call cancel() on it, that might help.
Will it freeze the app?
No, it won't.
Also, you are never setting your progress!

Error in AsyncTask update of view

I am getting from time to time testing my app error:
03-04 20:57:01.929: E/TestApp(13673): android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
From questions like this: Whats this exception?, and my own experience (I got this same error from time to time as in mentioned question) I would like to ask you guys what I can do to get rid of it?
As far as I know, I can do some stuff on AsyncTask connected to View, so I don't know why I am getting this info.
This is my code:
private MyDBAdapter mySQLiteAdapter;
private ListView wordList;
private AsyncDBDownload asycn;
private ProgressDialog dbUpdate;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.smart_guide_ocr);
asycn = new AsyncDBDownload();
wordList = (ListView) findViewById(R.id.wordsList);
//...
}
#Override
protected void onResume() {
super.onResume();
asycn.execute(null);
}
private class AsyncDBDownload extends AsyncTask<String, Integer, String> {
#Override
protected String doInBackground(String... params) {
try {
refreshList();//upload of contetn and set of adapter
} catch (Exception ex) {
Log.e(TAG, ex.toString());
}
return null;
}
#Override
protected void onPostExecute(String result) {
dbUpdate.dismiss();
}
#Override
protected void onPreExecute() {
dbUpdate = ProgressDialog.show(TestAppActivity.this, "Wait",
"DB download");
}
}
private void refreshList() {
mySQLiteAdapter = new MyDBAdapter(TestAppActivity.this);
mySQLiteAdapter.open();
String[] columns = { MyDBAdapter.KEY_TRANSLATED, MyDBAdapter.KEY_WORD, MyDBAdapter.KEY_LANG,
MyDBAdapter.KEY_ID };
Cursor contentRead = mySQLiteAdapter.getAllEntries(false, columns,
null, null, null, null, MyDBAdapter.KEY_ID, null);
startManagingCursor(contentRead);
Log.d(TAG, Integer.toString(contentRead.getCount()));
RowItem adapterCursor = new RowItem(this, R.layout.save_word_row,
contentRead, columns, new int[] { R.id.translatedWord, R.id.orgWord, R.id.langInfo }, 0);
wordList.setAdapter(adapterCursor);
mySQLiteAdapter.close();
}
You must not call wordList.setAdapter(adapterCursor); from within refresList method. That's a way of "changing a view from a non-UI thread".
So, instead, save the adapterCursor instance and use it from within the onPostExecute method.
You can not manipulate your Views within a background task. Do all the loading you need in your AsyncTask, pass it back into the activity in onPostExecute and set your adapter then. Doing any form of UI manipulation in a background task or service will throw this error.

Categories

Resources