I try to work with AsyncTaskLoader and I have one problem. I load in AsyncTaskLoader data from the internet then start other activity(BusModelsActivity) in method onLoadFinished
#Override
public void onLoadFinished(Loader<List<BusModelParcelable>> loader, List<BusModelParcelable> data) {
hideDialog();
Log.d("onLoadFinished", TestTags.TAG1);
Intent intent = new Intent(BusSearchParamActivity.this,BusModelsActivity.class);
intent.putParcelableArrayListExtra(AppVariables.BUS_MODELS_LIST, (ArrayList) data);
startActivity(intent);
}
but when I click back in activity BusModelsActivity and return to BusSearchParamActivity method onLoadFinished run again, and BusModelsActivity starts again. What to do with it? I call other activity when click at button:
public void pickUpButtonClick(View v) {
getSupportLoaderManager().initLoader(LOADER_MODELS,null,busModelsCallBack);
}
where busModelsCallBack is implementation of LoaderCallbacks interface. When I did debug it stoped only on onLoadFinished, not onCreateLoader or click button.
I am afraid to tell you that the AsyncTask behavior till now are not 100% granted. You have two ways to overcome this problem.
1)Do your actions in a Thread instead of AsyncTask. This will ensure that your code will be executed only once cause Thread never start twice until you want this. As following
new Thread(new Runnable() {
#Override
public void run() {
/All your code here
}
}).start();
2)Declare a static parameter in your activity called isPageLoaded initially with value false and set it to true inside your onLoadFinished after loading your page at the first time and check on its value before executing your onLoadFinished code as following:
#Override
public void onLoadFinished(Loader<List<BusModelParcelable>> loader, List<BusModelParcelable> data) {
if(!isPageLoaded){
hideDialog();
Log.d("onLoadFinished", TestTags.TAG1);
Intent intent = new Intent(BusSearchParamActivity.this,BusModelsActivity.class);
intent.putParcelableArrayListExtra(AppVariables.BUS_MODELS_LIST, (ArrayList) data);
startActivity(intent);
isPageLoaded = true;
}
}
Try:
private static boolean isClicked = false;
#Override
public void onLoadFinished(Loader<List<BusModelParcelable>> loader, List<BusModelParcelable> data) {
if(isClicked )
{
hideDialog();
Log.d("onLoadFinished", TestTags.TAG1);
Intent intent = new Intent(BusSearchParamActivity.this,BusModelsActivity.class);
intent.putParcelableArrayListExtra(AppVariables.BUS_MODELS_LIST, (ArrayList) data);
startActivity(intent);
isClicked = false;
}
}
public void pickUpButtonClick(View v) {
isClicked = true;
getSupportLoaderManager().initLoader(LOADER_MODELS,null,busModelsCallBack);
}
Related
I have a Fragment which contains a Progressbar. I retrieve it in onCreateView() method where setVisibility() works fine.
Now, when I try to set visibility of the same progressbar (declared in fragment at class level) inside onActivityResult() nothing happens. Here is the code.
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data){
if(requestCode == REQUEST_CODE_PROFILE_VIDEO_PATH){
if(resultCode == Activity.RESULT_OK) {
String profileVideoPath = data.getExtras().getString(ProfileVideoRecordingActivity.VIDEO_PROFILE_PATH);
Log.d("DEBUG", profileVideoPath);
//Upload to server
File profileVideo = new File(profileVideoPath);
if(profileVideo.exists()) {
pbarVideoUpload.setVisibility(View.VISIBLE);
FireBaseWrapper fileUploader = new FireBaseWrapper();
String serverFolderPath = "videoprofile";
String contentType = "video/mp4";
FireBaseAfterUpload afterUpload = new FireBaseAfterUpload() {
#Override
public void onSuccess(String uploadURL) {
Log.d("DEBUG", "Successfully uploaded video to server");
Log.d("DEBUG", uploadURL);
pbarVideoUpload.setVisibility(View.GONE);
ProfileService profileService = new ProfileService(TAG) {
#Override
protected void onPreServiceCall() {
}
#Override
protected void onPostServiceCall() {
}
#Override
public void afterSuccess(Object object) {
ReturnCode successCode = (ReturnCode) object;
if(successCode.getSuccess()){
Log.d("DEBUG", "Profile Video URL updated in DB");
}else{
Log.d("DEBUG", "Profile Video URL NOT updated in DB");
}
}
#Override
public void afterError() {
Log.d("DEBUG", "Profile Video URL NOT updated in DB");
}
};
profileService.updateVideoPath(uploadURL);
}
#Override
public void onProgress(String data) {
}
#Override
public void onFaliure() {
Log.d("DEBUG", "Error! Didn't upload");
pbarVideoUpload.setVisibility(View.GONE);
}
};
try {
fileUploader.upload(profileVideo, profileVideo.getName(), serverFolderPath, afterUpload, contentType, false);
}catch (FileNotFoundException e){
Log.e("DEBUG", "FileNotFoundException", e);
}
}
}
}
}
I tried calling setVisibility() inside an Handler and also on UI thread using runOnUiThread(). Both approaches didn't work.
How can I control visibility of progressbar inside onActivityResult() of Fragment?
I need it as I am uploading a file inside onActivityResult() and need to display progress.
I think you onActivityResult not triggered as it is in fragment. Please use the below code in your activity which hold the fragment.
public void onActivityResult(int requestCode, int resultCode, Intent intent) {
super.onActivityResult(requestCode, resultCode, intent);
Fragment fragment = (Fragment) getSupportFragmentManager().findFragmentByTag(fragmentTag);
if (fragment != null) {
fragment.onActivityResult(requestCode, resultCode, intent);
}
}
put this
pbarVideoUpload.setVisibility(View.GONE);
Inside this also like I mentioned,
#Override
public void afterSuccess(Object object) {
ReturnCode successCode = (ReturnCode) object;
if(successCode.getSuccess()){
pbarVideoUpload.setVisibility(View.GONE);
Log.d("DEBUG", "Profile Video URL updated in DB");
}else{
Log.d("DEBUG", "Profile Video URL NOT updated in DB");
}
}
Fragments onCreate() was called after onActivityResult(). Hence the views were getting reinitialized and progressbar was not displayed.
Created a static variable isVideoUploading. Set its values appropriately in onActivityResult() and used it to show/hide progressbar in onCreate().
This solved half the problem. The progressbar was now visible when uploading started.
Second half of the problem was to hide the progressbar on complete of firebase async upload method. Problem was that since upload was being done in background thread which started in onActivityResult() there was no way for onCreateView() to fire again after upload was complete.
For this I sent a broadcast intent using LocalBroadcastManager when upload was complete and registered it in the same fragment. Once broadcast was received I hid the progressbar.
I have trouble to return data from fragment to activity.
I have Activity A: is main activity for add product, user when click the text view (selectCategory) this activity show to user activity B which content fragment Bb(all type of Category), when user clicks in some of this categories, the app going to show user activity C which has fragment Cc (subcategories).
Here my problem: I need when the user clicks in some of this subcategory which content in fragment Cc to return data to activity A then show to the user.
A call --> B
categoryTextView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent i= new Intent(A.this,B.class);
i.putExtra("fragmenttype","CategoryFragment");
startActivityForResult(i,10);
}
});
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == 10) {
if (resultCode == RESULT_OK) {
titleProduct.setText(data.getStringExtra("nodecategory"));
}
}
}
return data from Cc fragment to A but nothing happened (I need from code to go to activity A to catch data in onActivityResult):
#Override
public void onClick(TreeNode node, Object value) {
Intent i = new Intent();
i.putExtra("nodecategory","hi");
getActivity().setResult(Activity.RESULT_OK, i);
getActivity().finish();
}
I tend to rely heavily on EventBus on handling some case like yours. Using EventBus makes our life simpler. We don't need to clutter our code with interface here and there.
A ---> B
First, A will launch B with:
Intent i= new Intent(A.this, B.class);
i.putExtra("fragmenttype","CategoryFragment");
startActivity((i); // No need using startActivityForResult,
// instead receive it from Event generated by B.class.
Then in B, send Event whenever there is something that A need to catch:
EventBus.getDefault().post(new MyEvent("passed_data"));
// You can finish B activity if its job finished.
finish();
With MyEvent class like:
public class MyEvent {
private String data;
public MyEvent(String data) {
this.data = data;
}
public String getData() {
return data;
}
}
In A, receive the Event:
#Subscribe
public void onEventMessage(MyEvent event) {
// process event here
mTextView.setText(event.getData);
}
For C --> A
Consider that we have show C activity. Whenever we want to inform A that something need to do based on C activities (something we do), we just need to fire Event with the data:
EventBus.getDefault().post(new DataFromCEvent("your_c_data"));
with DataFromCEvent like:
public class DataFromCEvent {
private String data;
public DataFromCEvent(String data) {
this.data = data;
}
public String getData() {
return data;
}
}
In A, you can receive it by adding:
#Subscribe
public void onEventMessage(DataFromCEvent event) {
// process event here
mTextView.setText(event.getData);
}
This also works with fragment. We only need to fire an Event for some changes that we need in other activities.
use Intent.FLAG_ACTIVITY_FORWARD_RESULT on your activity B.
Ex-> ActivityA -> ActivityB -> ActivityC - > ActivityA
ActivityA:
Intent intentB = new Intent(this, ActivityB.class);
startActivityForResult(intentB, requestCode);
ActivityB: activity B will forward to
Intent intentC = new Intent(this, ActivityC.class);
intentC.setFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
startActivity(intentC);
finish();
ActivityC:
setResult(resultCode);
finish();
I have my main Activity with a fragment, which has a Recyclerview retrieving all the data populated from the database. In this fragment I got a button which calls another activity to insert an object into the database.
The problem is when the Activity ends and returns to the Main Activity the Recyclerview doesn't show the new item I just created. I tried with this piece of code:
#Override
public void onResume() {
super.onResume();
adapterItem.addItem(MyApplication.getWritableDatabase().getAllItems());
listProjectsView.scrollToPosition(0);
}
The function getAllItems retrieve all the data from sqlite.
On my adapterItem from my Recyclerview I got this:
public void addItem(ArrayList<Item> listItems) {
this.listItems = listItems;
notifyItemInserted(0);
}
It works "fine". The main problem is when I switch to another application in progress in my mobile and I return to my developed app the onResume method switches on and show again my last insert, populating twice this item (and so on if I do it again).
Thanks
Pass the new item back to MainActivity, then deal with it yourself.
1.In MainActivity, use startActivityForResult to start the second Activity, like this:
startActivityForResult(new Intent(this, SecondActivity.class), REQUEST_CODE);
REQUEST_CODE is an int.
2.In second Activity, override finish like this:
#Override
public void finish() {
Intent returnIntent = new Intent();
returnIntent.putExtra("passed_item", itemYouJustCreated);
// setResult(RESULT_OK);
setResult(RESULT_OK, returnIntent); //By not passing the intent in the result, the calling activity will get null data.
super.finish();
}
3.In MainActivity, override onActivityResult like this:
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_CODE && resultCode == RESULT_OK) {
YourItem passedItem = data.getExtras().get("passed_item");
// deal with the item yourself
}
}
You can create static recyclerview (let say mRecyclerview) in the activity(let say firstActivity) which displays your recyclerview .
And when you add new item to your list in the other activity(let say secondActivity), you can just use
firstActivity.mRecyclerview.getAdapter().notifyDataSetChanged();
I use this way for a while and didn't encounter any performance drawback but test it with your own code for sure.
If it may help someone...
I had the same:
"I have my MainActivity with a fragment, which has a RecyclerView retrieving all the data populated from the database. In this fragment, I got a button that calls another activity(insertA) to insert an object into the database.
The problem was when the activity(insertA) ends and returns to the Main Activity the RecyclerView doesn't show the new item I just created."
So I used this in Fragment button which calls another activity(insertA) I just called
btn_addNew.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent myIntent = new Intent(context, insertA.class);
startActivity(myIntent);
}
});
WITHOUT FINISHING with finish(); !!!!!!!!!!!!
In insertA Activity in the method AddNewThingToTheDataBase() insted of finish(); or startActivity(Intent); just put onBackPressed();
public void AddNewThingToTheDataBase(){
*****Inserting in DB code;
onBackPressed();
}
And in Main Activity add this code
#Override
public void onResume() {
super.onResume();
*YourUpdateRecyleViewFunction();*
}
Try Like this,
Intent intent = new Intent(Context, YourClass);
startActivityForResult(intent, ADD_ITEM);
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == Activity.RESULT_OK) {
if (requestCode == ADD_ITEM){
adapterItem.addItem(MyApplication.getWritableDatabase().getAllItems());
listProjectsView.scrollToPosition(0);
}
}
}
hope it will work for you
You can make the recyclerView static and initialize it in onCreate method
public class MainActivity extends AppCompatActivity {
protected static RecyclerView recyclerView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
recyclerView = findViewById(R.id.notes_recycler_view);
displayDataOnRecyclerView(this);
}
Then create a method in MainActivity to display the data in the recyclerView
public static void displayDataOnRecyclerView(Context context) {
//using a Linear Layout Manager
RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(context);
recyclerView.setLayoutManager(layoutManager);
//data that will be displayed in the adapter from sqlite database
DatabaseHandler databaseHandler = new DatabaseHandler(context);
List<Model> data = databaseHandler.getAllData();
//specifying the adapter
RecyclerView.Adapter adapter = new RecyclerViewAdapter(data,context);
recyclerView.setAdapter(adapter);
}
Finally, call the displayDataOnRecyclerView method in the other Activity
MainActivity.displayDataOnRecyclerView(otherActivity.this);
Is it possible to call startActivityForResult() from a non-activity class to get the results?
Scenario is something like this:
I have a class NonActivity (it doesn't derive from Activity as its not a UI).
This class will have bunch of functions(steps basically) to run.
One of the steps requires to show UI(Activity) and then get the result (user enter something).
Then been able to use that data in next following steps.
How can this be achieved without deriving from activity class as I don't have UI component?
Also since I don't want to derive from activity class that means I cannot override OnActivityResult(). Where results actually come from?
startActivityForResult() is only available from real on-screen activities, since it is a method in, well, Activity. Please redesign your application so that the user interface is driven from activities.
On the other hand, if your non Activity class is initialized and used from an onscreen Activity, you could pass that instance of the Activity to your class as a parameter in the constructor and use it to launch other Activities.
Be careful though. Using this method increases the risk of a memory leak, as the external class (Utils in my example) might keep a reference to the Activity even after its gone.
If all you want to do is access data, then you could try writing it to SharedPreferences or a Database or some files and then using the application context (passed in via a constructor again) to read it. This reduces the risk of a memory leak. Something like:
MyApiClass myApiClass = new MyApiClass(getApplicationContext());
EXAMPLE CODE
Main Activity:
public class Main extends FragmentActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Utils util = new Utils(this);
util.startTest();
}
#Override
protected void onActivityResult(int arg0, int arg1, Intent arg2) {
Toast.makeText(this, "onActivityResult called", Toast.LENGTH_LONG).show();
super.onActivityResult(arg0, arg1, arg2);
}
}
Utils class (which launches for result):
public class Utils {
Activity activity;
public Utils(Activity ac) {
activity = ac;
}
public void startTest() {
Intent i = new Intent(activity, Test.class);
activity.startActivityForResult(i, 1);
}
}
Test Activity:
public class Test extends FragmentActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Toast.makeText(this, "Test", Toast.LENGTH_LONG).show();
this.setResult(Activity.RESULT_OK);
this.finish();
}
}
StartActivityForResult from a class using a fragment with no visible GUI. You might find something like this in a utility class.
see runGetUserAccount below. It creates its own fragment and executes a startActivityForResult. Then it has it's own onActivityResult.
public class MyGooglePlay {
private static final int CONNECTION_FAILURE_RESOLUTION_REQUEST = 31502;
private ActionBarActivity activity;
private FragmentManager fragManager;
public MyGooglePlay(ActionBarActivity activity) {
this.activity = activity;
this.fragManager = activity.getSupportFragmentManager();
}
/**
* Starts an activity in Google Play Services so the user can pick an
* account
*/
private String mEmail = "";
static final int REQUEST_CODE_PICK_ACCOUNT = 1000;
public void runGetUserAccount() {
if (TextUtils.isEmpty(mEmail)) {
// run this code in gui less fragment so we can pickup the
// on activity result from inside the mygoogleplay class.
Fragment f = new Fragment() {
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
String[] accountTypes = new String[] { "com.google" };
Intent intent = AccountPicker.newChooseAccountIntent(null,
null, accountTypes, false, null, null, null, null);
startActivityForResult(intent, REQUEST_CODE_PICK_ACCOUNT);
}
#Override
public void onActivityResult(int requestCode, int resultCode,
Intent data) {
if (requestCode == REQUEST_CODE_PICK_ACCOUNT) {
if (resultCode == Activity.RESULT_OK) {
set_Email(data
.getStringExtra(AccountManager.KEY_ACCOUNT_NAME));
// getUsername();
}
super.onActivityResult(requestCode, resultCode, data);
}
//this is to verify the fragment has been removed.
//you can log or put a breakpoint to verify
#Override public void onDestroy(){
super.onDestroy();
}
};
FragmentTransaction fragmentTransaction = this.fragManager
.beginTransaction();
fragmentTransaction.add(f, "getusername");
fragmentTransaction.commit();
}
}
/**
* #param mEmail
* the mEmail to set
*/
private void set_Email(String mEmail) {
this.mEmail = mEmail;
if (!TextUtils.isEmpty(mEmail)) {
// TODO notify caller email is ready;
// activity.onEmailReady(mEmail);
}
//we are done with the "getusername" fragment
Fragment f = fragManager.findFragmentByTag("getusername");
if (f!=null) {
fragManager.beginTransaction().remove(f).commit();
}
}
}
U should pass context as Activity,then u will get solution.
try this below code.it will work
In non Activity class
public class nonActivity {
public static void method(Activity activity)
{
Intent intent = new Intent(activity, SecondActivity.class);
activity. startActivityForResult(intent, REQUEST_CODE);
}
}
In SecondActivity
Intent intent = getIntent();
intent.putExtra("data", "data"); //here u can pass data to previous activity
setResult(RESULT_OK, intent);
finish();
In firstActivity
protected void onActivityResult(int requestCode, int resultCode, #Nullable Intent data) {
try {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_CODE && resultCode == RESULT_OK) {
String status = data.getStringExtra("data");
//Do what u want with data
}
} catch (Exception e) {
System.out.println("=====Exception=====" + e.toString());
}
}
If you want the result back from the activity to your normal class, supposed it is a class with a custom adapter within it.
you cannot use startActivityForResult because you are not in an activity
what I did is that i launched the activity from the class with an intent. Then I calculated or did what I have to. From this activity I send the information to the main class supposed with a method MainActivity.the_method() and in the main activity I changed the custom adapter o did what I have to using the adapter object and calling adapter.getItem(position)
Hope this can give you an idea
I use a TabActivity with some tabs,each tab contain a ActvityGroup,each ActivityGroup manage more than one Activity.one of ActivtyGroups have three Activies:A,B and C.
At first A is created,when user click a button in A,it jump to B.
in B there are some important data which can be edited in C,when click a "edit"button in B,it jump to C.
if some data is edited in C,when i click back button,i want modify the same data in B.
what drive me crazy is when i use "finish()" in class C,my app exit directly.
I had searched many solutions on the net,bu none of them fit for my case,I don't know where is wrong,please help me or give me a example of how to use startActivityForResult() in ActivityGroup
here is my group:
public class MyGroup extends ActivityGroup
{
private int ID=0;
private AlertDialog dialog;
private Stack<View>history;
private LocalActivityManager manager;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
history = new Stack<View>();
manager = getLocalActivityManager();
Intent intent = new Intent(this,A.class);
startActivity(intent);
}
#Override
public void startActivity(Intent intent)
{
View view = manager.startActivity(""+ID++,intent).getDecorView();
history.push(view);
setContentView(view);
}
#Override
public void startActivityForResult(Intent intent,int requestCode)
{
// super.startActivityForResult(intent, requestCode);
View view = manager.startActivity(""+ID++,intent).getDecorView();
history.push(view);
setContentView(view);
}
/*
* if user edited data in C.class.
* when C.class finished,refresh data in the B.class
*/
#Override
protected void onActivityResult(int requestCode,int resultCode,Intent data)
{
Log.e("MyGroup","running");
super.onActivityResult(requestCode, resultCode, data);
if(resultCode==RESULT_OK)
{
//modify data in B.java
B subActivity=(B)(manager.getCurrentActivity());
subActivity.handleActivityResult(requestCode, resultCode, data);
}
}
/*
* when press back button, manage which page to show next
* if there is one page in stack,that means when press back button it will
* exit the app,so we add a dialog to notify user whether exit app or not
*/
#Override
public void onBackPressed()
{
int size=history.size();
if ( history.size()>= 2)
{
history.remove(size-1);
setContentView(history.get(size-2));
}
else
{
if(dialog==null)
{
createDialog();
}
dialog.show();
}
}
}
in B.class:
public void nextPage()
{
Intent intent=new Intent(B.this,C.class);
intent.putExtra("name", productAdapter.getName(position));
intent.putExtra("id", productAdapter.getID(position));
B.this.getParent().startActivityForResult(intent,11);
}
/*
* modify data in modifyItem
*/
public void handleActivityResult(int requestCode,int resultCode,Intent data)
{
String price=data.getExtras().getString("price");
String name=data.getExtras().getString("name");
String quantity=data.getExtras().getString("quantity");
productAdapter.setName(name, modifyItem);
productAdapter.setPrice(price, modifyItem);
productAdapter.setQuantity(quantity, modifyItem);
productAdapter.notifyDataSetChanged();
}
in C.class:
#Override
public void onBackPressed()
{
if(price!=null)
{
Bundle bundle=new Bundle();
bundle.putString("name",name);
bundle.putString("price",price);
bundle.putString("quantity",quantity);
this.getParent().setResult(RESULT_OK,new Intent().putExtras(bundle));
this.finish();
Log.e("C","inner");
}
Log.e("C","outer");
this.getParent().onBackPressed();
}
Why do you call finish? Pressing back means it will destroy
Your Activity from a ActivityGroup will not get the response calls directly.
You need to redirect from ActivityGroup.
Please see the below answer
Here is the solution. Please try this
https://stackoverflow.com/a/15047518/1403112