Android: call main activity method from Async onPostExecute method - android

Trying to call MainActivity method on onPostExecute(), but not getting any success. I tried so many things, but I think I am doing something wrong. processFinish() method on MainActivity is not called from onPostExecute().
//myClass.java
public class myClass extends Activity {
public AsyncResponse delegate=null;
public myClass(Context context){
this.mContext = context;
}
public interface AsyncResponse {
void processFinish(String output);
}
public class GetNotification extends AsyncTask<Integer, Void, String>{
public GetNotification() {
super();
}
#Override
protected String doInBackground(Integer... mArgs){
//code
}
#Override
protected void onPostExecute(String result){
super.onPostExecute(result);
delegate.processFinish(result);
}
#Override
protected void onPreExecute(){
}
}
public void getValue(int f){
m_flag = f;
if(Build.VERSION.SDK_INT >= 11){
new GetNotification().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, f);
}
else{
new GetNotification().execute(f);
}
}
}
//MainActivity.java
public class MainActivity extends Activity implements AsyncResponse{
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//code
}
#Override
public void processFinish(String output){
getComActivity(output);
}
private void getData(String mURL){
this.getUrl=new com.sample.myClass(this);
getUrl.getValue(1);
}
public void getComActivity(String gStr){
if (gStr != null && gStr.trim() != ""){
Intent mIntent = new Intent(this.getApplicationContext(), myActivity.class);
this.startActivity(mIntent);
}
}
}

You need to initialze delegate. Change the code in myClass constructor.
public myClass(Context context){
delegate = (AsyncResponse) context;
}

public GetNotification() {
super();
}
//In your AsyncTask class
//use MainActivity or myClass instead of Activity
private Activity activity;
public GetNotification(Activity activity) {
this.activity = activity;
}
private void callMethod()
{
activity.some_method();
}

public class myClass extends Activity {
public AsyncResponse delegate=null;
Context mContext;
public myClass(Context context){
this.mContext = context;
}
public interface AsyncResponse {
void processFinish(String output);
}
public class GetNotification extends AsyncTask<Integer, Void, String>{
public GetNotification() {
super();
}
#Override
protected void onPreExecute(){
//start dialog progress over here
}
#Override
protected String doInBackground(Integer... mArgs){
//code
return null;
}
#Override
protected void onPostExecute(String result){
super.onPostExecute(result);
delegate.processFinish(result);
}
}
#SuppressLint("NewApi")
public void getValue(int f){
int m_flag = f;
if(Build.VERSION.SDK_INT >= 11){
new GetNotification().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, f);
}
else{
new GetNotification().execute(f);
if( MainActivity.activity!=null)
MainActivity.getComActivity("PassYourStringOverHere"); //here I am giving example how to call MainActivity method from other activity
}
}
public class MainActivity extends Activity implements AsyncResponse{
private myClass getUrl;
public static Activity activity=null;
public static Context context=null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
activity=this;//use to initialize the activity...later you can call...and start intent using this activity object...
context=this;//use for Intent...why I used this pattern because i made a static method so I have to do...or else it will show error...
//code
}
#Override
public void processFinish(String output){
getComActivity(output);
}
private void getData(String mURL){
this.getUrl=new com.sample.myClass(this);
getUrl.getValue(1);
}
public static void getComActivity(String gStr){
if (gStr != null && gStr.trim() != ""){
Intent mIntent = new Intent(context, myActivity.class);
activity.startActivity(mIntent);
}
}
}

Related

Only the original thread that created a view hierarchy can touch its views. - Strange behavior

