[英]Called method current selected fragment viewpager from parent activity?
[英]Calling methods on the current Fragment in a ViewPager from Activity
我正在聽android應用程序中的網絡活動。 當事件通過網絡出現時,我想更新一些駐留在應用程序中不同Fragment中的TextView。 現在,我有一個單屏幕應用程序,其中一個片段一次顯示在屏幕上。
如何在FragmentStatePagerAdapter管理的ViewPager內部現有Fragment上調用方法?
我能夠正確“繪制” UI,它會按預期顯示在屏幕上。 一切正常。 我很難過的事情是在后台線程向包含的Activity發送消息時調用一個方法。 該線程運行時間很長,並且會頻繁更新每個TextView(以倒數計時器為例)。
{thread}-> Actvity.handleMessage()-> {current} Fragment.update();
我試圖辨別什么是“當前”屏幕上的Fragment,以便我可以在其上調用方法以更新其TextViews。 我正在嘗試使用已讀過的findFragmentByTag方法,但它始終返回一個空的Fragment對象。
具體來說,我正在這樣做:
private String getFragmentTag(int viewPagerId, int fragmentPosition){
return "android:switcher:" + viewPagerId + ":" + fragmentPosition;
}
//Take the data from the thread (network) and react to it.
@Override
public boolean handleMessage(Message msg) {
//tell the fragment to update itself
//Log.v(TAG, "Handler: " + msg.what);
int currentFragmentIndex = pager.getCurrentItem();
Log.v(TAG, "Current Fragment Index: " + Integer.toString(currentFragmentIndex));
String fTag = getFragmentTag(pager.getId(), currentFragmentIndex );
Log.v(TAG, "Current Fragment Tag: " + fTag);
////THIS IS WHERE I AM HAVING TROUBLE!////
Log.v(TAG, "fragment: " + getSupportFragmentManager().findFragmentByTag(fTag));
////THIS ALWAYS OUTPUTS:
////fragment: null
//now do the update
//currentFragment.update(sensorDataMap);
return true;
}
基於大量閱讀,尤其是本篇文章- 使用FragmentPagerAdapter時如何獲取現有片段
這是相關的代碼...
MainActivity.java
public class MainActivity extends FragmentActivity implements Callback {
//receive messages from the other thread
private Handler handler = new Handler(this);
//the runnable listening to the network
private UDPListener udpl;
//we will parse the handler data into this map and store the values by int keys
private SparseArray<String> sensorDataMap = new SparseArray<String>();
//for logging and convenience
private static final String TAG = "BRRT";
//set up the fragment manager
private ViewPager pager;
private ScreenFragmenStatePagerAdapter fragmentManager;
private ScreenFragment currentFragment;
@Override
protected void onCreate(Bundle savedInstanceState) {
this.requestWindowFeature(Window.FEATURE_NO_TITLE);
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//remove the titlebar
this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
//keep the screen on while we are running
this.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
//set up the pager to move through the fragments
pager = (ViewPager) findViewById(R.id.viewPager);
fragmentManager = new ScreenFragmenStatePagerAdapter(getSupportFragmentManager());
pager.setAdapter(fragmentManager);
//start up the thread
Log.v(TAG, "start thread");
startUDPListener(handler);
Log.v(TAG, "past start thread");
}
//start up the thread to listen to the network, pass in the handle to this thread for messages
private void startUDPListener(Handler handler){
//spawn the listener thread, pass in the context and the handler object
try{
udpl = new UDPListener(this.getApplicationContext(), handler, sensorDataMap);
//TODO remove this debug flag
//DEBUG
udpl.setDebug(true);
//DEBUG
//set up the threaded reading, event throwing
Thread reader = new Thread(udpl);
reader.start();
} catch(Exception e){
//TODO real logging
Log.v(TAG, "caught after trying to start thread");
Log.v(TAG, e.getMessage());
}
}
//fragile, as this depends on the current naming convention for these fragment IDs in support/v4.
private String getFragmentTag(int viewPagerId, int fragmentPosition){
return "android:switcher:" + viewPagerId + ":" + fragmentPosition;
}
//Take the data from the thread (network) and react to it. This will get back unparsed strings
//and have to parse them in this thread, with the UI
@Override
public boolean handleMessage(Message msg) {
//tell the fragment to update itself
//Log.v(TAG, "Handler: " + msg.what);
int currentFragmentIndex = pager.getCurrentItem();
Log.v(TAG, "Current Fragment Index: " + Integer.toString(currentFragmentIndex));
String fTag = getFragmentTag(pager.getId(), currentFragmentIndex );
Log.v(TAG, "Current Fragment Tag: " + fTag);
Log.v(TAG, "fragment: " + getSupportFragmentManager().findFragmentByTag(fTag));
//Log.v(TAG, "Current Fragment Null? " + (currentFragment == null));
//now do the update
//currentFragment.update(sensorDataMap);
return true;
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
ScreenFragmenStatePagerAdapter .java
public class ScreenFragmenStatePagerAdapter extends FragmentStatePagerAdapter {
//the set of screens we are interested in.
private ArrayList<ScreenConfig> screens = new ArrayList<ScreenConfig>(6);
//for logging and convenience
private static final String TAG = "CC";
//convenience variable to let us know what screen we are pointing at, logically
private ScreenConfig currentScreenConfig;
public ScreenFragmenStatePagerAdapter(FragmentManager fm) {
super(fm);
//set up the data.
setupScreenData();
}
@Override
public Fragment getItem(int pos) {
//Log.v(TAG, "fragment pos: " + pos);
//hopefully this will always work
currentScreenConfig = screens.get(pos);
ScreenFragment sf;
if (currentScreenConfig.eventCount() == 1){
sf = OneUpScreen.newInstance();
} else {
sf = FourUpScreen.newInstance();
}
sf.setConfig(currentScreenConfig);
return sf;
}
@Override
public int getCount() {
return screens.size();
}
//class that maps the various events to their descriptions in a screen by screen way
//do all the grunt work of mapping screens to events
private void setupScreenData(){
//TODO convert this stuff to JSON so we can pass them around in Bundles
//a 1up screen
ScreenConfig configGun = new ScreenConfig("Gun");
configGun.addEvent(204, "TimeToGun","Ttg", "TTG");
screens.add(configGun);
//the rest are 4up screens
ScreenConfig configBowman = new ScreenConfig("Bowman");
configBowman.addEvent(5, "ExTws","Tws", "TWS");
configBowman.addEvent(34, "ExLayTimeOnStrb", "LayTimeOnStrb", "Time Stb");
configBowman.addEvent(37, "ExLayTimeOnPort", "LayTimeOnPort", "Time Prt");
configBowman.addEvent(113, "ExNextMarkTwa", "NextMarkTwa", "TWA");
screens.add(configBowman);
ScreenConfig configPit = new ScreenConfig("Pit");
configPit.addEvent(88, "ExMarkTime","MarkTime", "Time Mark");
configPit.addEvent(113, "ExNextMarkTwa", "NextMarkTwa", "Next TWA");
configPit.addEvent(111, "ExNextMarkRng", "NextMarkRng", "Next Range");
configPit.addEvent(112, "ExNextMarkBrg", "NextMarkBrg", "Next Brg");
screens.add(configPit);
ScreenConfig configUpwindTrimmer = new ScreenConfig("Upwind Trimmer");
configUpwindTrimmer.addEvent(5, "ExTws","Tws", "TWS");
configUpwindTrimmer.addEvent(1, "ExBsp", "Bsp", "BSP");
configUpwindTrimmer.addEvent(54, "ExTargBspN", "TargBspN", "Tgt BSP");
configUpwindTrimmer.addEvent(4, "ExTwa", "Twa", "TWA");
screens.add(configUpwindTrimmer);
ScreenConfig configDownwindTrimmer = new ScreenConfig("Downwind Trimmer");
configDownwindTrimmer.addEvent(5, "ExTws","Tws", "TWS");
configDownwindTrimmer.addEvent(4, "ExTwa", "Twa", "TWA");
configDownwindTrimmer.addEvent(53, "ExTargTwaN", "TargTwaN", "Tgt BSP");
configDownwindTrimmer.addEvent(58, "ExPolarBspPercent", "PolarBspPercent", "P Bsp %");
screens.add(configDownwindTrimmer);
ScreenConfig configHelmsman = new ScreenConfig("Helmsman");
configHelmsman.addEvent(5, "ExTws","Tws", "TWS");
configHelmsman.addEvent(1, "ExBsp", "Bsp", "BSP");
configHelmsman.addEvent(6, "ExTwd", "Twd", "TWD");
configHelmsman.addEvent(4, "ExTwa", "Twa", "TWA");
screens.add(configHelmsman);
}
}
activty_main.xml
<android.support.v4.view.ViewPager
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/viewPager"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
好的,我放棄了通常的方式, 轉而使用綠色機器人基於EventBus的體系結構。
以下是相關的Java文件,可幫助您了解我在此問題上的結論。 我基本上轉向在網絡線程中發布到EventBus並直接在Fragments中接收這些事件。 它極大地簡化了我的代碼。 對代碼有很多優化工作(諸如將Fragment和Activity生命周期處理程序拉入中心類或接口之類的事情),但這是將來的事情。
這是MainActivity.java文件。 現在,它所做的一切(基本上)是設置viewpager並啟動網絡線程。
public class MainActivity extends FragmentActivity {
//the runnable listening to the network
private UDPListener udpl;
//for logging and convenience
private static final String TAG = "BRRT";
//set up the fragment manager
private ViewPager pager;
private ScreenFragmenStatePagerAdapter fragmentManager;
//we will parse the handler data into this map and store the values by int keys
private SparseArray<String> sensorDataMap = new SparseArray<String>();
@Override
protected void onCreate(Bundle savedInstanceState) {
this.requestWindowFeature(Window.FEATURE_NO_TITLE);
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//remove the titlebar
this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
//keep the screen on while we are running
this.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
//set up the pager to move through the fragments
pager = (ViewPager) findViewById(R.id.viewPager);
fragmentManager = new ScreenFragmenStatePagerAdapter(getSupportFragmentManager());
pager.setAdapter(fragmentManager);
}
@Override
public void onResume(){
//start up the thread
Log.v(TAG, "start thread");
startUDPListener();
Log.v(TAG, "past start thread");
super.onResume();
}
//start up the thread to listen to the network, pass in the handle to this thread for messages
private void startUDPListener(){
//spawn the listener thread, pass in the context and the handler object
try{
udpl = new UDPListener(this.getApplicationContext(), sensorDataMap);
//TODO remove this debug flag
//DEBUG
udpl.setDebug(true);
//DEBUG
//set up the threaded reading, event throwing
Thread reader = new Thread(udpl);
reader.start();
} catch(Exception e){
//TODO real logging
Log.v(TAG, "caught after trying to start thread");
Log.v(TAG, e.getMessage());
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
這是片段。 它所做的只是配置其視圖,並偵聽EventBus上的事件。
public class OneUpScreen extends ScreenFragment {
private Button name;
private TextView c00Title, c00Data;
//DEBUG
public String title;
//DEBUG
private int counter = 0;
//for logging and convenience
private static final String TAG = "BRRT";
@Override
public void onResume(){
EventBus.getDefault().register(this);
super.onResume();
}
@Override
public void onDestroy(){
EventBus.getDefault().unregister(this);
super.onDestroy();
}
//process the bus messaging
public void onEventMainThread(ExpeditionEvent event){ <-- READ IT FROM THE BUS
Log.v(TAG, "OneUp event received: " + event.getEventId() + " : " + event.getEventScreenValue());
c00Data.setText(""+counter);
counter++;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.one_up_screen_layout, container, false);
name = (Button) v.findViewById(R.id.lblTitle);
c00Title = (TextView) v.findViewById(R.id.c00Title);
c00Data = (TextView) v.findViewById(R.id.c00Data);
Bundle bundle = this.getArguments();
//initial set up of the text on the screen
//null check
name.setText((bundle.getString("name") == null) ? "error" : bundle.getString("name"));
c00Title.setText((bundle.getString("c00Title") == null) ? "error" : bundle.getString("c00Title"));
title = bundle.getString("c00Title");
return v;
}
public OneUpScreen(){
}
public static OneUpScreen newInstance() {
OneUpScreen frag = new OneUpScreen();
return frag;
}
//attach the config for this instance.
@Override
public void setConfig(ScreenConfig sc){
//set up the data to paint the screen for the first time
Bundle b = new Bundle();
//now we have to parse some stuff into a bundle and send the bundle to the fragment
b.putString("name", sc.getName());
b.putString("c00Title", sc.getEvents().get(0).getCleanName());
b.putInt("c00Data", sc.getEvents().get(0).getEventID());
//pass it along
this.setArguments(b);
}
}
這是我在網絡偵聽器中所說的,這在Runnable的run)方法中...
//throw out an event for each item
EventBus.getDefault().post(new ExpEvent(key, value)); <-- PUT IT ON THE BUS
-!
我希望這能幫助下一個在ViewPager,FragmentStatePagerAdapters,Fragments或Android線程方面遇到麻煩的人。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.