Update UI from AsyncTask and handle properly screen rotate - android

This code doesn't works when rotate screen.
I try to use Handler but messages are dispached to previous Activity(before rotate) and to new Activity.
¿How can a thread send messages to new Activity?
Please doesn't suggest avoid to rotate screen.
public class SampleActivity extends Activity {
TextView text;
Handler handler;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
LinearLayout layout = new LinearLayout(this);
layout.setOrientation(LinearLayout.VERTICAL);
text = new TextView(this);
text.setText("HELLO");
layout.addView(text);
if (savedInstanceState != null) {
text.setText(savedInstanceState.getString("text"));
}
setContentView(layout);
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString("text", text.getText().toString());
}
#Override
protected void onStart() {
super.onStart();
new CounterTask().execute();
}
public class CounterTask extends AsyncTask<Void, String, Void> {
#Override
protected Void doInBackground(Void... params) {
for (int i = 0; i < 100; i++) {
try {
Thread.sleep(100);
publishProgress("Hello " + i);
} catch (Exception e) {
}
}
return null;
}
#Override
protected void onProgressUpdate(String... values) {
String str = values[0];
text.setText(str);
}
}
}

You can run the AsyncTask in a retained fragment.
public class TaskFragment extends Fragment {
private Callback mCallback;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
mCallback = (Callback) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ " must implement TaskFragment.Callback");
}
}
#Override
public void onDetach() {
super.onDetach();
mCallback = null;
}
public void execute(){
new CounterTask().execute();
}
public interface Callback {
void onTaskUpdate(String value);
}
public class CounterTask extends AsyncTask<Void, String, Void> {
#Override
protected Void doInBackground(Void... params) {
for (int i = 0; i < 100; i++) {
try {
Thread.sleep(100);
publishProgress("Hello " + i);
} catch (Exception e) {
}
}
return null;
}
#Override
protected void onProgressUpdate(String... values) {
if(mCallback != null) {
String str = values[0];
mCallback.onTaskUpdate(str);
}
}
}
}
Then, implement the callback in your activity and add the fragment via the fragment manager.
public class SampleActivity extends Activity implements
TaskFragment.Callback {
private static final String TAG_TASK_FRAGMENT = "task_fragment";
private TaskFragment mTaskFragment;
private TextView text;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
LinearLayout layout = new LinearLayout(this);
layout.setOrientation(LinearLayout.VERTICAL);
text = new TextView(this);
text.setText("HELLO");
layout.addView(text);
if (savedInstanceState != null) {
text.setText(savedInstanceState.getString("text"));
}
setContentView(layout);
FragmentManager fm = getFragmentManager();
mTaskFragment = (TaskFragment) fm.findFragmentByTag(TAG_TASK_FRAGMENT);
if(mTaskFragment == null){
mTaskFragment = new TaskFragment();
fm.beginTransaction()
.add(mTaskFragment, TAG_TASK_FRAGMENT)
.commit();
}
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString("text", text.getText().toString());
}
#Override
protected void onStart() {
super.onStart();
mTaskFragment.execute();
}
#Override
public void onTaskUpdate(String value) {
text.setText(value);
}
}

You could use AsyncTaskLoader. It will handle all rotations and lifecycle events of your activity/fragment.

Just add some configuration to prevent the recreating of activity when screen rotated, then everything's ok since there's only one instance of your activity.
Add the flowing line to your activity label in AndroidManifest.xml
android:configChanges="orientation|keyboardHidden|screenSize"
and this method to you SampleActivity.java
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
// when screen rotated, this method will be called instead of onCreate
}

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

Android Fragment with attached AsyncTask gives null after commit in Activity