This is a very strange behavior and I don't know how to fix it.
I have an Activity as a Presenter (In a MVP Architecture).
When the activity starts, I attach a Fragment as a View. The fragment itself is very simple.
public class CurrentSaleFragment extends BaseFragment {
private MainMVP.SalesPresenterOps salesPresenterOps;
private SaleAdapter adapter;
private ListView lv;
#BindView(R.id.btn_sell)
FloatingActionButton btnAdd;
public static CurrentSaleFragment newInstance(){
CurrentSaleFragment fragment = new CurrentSaleFragment();
Bundle arguments = new Bundle();
arguments.putInt(LAYOUT_RES_ID, R.layout.fragment_quick_sale );
fragment.setArguments(arguments);
return fragment;
}
#Override
protected void init() {
super.init();
lv = (ListView)view.findViewById(R.id.lv_sale);
}
#OnClick(R.id.btn_sell)
public void addToSale(View view){
mPresenter.moveToFragment(SellProductFragment.newInstance());
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
salesPresenterOps = (MainMVP.SalesPresenterOps)context;
}
#Override
public void onDetach() {
salesPresenterOps = null;
super.onDetach();
}
}
The BaseFragment from which this fragmend extends :
public class BaseFragment extends Fragment implements MainMVP.RequiredViewOps, View.OnClickListener,
LoaderRequiredOps{
protected View view;
protected MainMVP.PresenterOps mPresenter;
protected final static String LAYOUT_RES_ID = "layout_res_id";
#Override
public void showOperationResult(String message, final long rowId) {
Snackbar.make(view, message, Snackbar.LENGTH_LONG).setAction(
R.string.see, new View.OnClickListener() {
#Override
public void onClick(View v) {
onOperationResultClick(rowId);
}
}
).show();
}
#Override
public void showSnackBar(String msg) {
Snackbar.make(view, msg, Snackbar.LENGTH_SHORT).show();
}
#Override
public void showAlert(String msg) {}
protected void onOperationResultClick(long rowId){}
#Override
public void onAttach(Context context) {
super.onAttach(context);
mPresenter = (MainMVP.PresenterOps)context;
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
this.view = inflater.inflate(getArguments().getInt(LAYOUT_RES_ID), null);
init();
return view;
}
protected void addToClickListener(View ... params){
for (View v : params){
v.setOnClickListener(this);
}
}
protected void init() {
if (view != null){
ButterKnife.bind(this, view);
}
}
#Override
public void onDetach() {
mPresenter = null;
Log.d(getClass().getSimpleName(), "Fragment was detached");
super.onDetach();
}
#Override
public void onClick(View v) {}
#Override
public void onPreLoad() {
Dialogs.buildLoadingDialog(getContext(), "Loading...").show();
}
#Override
public void onLoad() {}
#Override
public void onDoneLoading() {
Dialogs.dismiss();
}
}
When I enter the method 'moveToFragment()' I just replace CurrentSaleFragment for a new Fragment:
protected void addFragment(BaseFragment fragment){
mView = fragment;
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_holder,
fragment, null).addToBackStack(null).commit();
}
Then the new fragment is attached:
public class SellProductFragment extends BaseFragment{
private ListView listView;
private ProductListAdapter adapter;
private MainMVP.SalesPresenterOps mSalesPresenter;
public static SellProductFragment newInstance(){
SellProductFragment fragment = new SellProductFragment();
Bundle arguments = new Bundle();
arguments.putInt(LAYOUT_RES_ID, R.layout.fragment_inventory);
fragment.setArguments(arguments);
return fragment;
}
private void reload(){
final Loader loader = new Loader(this);
loader.execute();
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
mSalesPresenter = (MainMVP.SalesPresenterOps)context;
}
#Override
protected void init() {
super.init();
listView = (ListView)view.findViewById(R.id.lv_inventory);
reload();
FloatingActionButton button = (FloatingActionButton)view.findViewById(R.id.btn_add);
addToClickListener(button);
}
#Override
public void onLoad() {
adapter = new ProductListAdapter(getActivity().getApplicationContext(), R.layout.row_product_item,
mSalesPresenter.getProducts());
try{
updateListView();
}catch (Exception e){
Log.w(getClass().getSimpleName(), e.getMessage());
}
}
private void updateListView(){
if (adapter != null && listView != null){
listView.setAdapter(adapter);
}else{
throw new RuntimeException();
}
}
}
See that This fragment also extends from BaseFragment and implements LoaderRequiredOps. The interface is used to 'load' any data. It adds a dialog and updated the adapter when the loading is done:
public class Loader extends AsyncTask<Void, Void, Void> {
private LoaderRequiredOps presenter;
public Loader(LoaderRequiredOps presenter){
this.presenter = presenter;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
presenter.onPreLoad();
}
#Override
protected Void doInBackground(Void... params) {
presenter.onLoad();
return null;
}
#Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
presenter.onDoneLoading();
presenter = null;
}
}
Now, when I try to execute the method reload() from the SellProductFragment i get the 'Only the original thread that created a view hierarchy can touch its views.'
This does not happen if the SellProductFragment is attached first instead of CurrentSaleFragment.
What is happening here?
Your Async Loader class calls the presenters method onLoad() from a background thread during doInBackground().
My guess is that in the onLoad() method of the presenter, a view is referenced.
In order to change the view at this point, post the view logic as a Runnable to the UI thread (you said your presenter is the activity, so this should be possible from the onLoad method).
#Override
public void onLoad() {
runOnUiThread(new Runnable() {
#Override
public void run() {
// Your ui code here...
}
});
// Rest of your code here...
}
For an unknown reason, an unidentified configuration allows to execute the setting of an adapter for a ListView on the doInBackground() method.
Moved it to onPostExecute() and now it's working

