I have an activity which contains a ViewPager inside it.The ViewPager's Adapter is FragmentStatePagerAdapter. Each page is Fragment.The Fragment contains a number of Threads. My problem is, I have to stop all the threads inside the fragment when ViewPager's page is changed.How can I do this ?
you have asked about communication between activity and fragment that you achieve using interface:
Your Fragment:
public class YourFragment
extends Fragment{
private OnListener listener;
public interface OnListener
{
void onChange();
}
void initialize( OnListener listener)
{
this.listener = listener;
}
//onview pager change call your interface method that will go to the activity as it has the listener for interface.
listener.onChange();
}
Your Activity:
public class yourActivity
extends Activity
implements yourFragment.OnListener
{
// intialize the method of fragment to set listener for interface where you define fragment.
yourFragment.initialize( this );
// implement what you want to do in interface method.
#Override
public void onChange()
{
// implement what you want to do
}
}
hope it will help.
Android's philosophy with applications is to kill processes, so maybe following the same idea you could kill your Threads. Be aware though that this can lead to deadlocks if your Threads own locks, or monitors.
A more serious approach to me seems to use Thread.interrupt() from your Activity. Then your Threads in your Fragment have to check Thread.interrupted for interruption, and finish gracefully if they've been interrupted.
You can use Thread.join() if you want some synchronous behavior
In addition, you can wait for a certain amount of time for your Thread to finish gracefully using a Timer, then kill them on timeout.
Please have a look at java.lang.Thread
To let this be more easy to implement, you could use a ThreadPoolExecutor or some other helper of java.util.concurrent package.
Related
I have multiple fragments which does the same thing but presented in different way to the user. However, the functionality in all those fragments more like same as in delete, add etc. That said, I do not want to duplicate the code. Therefore created a manager class so that I could have the centralized code. But, the problem now is, when the user is performing an action say, when the user is deleting an item, the fragment does not get refreshed. So, I need to send the message to the fragment from the manager class to refresh the list. I have the following pseudo code to give an insight...
public class MyFragment extends Fragment{
ManagerClass mManagerClass;
private void onItemSelected() {
mManagerClass = new ManagerClass(itemId);
}
public void refreshItems() {
ItemDao.query();
}
}
public class ManagerClass {
public ManagerClass(int itemId) {
DeleteItem(itemId);
}
private void DeleteItem(int itemId) {
//when this task completes it should call the MrFragment.refreshItems();
//Keep in mind that I cannot pass the Fragment becuse this ManagerClass is designed to handle more than two fragments
//MAY BE I SHOULD DO CALLBACK BUT HOW?.... When i try to implement there several callbacks but not sure which one should I use and how...
}
}
Any help would be greatly appreciated...
I was so stupid and dumb at the time. There are multiple ways to achieve this but the quick resolutions are:
1. Have a ABSTRACT class and extend the fragment out of it or
2. Use the OBSERVER pattern
I went with the second option, Observer pattern and works like a charm!
Would it be an anti-pattern if from a Presenter layer I open an Activity?
If so, should I manage the navigation of the app from the View Layer?
Yes it's an anti-mvp-pattern. Based on passive view in MVP, you lost your testability, because you don't have to deal with the android framework in your presenter.
So it's better to manage the navigation of the app from the View Layer.
class MyPresenter {
MyPresenter.View view;
void backButtonClicked() {
view.navigateToHomeScreen();
}
public interface View {
void navigateToHomeScreen();
}
}
class MyActivity extends Activity implements MyPresenter.View {
#Override
void navigateToHomeScreen() {
startActivity(...)
}
#OnClick(R.id.my_button)
void onClick() {
presenter.backButtonClicked();
}
}
Also another advantage of this way is that it will be easy to replace activity with a fragment or a view.
Edit 1:
Morgwai said this way will break separation of concern and single responsibility, but you cannot have single responsibility every where. Sometime you need to violate it. Here is an example from Google for MVP:
TaskDetailPresenter calls ShowEditTask which is responsible to open a new Activity inside TaskDetailFragment.
But also you can use CommandPattern which is a better approach
interface NavigationCommand {
void navigate();
}
So, Presenter will use it when it needs.
As I wrote in my comment to the accepted answer, I think that managing navigation from the view layer is a clear breaking of separation of concerns rule: views should contain ONLY methods to update current UI screen.
The problem originates from the android platform design as Activity and Fragment classes contain both methods to operate on UI screen and to send intent objects that start other activities like startActivity.
A clean way to solve this would be to create some Navigator interface that would contain methods related to navigation, make activities implement it and inject it into presenters as well. This way at least from the presenters' standpoint navigation and UI manipulation would be separated. It may however look odd from activities' standpoint: now they would often implement both interfaces (Navigator and View) and pass their reference 2 times to the presenter. If because of this reason you decide to manage navigation from your view layer then at least keep methods for navigating separate from those for manipulating UI: never perform navigation and UI manipulation in the same method.
In my opinion it would be better if you open an activity from the View Layer. I prefer that Presenter knows about Activity as little as possible.
If there is some condition of what activity should be started, you can use something like this:
public class Presenter {
private ViewsPresentation mViewsPresentation;
public void someButtonClicked() {
if (/*some condition*/) {
mViewsPresentation.startFirstActivity();
} else {
mViewsPresentation.startSecondActivity();
}
}
public interface ViewsPresentation {
void startFirstActivity();
void startSecondActivity();
}
}
I have made this solution (in Kotlin):
I created an Interface called ViewNavigator
interface ViewNavigator {
fun navigateTo(target: Class<*>)
}
Then I made the View Interface Implement it
interface View : ViewNavigator {
//...
}
Then the Actual View (the activity) can override the navigateTo function
override fun navigateTo(target: Class<*>) {
startActivity(Intent(this, target))
}
So, whenever I want to navigate to any activity, I can simply write that in the presenter class. For example:
override fun onAnimationFinished() {
view.navigateTo(HomeActivity::class.java)
}
At school we're now learning on how to make fragments more universal by using interfaces.
This technique is still kinda abstract and I don't really know when/how to use it.
Can anybody point me to some resources on how to use that technique (Could it be called interface callbacks?)
All help is very appreciated!
The callback approach, as you would call it, is as simple as Listener interface found in many parts of Java or Android. You may check the Observer pattern if you want to learn about a very general description. But if you already understand how to work with Listener, you will easily get the point about callbacks.
NOTE: Do not mix it with Callback term - these are not the same.
Suppose we have Activity MyActivity and Fragment MyFragment. We want to post some data from Fragment to Activity. Then let us create an interface within MyFragment:
public class MyFragment extends Fragment{
private PostDataCallback mCallback;//our Activity will implement this
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
// This makes sure that the container activity has implemented
// the callback interface. If not, it throws an exception
try {
mCallback = (PostDataCallback) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ " must implement OnHeadlineSelectedListener");
}
}
public interface PostDataCallback{
public void onPostData(Object data);
}
/*
we trigger this method when we calculated
data or something like that and want to post it*/
public void onSomeEvent(Object data){
mCallback.onPostData(data);
}
}
Our MyActivity will look like this:
public class MyActivity extends Activity implements MyFragment.PostDataCallback{
private Object data;
#Override
protected void onCreate(Bundle savedInstanceState){
getFragmentManager().beginTransaction().add(R.id.some_container_id, new MyFragment(), "my fragment");
}
#Override
public void onPostData(Object data){
this.data = data;
//some operations
}
}
So, MyFragment knows nothing about the implementation of it's callback. But it knows, that it can call the method onPostData(Object o) on the instance of PostDataCallback, which is held in the variable mCallback.
Thus, when MyFragment triggers it's mCallback.onPostData(data), MyActivity get's the result.
Exactly the same approach would work if we wanted to send message from MyActivity to MyFragment, but we would do it do it vice versa: the trigger method, callback interface definition and instance would reside in MyActivity, and MyFragment would implement the interface.
Here are steps:
Download sample data from http://developer.android.com/training/basics/fragments/index.html(given in right side) and also look at url to how to add fragments from xml or dynamically to performing fragment transaction operations..
Then would recommend you to go through with fragment guide..http://developer.android.com/guide/components/fragments.html
Once you understand complete life cycle and its fragment callback methods then would be easy to understand example given by Google as sample.
To defining interface in fragment to calling interface or passing callback to activity..
Let’s say you have two fragments which shows list as article titles and article details.
In your article list extends fragment list public class Fragment1 extends ListFragment
Set your list view using list adapter in oncreateview method.
ArrayAdapter<String> adapter = new ArrayAdapter<String>(getActivity(),
android.R.layout.simple_list_item_1, Array);
setListAdapter(adapter);
Now we need to display article details when user click on article, so we need to pass position to activity to it can call back corresponding article details to show in fragment2.
So when user click on article, system call onListItemClick callback method.
public void onListItemClick(ListView l, View v, int position, long id) {
super.onListItemClick(l, v, position, id);
Call interface here and pass article position
Define interface and pass position in method which activity will override.
public interface OnArticleSelectedListener {
public void onArticleSelected(int position);
}
In on attach method instantiates an instance of interface by casting the Activity, If the activity has not implemented the interface, then the fragment throws a ClassCastException. On success.
Override interface method to display article details by passing position as bundle data to Fragment2.
Hope it will help you to understand sample code.
You can simple create new Android Application project in eclipse.
Then create Android Object (Fragment) with callback methods. This will give you an idea for interfaces.
And then the same you can apply for activity to fragment.
I am working on an application using viewpagerindicator.
In my main activity that has the viewpagerindicator, I spin off a thread that does some computation and updates a an instance variable mString of the activity. I want to update a fragment in the viewpagerindicator with the mString. However, I can't seem to figure out the best way to reach the fragment.
Does anyone know of any good samples that do something similar to this?
Create a callback object in your Fragment, register it with your FragmentActivity. If mString is already set in FragmentActivity then you can return it immediately via the callback, otherwise, when the computation thread finishes, it can return the string via the callback. The callback method should do whatever the Fragment needs to do with the string, e.g. set the text of a TextView.
E.g. create an interface called DynamicDataResponseHandler as follows:
public interface DynamicDataResponseHandler {
public void onUpdate(Object data);
}
Then in your Fragment, implement that interface as follows:
private class MyStringDataResponseHandler implements DynamicDataResponseHandler {
#Override
public void onUpdate(Object object) {
mYourTextView.setText((String)object);
}
}
Your Fragment can then instantiate a MyStringDataResponseHandler object in its onCreate, pass that to the FragmentActivity via a method in the FragmentActivity like:
private MyStringDataResponseHandler mMyStringDataResponseHandler;
public void registerMyStringDataResponseHandler (DynamicDataResponseHandler callback) {
mMyStringDataResponseHandler = callback;
if(mString != null) {
mMyStringDataResponseHandler.onUpdate(mString);
}
}
And wherever in your Handler you obtain the value for mString, do something like this:
if(mMyStringDataResponseHandler != null) {
mMyStringDataResponseHandler.onUpdate(mString);
}
Do some reading on the concept of Callbacks to get a better understanding of what I'm doing above and other ways you can use them.
You want to update the UI of a Fragment in ViewPager after it is started, do i make it clear?
Ok, in this situation
You should add a public method in your custom Fragment.
Find the Fragment in your Activity.
Invoke the method after your calculation is done.
The question is same with this one.
I have Activity class, Controller class (normal java class use to control number of activity) and BusinessEngine class (normal java class use to process data).
When I need to do some calculation from activity, Activity will call Controller and Controller will call BusinessEngine to do the calculation. When BusinessEngine done with the calculation, it will pass the value back to Controller and finally let the activity know the calculation is complete.
The problem is how I callback Activity from Controller class? Or pass any data to Activity and notify it the data has been change?
Any "long" running tasks must be performed in a background thread. I'm not sure if your currently doing this for your task, so just in case your not, there are a couple of ways to do this. The first is to simply use a AsyncTask, the second is to create your own instance of AbstractExecutorService (AsyncTask uses ThreadPoolExecutor) and use that to post Runnable or Callables to. The later way may save you a lot of re factoring depending on your code base.
Assuming you're now running the task in a background thread, it's necessary to perform your UI updates on the UI thread. There are again a couple of ways to do this. One method is to post a runnable to the method Activity#runOnUiThread, the second is to use a Handler which has previously been created on the UI thread (which Activity#runOnUiThread does behind the scenes).
So, assume your Activity has a method #postResults(final Object o), and your controller has the method #doSomething(final Activity activity).
Your activity would look something like this.
public class MyActivity extends Activity {
Controller controller = ....
ExecutorService service = Executors.newFixedThreadPool(10);
private void startTask() {
Runnable r = new Runnable() {
public void run() {
c.doSomething(MyActivity.this);
}
}
service.submit(r);
}
public void postResults(final Object o) {
Runnable r = new Runnable() {
public void run() {
// Update your UI here
}
}
runOnUiThread(r)
}
}
and your controller
public class Controller {
public void doSomething(final Activity activity) {
// Perform some long running task here
activity.postResults(someObject);
}
}
Obviously this example could be tidied up (for example passing a interface to doSomething rather than the Activity), but hopefully it should be enough to understand what you need to do :)
Why are you looking for the controller to call you Activity? Normally, your Activity must call the controller via its methods and directly get results from them:
// Code in your Activity
result = controller.doSomething(args);
try using a android AsyncTask, if your method takes a long time to process. example
Add your classes to an Async task or if you're calling the classes and passing them from one class to the other.I would say to use static class. And provide some code so we can know how you are passing your data.
If not use general methods to call the superclass or the subclass.
My answer is a bit abstract as information is less.