I try to understand basic design pattern behind implementing AsyncTask and attaching it to Fragment. I follow numerous tutorials and implemented code (which gives nothing):
1) my Fragment class which contains AsyncTask:
public class MyFragment extends Fragment
{
public interface TaskCallback
{
void onPreExecute();
void onProgressUpdate(Integer... i);
void onPostExecute();
}
private TaskCallback mCallback;
private Task mTask;
#Override
public void onAttach(Activity activity)
{
super.onAttach(activity);
mCallback = (TaskCallback) activity;
}
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setRetainInstance(true);
mTask = new Task();
mTask.execute();
}
private class Task extends AsyncTask<Void, Integer, Void>
{
#Override
protected void onPreExecute()
{
mCallback.onPreExecute();
}
#Override
protected Void doInBackground(Void... params)
{
for (int i=0; i<100; i++)
{
publishProgress(i*10);
}
return null;
}
#Override
protected void onProgressUpdate(Integer... values)
{
mCallback.onProgressUpdate(values);
}
#Override
protected void onPostExecute(Void aVoid)
{
mCallback.onPostExecute();
}
}
}
2) my Main Activity code
public class MainActivity extends ActionBarActivity implements MyFragment.TaskCallback
{
private ProgressBar mProgress;
private MyFragment mTaskFragment;
private final static String TAG_FRAGMENT = "Fragment Task";
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mProgress = (ProgressBar) findViewById(R.id.progressBar1);
mProgress.setProgress(0);
//create fragment manager and fragment instance
FragmentManager mFM = getSupportFragmentManager();
mTaskFragment = (MyFragment) mFM.findFragmentByTag(TAG_FRAGMENT);
if(mFM == null)
{
mTaskFragment = new MyFragment();
mFM.beginTransaction().add(mTaskFragment, TAG_FRAGMENT).commit();
}
//I added this method, but to no help, the same without this method
mFM.executePendingTransactions();
}
#Override
public void onPreExecute()
{
mProgress.setVisibility(View.VISIBLE);
}
#Override
public void onProgressUpdate(Integer... i)
{
mProgress.setProgress(i[0]);
}
#Override
public void onPostExecute()
{
mProgress.setVisibility(View.INVISIBLE);
}
}
Basically, when run the code by Debug, after
mTaskFragment = (MyFragment) mFM.findFragmentByTag(TAG_FRAGMENT);
if(mFM == null)
{
mTaskFragment = new MyFragment();
mFM.beginTransaction().add(mTaskFragment, TAG_FRAGMENT).commit();
}
Gives mTaskFragment = null
I suppose here is the problem (mTaskFragment = null), the code doesn't create instance of MyFragment.
The question: how should I change the code to update ProgressBar from background by using this (Fragment + AsyncTask) pattern?
another question: Fragment onAttached(Activity a) is deprecated, now we should use onAttached(Context context), does it mean it should be implemented like: mCallback = (TaskCallback) context;?
Replace if(mFM == null) with if(mTaskFragment == null) you want to check if the fragment is null not the FragmentManager.
Also the updated method for:
public void onAttach(Activity activity) is public void onAttach(Context context)
Using: mCallback = (TaskCallback) context; is fine as Context is a superclass of Activty (just make sure your Activity is implementing the interface)

Why does FragmentManager.findFragmentByTag(TAG_TASK_FRAGMENT) not return null