Custom AsyncTask with callback

I need to write AsyncTask that will get reference on new object instances after the screen rotation. I wrote Callback interface and in JukeTask declared weak reference to this field.
JukeTask:
public abstract class JukeTask<Params, Progress, Result>
extends AsyncTask<Params, Progress, Result> {
private WeakReference<Callback<Progress, Result>> mWRCallback;
public void setCallback(Callback<Progress, Result> callback) {
mWRCallback = new WeakReference<>(callback);
}
#Override
protected void onPreExecute() {
Callback<Progress, Result> callback = mWRCallback.get();
if(callback != null) {
callback.onPreExecute();
}
}
#SuppressWarnings("unchecked")
#Override
protected void onProgressUpdate(Progress... values) {
Callback<Progress, Result> callback = mWRCallback.get();
if(callback != null) {
callback.onProgressUpdate(values);
}
}
#Override
protected void onPostExecute(Result result) {
Callback<Progress, Result> callback = mWRCallback.get();
if(callback != null) {
callback.onPostExecute(result);
}
}
public interface Callback<P, R> {
void onPreExecute();
#SuppressWarnings("unchecked")
void onProgressUpdate(P... values);
void onPostExecute(R result);
}
}
Example of using:
public class TestActivity extends AppCompatActivity implements JukeTask.Callback<Integer, Integer> {
private static final String TAG = TestActivity.class.getSimpleName();
private TextView mTextView;
JukeTask<Void, Integer, Integer> mTask;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mTextView = new TextView(this);
setContentView(mTextView);
mTextView.setText("Started");
//...
if(mTask == null) {
mTextView.setText("Task is null!");
mTask = new JukeTask<Void, Integer, Integer>() {
#Override
protected Integer doInBackground(Void[] params) {
int i = 0;
for (; i < 100000; ++i) {
Log.d(TAG, "Tick " + i);
}
//Do smth
return i;
}
};
mTask.setCallback(this);
mTask.execute();
}
}
#Override
public void onPreExecute() {
}
#Override
public void onProgressUpdate(Integer... values) {
}
#Override
public void onPostExecute(Integer result) {
mTextView.setText(result.toString());
}
}
Should I use WeakReference in JukeTask for Callback to not block a garbage collector?
How to save a reference to JukeTask? Because after the screen rotation it re-executes JukeTask.

How to do method onPostExecute initiate new Activity

