Sunday, June 24, 2012

AsyncTask run in background thread of a invisible Fragment of ViewPager

Further exercise from last post "Communication between Fragments in ViewPager".

When a button in MyFragmentA clicked, it will start a AsyncTask in MyFragmentC, running in background and update a ProgressBar. When the ProgressBar finished, it will update MyFragmentB. It can be noted that the AsyncTask run in background even MyFragmentC is not in visible screen.

AsyncTask run in background thread of a invisible Fragment of ViewPager


Modify MyFragmentA.java and /res/layout/fragment_a.xml to add a Butten to start AsyncTask in MyFragmentC.
package com.exercise.AndroidViewPager;

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

public class MyFragmentA extends Fragment {
 
 EditText A_input;
 Button A_enter;
 Button A_startCProgress;

 @Override
 public View onCreateView(LayoutInflater inflater, ViewGroup container,
   Bundle savedInstanceState) {
  View myFragmentView = inflater.inflate(R.layout.fragment_a, container, false);
  
  A_input = (EditText)myFragmentView.findViewById(R.id.a_input);
  A_enter = (Button)myFragmentView.findViewById(R.id.a_enter);
  A_enter.setOnClickListener(A_enterOnClickListener);
  
  A_startCProgress = (Button)myFragmentView.findViewById(R.id.a_startcprogress);
  A_startCProgress.setOnClickListener(A_startCProgressOnClickListener);
  
  return myFragmentView;
 }
 
 OnClickListener A_startCProgressOnClickListener
 = new OnClickListener(){

  @Override
  public void onClick(View v) {
   // TODO Auto-generated method stub
   String TabOfFragmentC = ((AndroidViewPagerActivity)getActivity()).getTabFragmentC();
   
   MyFragmentC fragmentC = (MyFragmentC)getActivity()
     .getSupportFragmentManager()
     .findFragmentByTag(TabOfFragmentC);

   fragmentC.StartProgress();
   
  }
  
 };
 
 OnClickListener A_enterOnClickListener
 = new OnClickListener(){

  @Override
  public void onClick(View arg0) {
   
   String textPassToB = A_input.getText().toString();
   
   String TabOfFragmentB = ((AndroidViewPagerActivity)getActivity()).getTabFragmentB();
   
   MyFragmentB fragmentB = (MyFragmentB)getActivity()
     .getSupportFragmentManager()
     .findFragmentByTag(TabOfFragmentB);

   fragmentB.b_updateText(textPassToB);
   
   Toast.makeText(getActivity(), 
     "text sent to Fragment B:\n " + TabOfFragmentB, 
     Toast.LENGTH_LONG).show();
  }};

}


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
   android:layout_width="fill_parent"
   android:layout_height="fill_parent"
   android:orientation="vertical" >
   <TextView
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:text="It's Fragment A" />
   <EditText
       android:id="@+id/a_input"
       android:layout_width="match_parent"
       android:layout_height="wrap_content" />
   <Button
       android:id="@+id/a_enter"
       android:layout_width="match_parent"
       android:layout_height="wrap_content" 
       android:text="Enter to Fragment B"/>
   <Button
       android:id="@+id/a_startcprogress"
       android:layout_width="match_parent"
       android:layout_height="wrap_content" 
       android:text="Start Async Progress in Fragment C"/>
</LinearLayout>


Modify MyFragmentC.java and /res/layout/fragment_c.xml to add a ProgressBar and implement AsyncTask.
package com.exercise.AndroidViewPager;

import android.os.AsyncTask;
import android.os.Bundle;
import android.os.SystemClock;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ProgressBar;

public class MyFragmentC extends Fragment {
 
 ProgressBar cProgress;

 @Override
 public View onCreateView(LayoutInflater inflater, ViewGroup container,
   Bundle savedInstanceState) {
  View myFragmentView = inflater.inflate(R.layout.fragment_c, container, false);
  
  String myTag = getTag();
  ((AndroidViewPagerActivity)getActivity()).setTabFragmentC(myTag);
  
  cProgress = (ProgressBar)myFragmentView.findViewById(R.id.progressbar);
  
  return myFragmentView;
 }
 
 public void StartProgress(){
  new ProgressAsyncTask().execute();
 }
 
 public class ProgressAsyncTask extends 
  AsyncTask<Void, Integer, Void> {

  int myProgress;
  
  @Override
  protected void onPreExecute() {
   // TODO Auto-generated method stub
   super.onPreExecute();
   myProgress = 0;
  }

  @Override
  protected void onPostExecute(Void result) {
   // TODO Auto-generated method stub
   super.onPostExecute(result);
   
   String TabOfFragmentB = ((AndroidViewPagerActivity)getActivity()).getTabFragmentB();
   MyFragmentB fragmentB = (MyFragmentB)getActivity()
     .getSupportFragmentManager()
     .findFragmentByTag(TabOfFragmentB);
   fragmentB.b_updateText("Progress finished!");
   
  }

  @Override
  protected Void doInBackground(Void... arg0) {
   // TODO Auto-generated method stub
   while(myProgress<100){
    myProgress++;
    publishProgress(myProgress);
     SystemClock.sleep(100);  
   }
   return null;
  }

  @Override
  protected void onProgressUpdate(Integer... values) {
   // TODO Auto-generated method stub
   cProgress.setProgress(values[0]);
  }
  
 }

}


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
   android:layout_width="fill_parent"
   android:layout_height="fill_parent"
   android:orientation="vertical" >
   <TextView
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:text="It's Fragment C" />
 <ProgressBar
     android:id="@+id/progressbar"
     android:layout_width="fill_parent"
     android:layout_height="wrap_content"
     style="?android:attr/progressBarStyleHorizontal"
     android:progress="0"
     android:max="100"/>
