I have a MainActivity with tabhost , tabhost has three tab(Fragment) . SecondTab has a RecyclerView . In MainActivity, use the ActionBar button to go to another activity(NewClass) and add new values(MainActivity is still open) . After adding new values, I want to go back to MainActivity and refresh the RecyclerView to display new values.
I am using reactToPublishedEvent() method to refresh RecyclerView but doesnt work.
I could not solve my problem with using answers .
MainActivity
public class MainActivity extends AppCompatActivity implements Publisher{
private Listener listener;
protected void onCreate(Bundle savedInstanceState) {
//. . .
public void onClick(View view)
{
Intent intent = new Intent();
intent.setClass(this , NewClass.class);
startActivityForResult(intent , 1);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
super.onActivityResult(requestCode, resultCode, data);
if(requestCode == 1 && resultCode == RESULT_OK)
{
if(data != null)
{
listener.reactToPublishedEvent();
}
}
}
#Override
public void setListener(SecondTab listener) {
this.listener = listener;
}
interface Listener{
void reactToPublishedEvent();
}}
NewClass
boolean check = database.SaveClass(className, classDay, classTimeStart, classTimeEnd, Integer.parseInt(classNumber), uniName , checkMidTerm , checkEndTerm , checkPractical , checkProject , checkConference);
if(check)
{
Intent intent = new Intent();
setResult(RESULT_OK , intent);
finish();
}
SecondTab :
public class SecondTab extends Fragment implements MainActivity.Listener{
private RecyclerView recyclerView;
private DatabaseHandler database;
private RecyclerViewAdapter recyclerAdapter;
private List<ClassTable> classData;
#Nullable
#Override
public View onCreateView(final LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.activity_second_tab, container, false);
database = new DatabaseHandler(getContext());
recyclerView = view.findViewById(R.id.recyclerView_SecondTab);
classData = new ArrayList<>();
prepareAdapter();
return view;
}
private void prepareAdapter()
{
classData = database.getClassData();//Receive table data
recyclerAdapter = new RecyclerViewAdapter(this , getContext(), classData);
recyclerView.setAdapter(recyclerAdapter);
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
if(context instanceof Publisher){
((Publisher)context).setListener(this);
}
}
#Override
public void reactToPublishedEvent() {
recyclerAdapter.notifyDataSetChanged();//this line is not correct
}
Publisher
public interface Publisher {
void setListener(SecondTab listener);}
I recommend you to use Publisher/Listener pattern.
Publisher - publish some event. Listener react to this events.
So you need to create two interfaces:
interface Publisher{
void setListener(Listener listener)
}
And
interface Listener{
void reactToPublishedEvent()
}
Your MainActivity is publisher. It emmit some events, so your MainActivity should be updated:
class MainActivity extends AppCompatActivity implements Publisher{
private Listener listener;
... // Some your code here
#Ovveride
public void setListener(Listener listener){
this.listener = listener
}
}
Your SecondTab is Listener and should be updated as:
public class SecondTab extends Fragment implements AlertDialogShowClass.OnItemChange, Listener{
... //Your code here
#Ovveride
public void onAttach(Context context){
//Set this fragment in activity as Listener
if(context instance of Publisher){
((Publisher)context).setListener(this)
}
}
}
Then in onActivityResult method you can write something like this:
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
super.onActivityResult(requestCode, resultCode, data);
if(requestCode == 1 && resultCode == RESULT_OK)
{
if(data != null && listener!=null)
{
listener.reactToPublishedEvent()
}
}
}
There are two way
1.Local broadcast manager
2.Interface
Few methods to achieve the problem.
Observer Pattern.
Local BroadcastManager.
Directly update from the Fragment.
First and second methods are already described in above answers. So will describe the the third one.
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
super.onActivityResult(requestCode, resultCode, data);
if(requestCode == 1 && resultCode == RESULT_OK)
{
if(data != null)
{
Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.fragment);
if (fragment instanceof SecondTab)
{
((SecondTab)fragment).recyclerView.notifyDataSetChanged();
// Any Notify method as the requirement
}
}
}
}
Hope This will help.
Cheers!!
Related
I have created an activity which contains a button, a ViewPager and some fragments. When I click on the button a DialogActivity opens and connects to the web service using AsyncHttpClient and returns some strings which are pictures url, name, etc. to MainActivity. I want MainActivity to show the data in fragment specially the picture url (using Glide) but I can’t do this.
I appreciate it if you help me
DialogActivity:
void parsAndShowBiography(String response) {
try {
Gson gson = new Gson();
TheaudiodbBiography theaudiodbBiography = gson.fromJson(response, TheaudiodbBiography.class);
Intent returnIntent = new Intent(DialogActivity.this, MainActivity.class);
returnIntent.putExtra("artistThumb", theaudiodbBiography.getArtists()
.get(0).getStrArtistThumb());
returnIntent.putExtra("strArtist", theaudiodbBiography.getArtists()
.get(0).getStrArtist());
returnIntent.putExtra("artistFanart1", theaudiodbBiography.getArtists()
.get(0).getStrArtistFanart());
setResult(Activity.RESULT_OK, returnIntent);
finish();
MainActivity :
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == 100 && resultCode == Activity.RESULT_OK) {
???????????????????????
}
And this is the Fragment :
public class BiographyFragment extends Fragment {
static BiographyFragment instance;
public static BiographyFragment getInstance() {
if (instance == null) {
instance = new BiographyFragment();
}
return instance;
}
#Override
public View onCreateView(#NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.bigraphy_fragment, container, false);
return view;
}
I put some TextViews and ImageViews into Fragment xml file.
and if it helps this is the UX :
Hi guys i solved the question with this code :
MainActivity :
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == 100 && resultCode == Activity.RESULT_OK) {
View test=BiographyFragment.getInstance().getView();
Glide.with(this).load(data.getStringExtra("artistFanart1")).into(
(ImageView)test.findViewById(R.id.artistFanart1));
}
I am trying to make image selector for application.For that i am using multi-image-selector library which is perfeclty works when used in activity ,but here i want to use it in fragment.so in fragment OnActivityResult() method is not getting called.Can anyone help me to solve this?
Here's my code:
MainActivity.java:(My Main Activity)
public class MainActivity extends AppCompatActivity {
private static final int REQUEST_IMAGE = 2;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
getFragmentManager().beginTransaction().replace(R.id.frame, new Image_Selecter()).commit();
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
// Utilz.printLog("Parentactivity", "onActivityResult");
Log.e("hererererer", "hererererer");
if (requestCode == REQUEST_IMAGE) {
new Image().onActivityResult(requestCode, resultCode, data);
}
}
}
Image:(My Fragment)
public class Image extends Fragment {
private ArrayList<String> mSelectPath;
private static final int REQUEST_IMAGE = 2;
ArrayList<Uri> mMedia = new ArrayList<Uri>();
Uri uri;
ImageView img;
protected static final int REQUEST_STORAGE_READ_ACCESS_PERMISSION = 101;
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.activity_image, container, false);
img = (ImageView) view.findViewById(R.id.img);
img.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
pickImage();
}
});
return view;
}
public void pickImage() {
MultiImageSelector selector = new MultiImageSelector(getActivity());
selector.showCamera(true);
selector.multi();
selector.count(1);
selector.origin(mSelectPath);
selector.start(getActivity(), REQUEST_IMAGE);
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_IMAGE) {
if (resultCode == getActivity().RESULT_OK) {
mSelectPath = data.getStringArrayListExtra(MultiImageSelector.EXTRA_RESULT);
mMedia.clear();
for (String p : mSelectPath) {
Uri uri = Uri.parse(p);
mMedia.add(uri);
}
uri = mMedia.get(0);
Log.e("uri", " " + uri);
if (!uri.toString().contains("content://")) {
uri = Uri.fromFile(new File(uri.toString()));
Log.e("in if", " uri = " + uri);
}
try {
Glide.with(this)
.load(uri)
.placeholder(R.mipmap.ic_launcher)
.error(R.mipmap.ic_launcher)
.into(img);
} catch (Exception e) {
Log.e("Exceptionn", " " + e);
}
}
}
}
Try this in your activity
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
Log.d("Parentactivity", "onActivityResult");
if (requestCode == REQUEST_IMAGE) { //use request code as REQUEST_IMAGE while starting intent for camera
Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.frame);
fragment.onActivityResult(requestCode, resultCode, data);//calling fragments onActivityResult here
}
}
IIRC onActivityResult doesn't get called on a Fragment, it gets called on your parent Activity. You would need to catch this in the Activity and forward the result on to the fragment.
There are two methods which looks same but behaves little bit different.
If method is called by from activity, its not going to give callback to fragment unless called from fragment.
Activity.startActivityForResult()
Fragment.startActivityForResult()
Check out the library if there is way to calling it from fragment.
I dont know the library, just imaging if you can pass fragment to
MultiImageSelector selector = new MultiImageSelector(getActivity()); or selector.start(getActivity(), REQUEST_IMAGE);
Good luck
Emre
you have to call it with intent
public void pickImage() {
Intent intent = new Intent(getContext(), MultiImageSelectorActivity.class);
intent.putExtra(MultiImageSelectorActivity.EXTRA_SHOW_CAMERA, true);
intent.putExtra(MultiImageSelectorActivity.EXTRA_SELECT_COUNT, 1);
intent.putExtra(MultiImageSelectorActivity.EXTRA_SELECT_MODE, MultiImageSelectorActivity.MODE_MULTI);
intent.putStringArrayListExtra(MultiImageSelectorActivity.EXTRA_DEFAULT_SELECTED_LIST, mSelectPath);
startActivityForResult(intent, REQUEST_IMAGE);
}
if you were doing getActivity().startActivityForResult(intent, REQUEST_IMAGE);
the on OnActivityResult() will happen on activity instead of fragment. The way you are using it is like that, so you need to use the intent way.
also that maybe will make your code to work
public void pickImage() {
MultiImageSelector selector = new MultiImageSelector(getContext());
selector.showCamera(true);
selector.multi();
selector.count(1);
selector.origin(mSelectPath);
selector.start(getContext(), REQUEST_IMAGE);
}
How flow goes?
Activity 1 -----> Activity 2 (containing/inside) ------> Fragment
WhatI want to achieve?
Fragment (sends some data back to Activity 2) ----> Activity 2 (onBackPressed : collects that data & send it back to Activity 1) ---> Activity 1
How should I achieve above. I really don't want to use any variables/constants to cache the fragment data. Need to know any in-built method to handle this?
Moreover,
Activity 2 loads Fragment inside it.
In onBackPressed, I'm using setResult in Activity 2 to do standard data passing using startActivityForResult from Activity 1.
Also, if I write any method inside Fragment & call from Activity 2 using then due to that to/fro process a WHITE screen appears. So, really don't want to write own method & need to manage it while leaving the Fragment.
You should start Activity2 with startActivityForResult as below;
Intent i = new Intent(this, Activity2.class);
startActivityForResult(i, requestCode);
And in Activity2/fragment, you should finish acitivity as below;
Intent returnIntent = new Intent();
returnIntent.putExtra("result",result);
getActivity().setResult(Activity.RESULT_OK,returnIntent);
getActivity().finish()
And get result in Activity1 as below;
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (this.requestCode == requestCode) {
if(resultCode == Activity.RESULT_OK){
//Get result
}
}
}
Hope it helps.
To pass data from Activity 2 to Activity 1 you can use startActivityForResult() in Activity 1 to start Activity 2, and onActivityResult() in Activity 1 to receive that data.
To pass data from Fragment to Activity 2, I'd suggest to use some interface like
interface OnSomeDataListener {
void onSomeData(SomeData data);
}
Then implement a setter method for this interface to a fragment like
public void setOnSomeDataListener(OnSomeDataListener listener) {
this.listener = listener;
}
And then in Activity, when instantiating a Fragment:
YourFragment fragment = new YourFragment();
fragment.setOnSomeDataListener(new OnSomeDataListener() {
void onSomeData(SomeData data) {
//return the result
Intent intent = new Intent();
intent.putExtra("data", data);
setResult(RESULT_OK, intent);
finish();
}
}
And finally, in the fragment, when you want to return some data to Activity:
if(listener != null) {
listener.onSomeData(dataToReturn);
}
From your FirstActivity call the SecondActivity using startActivityForResult() method
Intent i = new Intent(this, SecondActivity.class);
startActivityForResult(i, 1);
In your SecondActivity set the data which you want to return back to FirstActivity onBackPressed of SecondActivity.
#Override
public void onBackPressed() {
super.onBackPressed();
Intent returnIntent = new Intent();
returnIntent.putExtra("result",result);
returnIntent.putExtra("bool",true);
setResult(Activity.RESULT_OK,returnIntent);
finish();
}
Now in your FirstActivity class write following code for the onActivityResult() method.
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == 1) {
if(resultCode == Activity.RESULT_OK){
String result=data.getStringExtra("result");
boolean bool = data.getBooleanExtra("bool");
}
if (resultCode == Activity.RESULT_CANCELED) {
//Write your code if there's no result
}
}
}//
To send data from Fragment to Second activity, you can use interface callback
public interface sendDataListener
{
void sendData(boolean foo);
}
Implement this listener to Second activity
Try to do this:
public class MyFragment extends Fragment{
private MyFragmentCommunicator myFragmentCommunicator;
....
myFragmentCommunicator.sendDataToActivity(name, image, isSend);
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
myFragmentCommunicator = (MyFragmentCommunicator)activity;
}
}
then declare your interface:
public interface MyFragmentCommunicator{
void sendDataToActivity(String name, String image, boolean isSend);
}
and then in your Activity do this:
public class MyActivity extends AppCompatActivity implements MyFragmentCommunicator{
#Override
public void sendDataToActivity(String name, String image, String price) {
//Manipulate the data
}
}
Hope it helps!!!
i acheived in Following way
In Activity write setters and getters
public String getFilePath() {
return filePath;
}
public void setFilePath(String filePath) {
this.filePath = filePath;
}
public String getFileName() {
return fileName;
}
public void setFileName(String fileName) {
this.fileName = fileName;
}
and in Fragment
filePath = ((YourActivity) getActivity()).getFilePath();
fileName=((YourActivity) getActivity()).getFileName();
if You are Using Same Fragment in More Than 1 Activity You can Create a constructor for that fragment and Pass context and check context is of which activity
public class BookmarkFragment extends Fragment {
private String filePath;
private String fileName;
Context contextCheckClass;
public BookmarkFragment(Context ctx ) {
this.contextCheckClass=ctx;
}
#SuppressLint("InflateParams")
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
group= (View)inflater.inflate(R.layout.fragment_bookmark, null);
if(contextCheckClass instanceof FirstReaderScreen){
filePath = ((FirstReaderScreen) getActivity()).getFilePath();
fileName=((FirstReaderScreen) getActivity()).getFileName();
// ispurchased=((FirstReaderScreen) getActivity()).isIspurchased();
}
else if(contextCheckClass instanceof MainReaderScreen){
filePath = ((MainReaderScreen) getActivity()).getFilePath();
fileName=((MainReaderScreen) getActivity()).getFileName();
// ispurchased=((MainReaderScreen) getActivity()).isIspurchased();
}
return group;
}
for calling fragment
BookmarkFragment bookmarkFragment=new BookmarkFragment(FirstReaderScreen.this);
getSupportFragmentManager()
.beginTransaction()
.add(R.id.LL_Fragment, bookmarkFragment)//LL_fragment is container
.addToBackStack(null)
.commit();
and thank you in advance for your suggestions.
MainActivity.java
RecyclerView.Adapter mAdapter;
#Override
...
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mRecyclerView = (RecyclerView) findViewById(R.id.RecyclerView);
mAdapter = new MyAdapter(getBaseContext(),TITLES,ICONS,NAME,EMAIL,PROFILE);
mRecyclerView.setAdapter(mAdapter);
mLayoutManager = new LinearLayoutManager(this);
mRecyclerView.setLayoutManager(mLayoutManager);
...}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
Bitmap bitmap = null;
String path = "";
mImageCaptureUri = data.getData();
path = getPath(mImageCaptureUri); //from Gallery
if (path == null)
path = mImageCaptureUri.getPath();
if (path != null)
bitmap = BitmapFactory.decodeFile(path);
mImageView.setImageBitmap(bitmap);
}
Myadapter.java
class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
...
Context mContext;
Activity mActivity;
private static final int SELECT_PICTURE = 1;
private String selectedImagePath;
public static class ViewHolder extends RecyclerView.ViewHolder {...}
MyAdapter(Context context, String Titles[],int Icons[],String Name,String Email, int Profile){
this.mContext = context;
mNavTitles = Titles
mIcons = Icons;
name = Name;
email = Email;
profile = Profile;
}
#Override
public void onBindViewHolder(MyAdapter.ViewHolder holder, int position) {
if(holder.Holderid ==1) {
holder.textView.setText(mNavTitles[position - 1]);
holder.imageView.setImageResource(mIcons[position -1]);
}
else{
holder.profile.setImageResource(profile);
holder.Name.setText(name);
holder.email.setText(email);
holder.profile.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mActivity = (Activity)mContext;
Intent imageIntent = new Intent();
imageIntent.setType("image/*");
imageIntent.setAction(imageIntent.ACTION_GET_CONTENT);
mActivity.startActivityForResult(Intent.createChooser(imageIntent, "Select photo"), 2);
}
});
}
}
It's possible call startActivityForResult in Adapter?
Why error is on mActivity = (Activity)mContext;?
p.s.: I tried to create method
public void startxx(Intent i){
startActivityForResult(i, 2);
}
and call this in Adapter...but Adapter wants statxx static and Activity non-static.
Context is Base class for Activity. You can not downcast object in Java. Thats why you can not perform mActivity = (Activity)mContext;.
You can not call startActivityForResult() from as Adapter class as it is method of Activity.java class. Here is one solution you can try -
- Declare one interface. say IObserver.java
public interface IObserver {
// change signature of method as per your need
public abstract void onItemClicked();
}
}
Write one method in Adapter class say
public void setListener(IObserver obs) {
mObserver = obs;
}
Implement IObserver interface in Activity class. You need to implement onItemClicked() method as well.
From onCreate() method of activity, call adapter.setListener(this);
In adapter class, from onClick() method, write code as below
holder.profile.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// It will call method from activity class where you can do startActivityForResult()
mObserver.onItemClicked();
}
});
Hope it will help.
I want to create simple communication Listener between Fragment and Activity, after define listener in Activity and implemented that from Fragment I get NullPointerException when I send String from Activity to Fragment, I want to send data from onActivityResult.
My activity is:
public class ActivityMain extends FragmentActivity {
public IonGetBarcodeFromScannerListener ionGetBarcodeFromScannerListener;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
G.currentActivity = this;
G.context = getBaseContext();
}
public void onActivityResult(int requestCode, int resultCode, Intent intent) {
IntentResult scanningResult = IntentIntegrator.parseActivityResult(requestCode, resultCode, intent);
if (scanningResult != null) {
String scanContent = scanningResult.getContents();
String scanFormat = scanningResult.getFormatName();
Log.e("barcode is: ", scanContent);
doSendBarcode(scanContent);
}
else{
Log.e("No scan data received! ", "");
doSendBarcode("");
}
}
public void doSendBarcode(String barcode){
ionGetBarcodeFromScannerListener.getBarcode(barcode);
}
public void setBarcodeListener(IonGetBarcodeFromScannerListener l){
ionGetBarcodeFromScannerListener = l;
}
public interface IonGetBarcodeFromScannerListener {
public void getBarcode(String barcode);
}
}
i get NullPointerException for this line:
ionGetBarcodeFromScannerListener.getBarcode(barcode);
My Fragment:
public class FragmentAddNewWayBill extends Fragment implements ActivityMain.IonGetBarcodeFromScannerListener{
private PtrClassicFrameLayout mPtrFrame;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
G.currentActivity = FragmentAddNewWayBill.this.getActivity();
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_new_waybill, container, false);
return view;
}
#Override
public void getBarcode(String barcode) {
Toast.makeText(G.currentActivity, "salam: " + barcode, Toast.LENGTH_SHORT).show();
}
}
I guess you are trying for activity and fragment communication in opposite way as I think interface will be defined in fragment and it's implementation will be done in activity. See http://developer.android.com/training/basics/fragments/communicating.html for more details
Seems you are never calling setBarcodeListener() so the field is never set, and therefore null.
-- update --
You could call it inside the fragment's onAttach() by using the return value from .getActivity().