I have one task that execute the method doInBackground and return a boolean value. What I want is to initiate a new Intent but the method startActivity is not available. How can I do that?
My task:
public class LoginTask extends AsyncTask<String, Integer, Boolean> {
#Override
protected Boolean doInBackground(String... params) {
boolean sucess;
//do some stuff
return sucess;
}
#Override
protected void onPostExecute(Boolean result) {
if (result) {
//startActivity(new Intent(this, MainViewActivity.class));
//it doesn't find startActivity
}
}
}
Pass the Activity that starts the AsyncTak in the constructor
public class LoginTask {
private Context mCtx;
public LoginTask(Context ctx){
mCtx = ctx;
}
....
#Override
protected void onPostExecute(Boolean result) {
if (result) {
mCtx.startActivity(new Intent(mCtx, MainViewActivity.class));
}
}
}
A remark about previous replies:
Please remember to do not leak your activity. Use WeakReference class:
public static class LoginTask extends AsyncTask<String, Integer, Boolean> {
WeakReference<Activity> mActivityReference;
public LoginTask(Activity activity){
this.mActivityReference = new WeakReference<Activity>(activity);
}
#Override
protected Boolean doInBackground(String... params) {
boolean sucess;
//do some stuff
return sucess;
}
#Override
protected void onPostExecute(Boolean result) {
if (result && mActivityReference.get() != null) {
Activity activity = mActivityReference.get();
activity.startActivity(new Intent(activity, MainViewActivity.class));
}
}
}
You need to create the task with a reference to the activity or context that spawned it.
public class LoginTask extends AsyncTask<String, Integer, Boolean> {
Activity mActivity;
public LoginTask(Activity activity){
this.mActivity = mActivity;
}
#Override
protected Boolean doInBackground(String... params) {
boolean sucess;
//do some stuff
return sucess;
}
#Override
protected void onPostExecute(Boolean result) {
if (result) {
mActivity.startActivity(new Intent(mContext, MainViewActivity.class));
}
}
}
Are you sure that startActivity is not available? I just tested it and it works fine for me.
I think you should replace the this in your line, because the this doesn't refer to the Activity, it refers to the ASyncTask.
startActivity(new Intent(getApplicationContext(), MainViewActivity.class));
That should work.
this inside onPostExecute() refers to AsyncTask class instance.
Use YourActivityName.this instead:
startActivity(new Intent(ParentActivity.this, MainViewActivity.class));

ActionBarSherlock change ProgressBar from external AsyncTask

I want to set ProgressVisibility(true) in an AsyncTask. Is the AsyncTask in the Main, all is fine.
public class GlanceActivity extends SherlockActivity implements ActionBar.OnNavigationListener {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//This has to be called before setContentView and you must use the
//class in com.actionbarsherlock.view and NOT android.view
requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
setContentView(R.layout.activity_glance);
}
public class TestTask extends AsyncTask<String, String, ArrayList<String>> {
#Override
public void onPreExecute() {
// Show IndeterminateProgressBar
setSupportProgressBarIndeterminateVisibility(true);
}
#Override
protected ArrayList<String> doInBackground(String... params) {
// Load some Data...
return null;
}
protected void onPostExecute(ArrayList<String> arg) {
// Hide IndeterminateProgressBar
setProgressBarIndeterminateVisibility(false);
}
}
}
But if I want to generate an Extra File for the AsyncTask, the setProgressBarIndeterminateVisibility is undefined for GroupPageTask...
How can I use this method in an seperate AsyncTask File?
GlanceActivity.java
public class GlanceActivity extends SherlockActivity implements ActionBar.OnNavigationListener {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//This has to be called before setContentView and you must use the
//class in com.actionbarsherlock.view and NOT android.view
requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
setContentView(R.layout.activity_glance);
}
}
GroupPageTask.java
public class GroupPageTask extends AsyncTask<String, String, ArrayList<String>> {
#Override
public void onPreExecute() {
// Show IndeterminateProgressBar
setSupportProgressBarIndeterminateVisibility(true);
}
#Override
protected ArrayList<String> doInBackground(String... params) {
// Load some Data...
return null;
}
protected void onPostExecute(ArrayList<String> arg) {
// Hide IndeterminateProgressBar
setProgressBarIndeterminateVisibility(false);
}
}
You could hand over the context during AsyncTask construction:
public class GroupPageTask extends AsyncTask<String, String, ArrayList<String>>
{
private Context context;
public AsyncTask(Context context)
{
this.context = context;
}
protected void onPreExecute()
{
((Activity) context).setProgressBarIndeterminateVisibility(true);
}
protected void onPostExecute(ArrayList<String> arg)
{
((Activity) context).setProgressBarIndeterminateVisibility(false);
}
}
Then create your AsyncTask with the new constructor from your activity:
GroupPageTask groupPageTask = new GroupPageTask(this);
With the Answer of Matt Handys, i found the right way...
GlanceActivity.java
public class GlanceActivity extends SherlockActivity implements ActionBar.OnNavigationListener {
public static Context context;
#Override
public void onCreate(Bundle savedInstanceState) {
GroupPageTask groupPageTask = new GroupPageTask(getSherlock());
}
}
GroupPageTask.java
public class GroupPageTask extends AsyncTask<String, String, ArrayList<Mannschaft>> {
private ActionBarSherlock sherlock;
#Override
public void onPreExecute() {
// Show IndeterminateProgressBar
sherlock.setProgressBarIndeterminateVisibility(true);
}
protected void onPostExecute(ArrayList<Mannschaft> arg) {
sherlock.setProgressBarIndeterminateVisibility(false);
}
}