I read this http://www.androiddesignpatterns.com/2013/04/retaining-objects-across-config-changes.html. And I played the example code in the link. To my surprise, fm.findFragmentByTag(TAG_TASK_FRAGMENT) does not return null when I rotate the phone, if I remove setRetainInstance(true) in the TaskFragment.onCreate(). I copied the code here with one line change (remove setRetainInstance(true)).
Please explain why fm.findFragmentByTag(TAG_TASK_FRAGMENT) does not return null in this case.
public class MainActivity extends Activity implements TaskFragment.TaskCallbacks {
private static final String TAG_TASK_FRAGMENT = "task_fragment";
private TaskFragment mTaskFragment;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
FragmentManager fm = getFragmentManager();
mTaskFragment = (TaskFragment) fm.findFragmentByTag(TAG_TASK_FRAGMENT);
if (mTaskFragment == null) {
mTaskFragment = new TaskFragment();
fm.beginTransaction().add(mTaskFragment, TAG_TASK_FRAGMENT).commit();
}
}
#Override
public void onPreExecute() { }
#Override
public void onProgressUpdate(int percent) { }
#Override
public void onCancelled() { }
#Override
public void onPostExecute() { }
}
public class TaskFragment extends Fragment {
interface TaskCallbacks {
void onPreExecute();
void onProgressUpdate(int percent);
void onCancelled();
void onPostExecute();
}
private TaskCallbacks mCallbacks;
private DummyTask mTask;
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
mCallbacks = (TaskCallbacks) activity;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// I remove this call to produce the problem
// setRetainInstance(true);
mTask = new DummyTask();
mTask.execute();
}
#Override
public void onDetach() {
super.onDetach();
mCallbacks = null;
}
private class DummyTask extends AsyncTask<Void, Integer, Void> {
#Override
protected void onPreExecute() {
if (mCallbacks != null) {
mCallbacks.onPreExecute();
}
}
#Override
protected Void doInBackground(Void... ignore) {
for (int i = 0; !isCancelled() && i < 100; i++) {
SystemClock.sleep(100);
publishProgress(i);
}
return null;
}
#Override
protected void onProgressUpdate(Integer... percent) {
if (mCallbacks != null) {
mCallbacks.onProgressUpdate(percent[0]);
}
}
#Override
protected void onCancelled() {
if (mCallbacks != null) {
mCallbacks.onCancelled();
}
}
#Override
protected void onPostExecute(Void ignore) {
if (mCallbacks != null) {
mCallbacks.onPostExecute();
}
}
}
}
SetRetainInstance controls whether the entire fragment (and its contents) is retained in memory or whether it is recreated as a new Fragment from its Bundle.
The only time it would return null is the very first time the app is run. After that it has been added to the FragmentManager and is always available. (Rotating the device does not clear the FragmentManager regardless of whether you use SetRetainInstance or not)
You seem to think that SetRetainInstance controls whether the fragment is kept in the FragmentManager or not. It does not.
In your example, the AsyncTask starts running the first time the Fragment is created. SetRetainInstance is used to stop the OnDestroy method of the Fragment being called. After an orientation change, the fragment and its running task is still in the FragmentManager and the task is still running. Without SetRetainInstance, when the Orientation change occurs, the fragment is destroyed and recreated from its bundle when you retrieve it from the FragmentManager. This puts the AsyncTask in a delicate state as the task could still be running even if its hosting Fragment has been destroyed possibly leading to a crash.
See this question for a more in depth explanation.
Understanding Fragment's setRetainInstance(boolean)

In which case getFragmentManager() return null?