</LinearLayout>


main activity, AndroidViewPagerActivity.java
package com.exercise.AndroidViewPager;

import java.util.ArrayList;

import android.app.ActionBar;
import android.app.ActionBar.Tab;
import android.app.FragmentTransaction;
import android.content.Context;
import android.os.Bundle;

import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.view.ViewPager;

public class AndroidViewPagerActivity extends FragmentActivity {
 
 ViewPager mViewPager;
 TabsAdapter mTabsAdapter;
 
 String TabFragmentB;
 String TabFragmentC;
 
 public void setTabFragmentB(String t){
  TabFragmentB = t;
 }
 
 public String getTabFragmentB(){
  return TabFragmentB;
 }
 
 public void setTabFragmentC(String t){
  TabFragmentC = t;
 }
 
 public String getTabFragmentC(){
  return TabFragmentC;
 }
 
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        mViewPager = new ViewPager(this);
        mViewPager.setId(R.id.pager);
        setContentView(mViewPager);
        
        final ActionBar bar = getActionBar();
        bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
        bar.setDisplayOptions(0, ActionBar.DISPLAY_SHOW_TITLE);
        
        mTabsAdapter = new TabsAdapter(this, mViewPager);
        mTabsAdapter.addTab(bar.newTab().setText("Fragment A"),
                MyFragmentA.class, null);
        mTabsAdapter.addTab(bar.newTab().setText("Fragment B"),
          MyFragmentB.class, null);
        mTabsAdapter.addTab(bar.newTab().setText("Fragment C"),
          MyFragmentC.class, null);

        if (savedInstanceState != null) {
            bar.setSelectedNavigationItem(savedInstanceState.getInt("tab", 0));
        }

    }

 @Override
 protected void onSaveInstanceState(Bundle outState) {
  //super.onSaveInstanceState(outState);
  outState.putInt("tab", getActionBar().getSelectedNavigationIndex());
 }
 
 public static class TabsAdapter extends FragmentPagerAdapter
  implements ActionBar.TabListener, ViewPager.OnPageChangeListener {
  
  private final Context mContext;
        private final ActionBar mActionBar;
        private final ViewPager mViewPager;
        private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>();
        
        static final class TabInfo {
            private final Class<?> clss;
            private final Bundle args;

            TabInfo(Class<?> _class, Bundle _args) {
                clss = _class;
                args = _args;
            }
        }

  public TabsAdapter(FragmentActivity activity, ViewPager pager) {
   super(activity.getSupportFragmentManager());
            mContext = activity;
            mActionBar = activity.getActionBar();
            mViewPager = pager;
            mViewPager.setAdapter(this);
            mViewPager.setOnPageChangeListener(this);
        }

  public void addTab(ActionBar.Tab tab, Class<?> clss, Bundle args) {
            TabInfo info = new TabInfo(clss, args);
            tab.setTag(info);
            tab.setTabListener(this);
            mTabs.add(info);
            mActionBar.addTab(tab);
            notifyDataSetChanged();
        }

  @Override
  public void onPageScrollStateChanged(int state) {
   // TODO Auto-generated method stub
   
  }

  @Override
  public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
   // TODO Auto-generated method stub
   
  }

  @Override
  public void onPageSelected(int position) {
   // TODO Auto-generated method stub
   mActionBar.setSelectedNavigationItem(position);
  }

  @Override
  public void onTabReselected(Tab tab, FragmentTransaction ft) {
   // TODO Auto-generated method stub
   
  }

  @Override
  public void onTabSelected(Tab tab, FragmentTransaction ft) {
   Object tag = tab.getTag();
            for (int i=0; i<mTabs.size(); i++) {
                if (mTabs.get(i) == tag) {
                    mViewPager.setCurrentItem(i);
                }
            }
  }

  @Override
  public void onTabUnselected(Tab tab, FragmentTransaction ft) {
   // TODO Auto-generated method stub
   
  }

  @Override
  public Fragment getItem(int position) {
   TabInfo info = mTabs.get(position);
            return Fragment.instantiate(mContext, info.clss.getName(), info.args);
  }

  @Override
  public int getCount() {
   return mTabs.size();
  }

 }

}


Download the files.

2 comments:

@ said...

Force close after first run!
Thank!

Brian-Mac said...

If some people are getting the force close problem; try changing the project.properties file to match the version it will run on and also change the manifest file to also match the version

ie
I changed the manifest and system.properties file to 19