Finish the calling activity when AsyncTask completes

My calling activity:
public class Hello extends Activity {
public void onCreate(Bundle savedInstanceState) {
MyTask mt = new MyTask(this);
mt.execute();
}
Now In MyTask (an external class):
public class MyTask extends AsyncTask<Void, Void, Void> {
private Context mContext;
public MyTask(Context context) {
mContext = context;
}
//doinbackground, etc
protected void onPostExecute() {
mContext.finish();
}
Other things are working as expected if I remove mContext.finish() above.
But if I'm calling mContext.finish() , I'm getting an error: The method finish() is undefined for the type Context (Eclipse doesn't show finish() when I write mContext. so that suggests I'm using finish() wrongly.)
What do I need to do to finish the calling activity Hello after MyTask completes the task
((Activity)mContext).finish();
Would be the correct way to cast a Context to an Activity and call its finish() method. Not sure why you'd want to finish an Activity from an AsyncTask though
What you can try to do instead of calling context.finish(), why don't you do a callback interface like this:
public interface TaskCallback{
void done();
}
Then you implement this into your Activity
public Hello extends Activity implements TaskCallback{
.....BUNCH OF ACTIVITY CODE.....
public void onCreate(Bundle savedInstanceState) {
MyTask mt = new MyTask(this);
mt.execute();
}
public void done() {
finish();
}
}
And instead of having Context as a parameter you have TaskCallback
public class MyTask extends AsyncTask<Void, Void, Void> {
private TaskCallback mCallback;
public MyTask(TaskCallback callback) {
mCallback = callback;
}
//doinbackground, etc
protected void onPostExecute() {
mCallback.done();
}
There you go, it gives you more flexibility to custom each implementation.
I got the same situation, then I do as follows:
public class MyTask extends AsyncTask<Void, Void, Void> {
private Activity mActivity;
private Context mContext;
public MyTask(Activity activity) {
mActivity = activity;
mContext = mActivity.getApplicationContext();
}
//doinbackground, etc
protected void onPostExecute() {
mActivity.finish();
}
Hope it help :)
Define a method in your activity class like this:
public void FinishAfterAsyncTask()
{
this.finish();
}
And call this method from the OnPostExecute method of the AsynTask class.
You could create a new private AsyncTask extended from your public one.
In this private AsyncTask you have access to the Activity stuff and you can override the onPostExecute method to finish it.
Your truly AsyncTask
public class MyPublicAsyncTask extends AsyncTask<Void, Void, Void> {
Context context;
public GetHorariosAsyncTask(Context ctx){
context = ctx;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
// prepare yourself for an async work
}
#Override
protected Void doInBackground(Void... params) {
// Do yout cool async stuff
}
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
// you're finish, let's tell to user
}
}
Your Activity with private AsyncTask
public class MyActivity extends Activity {
Activity mAct;
#Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
mAct = this;
}
private class MyPrivateAsyncTask extends MyPublicAsyncTask {
public MyPrivateAsyncTask(Context ctx) {
super(ctx);
// TODO Auto-generated constructor stub
}
#Override
protected void onPostExecute(Void result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
// our async task is completed! let's take care of this activity
mAct.finish();
}
}
}
Can you try
this.finish()
Seems like its because of calling it using mContext that it says undefined.

Categories

Resources