Problem : getFragmentManager() return null randomly.
Case: I have one activity with tab. On each tab press I'm replacing the content container with fragment. In case of two fragment I'm doing network hit to fetch data from a server. For that I have written the following code:
public class FetchMessagesyFragmentTask extends Fragment {
private static final String TAG_EXTRA = "tab_extra";
private static final String TAG = "Test";
private String mData;
public static final FetchMessagesyFragmentTask newInstance(String data) {
FetchMessagesyFragmentTask fragment = new FetchMessagesyFragmentTask();
Bundle bundle = new Bundle();
bundle.putString(TAG_EXTRA, data);
fragment.setArguments(bundle);
return fragment;
}
public static interface TaskCallbacks {
void onPreExecute();
void onCancelled();
void onPostExecute(MessageResponse response);
}
private TaskCallbacks mCallbacks;
private FetchMessage mTask;
private boolean mRunning;
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
if (!(getTargetFragment() instanceof TaskCallbacks)) {
throw new IllegalStateException(
"Target fragment must implement the TaskCallbacks interface.");
}
mCallbacks = (TaskCallbacks) getTargetFragment();
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
mData = getArguments().getString(TAG_EXTRA);
}
#Override
public void onDestroy() {
super.onDestroy();
cancel();
}
public void execute(String data) {
if (!mRunning) {
mTask = new FetchMessage();
mTask.execute(data);
mRunning = true;
}
}
public void cancel() {
if (mRunning) {
mTask.cancel(false);
mTask = null;
mRunning = false;
}
}
public boolean isRunning() {
return mRunning;
}
private class FetchMessage extends AsyncTask<String, Void, MessageResponse> {
private ProgressDialogFragment progressDialog;
#Override
protected void onPreExecute() {
progressDialog = new ProgressDialogFragment.Builder().setMessage(
"Please wait...").build();
progressDialog.show(((Fragment) mCallbacks).getFragmentManager(),
"task_progress");
mCallbacks.onPreExecute();
mRunning = true;
}
#Override
protected MessageResponse doInBackground(String... params) {
//Doing network hit here and returning value.
return value;
}
#Override
protected void onCancelled() {
mCallbacks.onCancelled();
mRunning = false;
}
#Override
protected void onPostExecute(MessageResponse response) {
if (mCallbacks != null) {
FragmentManager manager = ((Fragment) mCallbacks)
.getFragmentManager();
//XXXXXXXX GETTING MANAGER AS NULL HERE SOMETIME XXXXXXXXXXXXXX
progressDialog.dismiss(manager);
if (response != null) {
if (Integer.parseInt(response.getResponseCode()) == NetworkConstant.SUCCESS
&& response.getChatMessage() != null) {
saveDataToDb(response);
}
}
mCallbacks.onPostExecute(response);
mRunning = false;
}
}
private void saveDataToDb(MessageResponse response) {
//SaveToDB
}
}
}
I'm following this url to handle network hit on orientation change. I have commented the line where I'm getting the issue.
Note
This code work fine in normal situation but crash when I switch tabs very fast.

Call method of interface implements with child fragment From container activity Android

I'm stuck with communication between activity and fragment using interface. I have created activity with child fragment. I wanna do some stuff with continuous thread defined in activity and during that thread when I'm getting some result at that time I wanna trigger to child fragment to do something.
My Container Activity
public class MySpaceActivity extends BaseDrawerActivity {
private OnSetLastSeenListener mListner;
public static Thread mThread = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
super.setHeaders(Const.MY_SPACE);
super.setSubmenus(Const.MY_SPACE,
Utils.getSubmenuList(Const.MY_SPACE, MySpaceActivity.this),
submenuBean);
// super.attachFragment(submenuBean);
}
#Override
public void setHeaderSubMenu(SubmenuBean subMenuBean) {
// txt_submenu.setText(subMenuBean.getSubmenu_name());
this.submenuBean = subMenuBean;
Log.print("::::: setHeaderSubMenu ::::");
super.attachFragment(submenuBean);
}
public void setsubFragment(SubmenuBean subMenuBean) {
this.submenuBean = subMenuBean;
super.attachSubFragment(submenuBean);
}
#Override
public void onBackPressed() {
super.onBackPressed();
popLastFragment();
}
private void popLastFragment() {
if (super.getNumberOfChilds() > 1) {
super.popSubFragment();
} else {
finish();
}
}
#Override
protected Fragment getFragement() {
StudentsFragment fragment = new StudentsFragment(Const.MY_SPACE,
getSubmenubean());
return fragment;
}
public SubmenuBean getSubmenubean() {
return submenuBean;
}
#Override
protected void onResume() {
// TODO Auto-generated method stub
super.onResume();
mThread = new Thread(new CountDownTimer(MySpaceActivity.this));
mThread.start();
}
#Override
protected void onStop() {
// TODO Auto-generated method stub
super.onStop();
if (mThread.isAlive()) {
mThread.interrupt();
mThread = null;
}
}
public void updateLastSeen(){
Log.print("::::::Call Interface::::::");
mListner.updateLastSeen();
}
class CountDownTimer implements Runnable {
private Context mContext;
private JSONObject mJsonObject;
private JSONArray mJsonArray;
public CountDownTimer(Context mContext) {
this.mContext = mContext;
}
// #Override
public void run() {
while (!Thread.currentThread().isInterrupted()) {
try {
HttpChatLastSeen mChat = new HttpChatLastSeen();
mJsonObject = mChat.Http_ChatLastSeen(mContext);
String mResult = mJsonObject.getString("Result");
if (mResult.equalsIgnoreCase(String
.valueOf(Const.RESULT_OK))) {
mJsonArray = mJsonObject.getJSONArray("UserData");
for (int i = 0; i < mJsonArray.length(); i++) {
mJsonObject = mJsonArray.getJSONObject(i);
new DbStudentMasterBll(mContext).update(
"last_seen", mJsonObject
.getString("LastSeen"), Integer
.parseInt(mJsonObject
.getString("UserId")));
}
} else {
Log.print("MY LAST SEEN Response : "
+ mJsonObject.toString());
}
updateLastSeen();
Thread.sleep(15000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} catch (Exception e) {
Log.print("ChatLastSeenThread : ", e.getMessage());
}
}
}
}
}
My Child Fragment With Interface :
public class StudentsFragment extends Fragment implements OnSetLastSeenListener{
TextView txt_submenu;
ListView list_students;
SubmenuBean submenuBean;
int Mainmenu;
MySpaceActivity mMySpaceActivity;
ArrayList<DbStudentMasterBean> studentsList;
StudentsAdapter mAdapter = null;
OnSetLastSeenListener mListner;
public StudentsFragment() {
super();
}
public StudentsFragment(int Mainmenu, SubmenuBean submenuBean) {
this.submenuBean = submenuBean;
this.Mainmenu = Mainmenu;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_students, container,
false);
mMySpaceActivity = (MySpaceActivity) getActivity();
txt_submenu = (TextView) view.findViewById(R.id.txt_submenu);
txt_submenu.setText(submenuBean.getSubmenu_name());
txt_submenu.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
mMySpaceActivity.openDrawer();
}
});
list_students = (ListView) view.findViewById(R.id.list_colleagues);
studentsList = new DbStudentMasterBll(getActivity()).getAllRecords();
mAdapter = new StudentsAdapter(getActivity(), studentsList, handler);
list_students.setAdapter(mAdapter);
list_students.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
DbStudentMasterBean bean = (DbStudentMasterBean) parent
.getAdapter().getItem(position);
Message msg = new Message();
msg.what = CHAT;
msg.obj = bean;
handler.sendMessage(msg);
}
});
return view;
}
Handler handler = new Handler() {
public void handleMessage(android.os.Message msg) {
switch (msg.what) {
case CHAT:
submenuBean.setTag(VIEWCHATSTUDENT);
DbStudentMasterBean bean = (DbStudentMasterBean) msg.obj;
mMySpaceActivity.setsubFragment(submenuBean);
break;
}
};
};
#Override
public void updateLastSeen() {
// TODO Auto-generated method stub
Log.print("!!!!!!!!!Refresh Adapter!!!!!!!!!!!");
mAdapter.notifyDataSetChanged();
}
}
My Interface :
public interface OnSetLastSeenListener {
public void updateLastSeen();
}
So I have implemented interface OnSetLastSeenListener with my child fragment StudentsFragment . Now I'm calling method of tht interface updateLastSeen() from my container activity with thread. But it is not getting trigger to child fragment where I have implemented interface. So I don't know whether it is good way to communicate or not? Let me take your help to suggest on this solution or best way to communicate from child fragment to parent activity.
Thanks,
It is better to use interface when you want to communicate something from Fragment to Activity and not vice versa.
In your case, you can directly call the method in Fragment from Activity through fragment object. No need to use interface.
Something like this (For static fragments)
StudentsFragment fragment = (StudentsFragment) getFragmentManager()
.findFragmentById(R.id.fragmentid);
if (fragment != null && fragment.isInLayout()) {
fragment.updateLastSeen();
}
For dynamic fragment you can use the fragment object directly.

Categories

Resources