Android碎片-只有创建视图层次结构的原始线程才能接触到它的视图



这是我的主要活动:

public class LearnTree extends AppCompatActivity {
private RulesFragment rulesFragment;
private TreeFragment treeFragment;
private PredictionFragment predictionFragment;
TabLayout tabLayout;
ViewPager viewPager;
private Button button;
private static ObjectOutputStream out;
private static ObjectInputStream in;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.learn_tree);
tabLayout=findViewById(R.id.tab_layout);
viewPager= findViewById((R.id.view_pager));
final ViewPagerAdapter viewPagerAdapter= new ViewPagerAdapter(getSupportFragmentManager());
viewPagerAdapter.addFragment(RulesFragment.getInstance(), "TREE RULES");
viewPagerAdapter.addFragment(TreeFragment.getInstance(), "REGRESSION TREE");
viewPagerAdapter.addFragment(PredictionFragment.getInstance(), "PREDICTION");
rulesFragment= (RulesFragment) viewPagerAdapter.getItem(0);
treeFragment= (TreeFragment) viewPagerAdapter.getItem(1);
predictionFragment= (PredictionFragment) viewPagerAdapter.getItem(2);
viewPager.setAdapter(viewPagerAdapter);
tabLayout.setupWithViewPager(viewPager);
LearnTree.PrimeThread p=new LearnTree.PrimeThread();
p.start();
}
private class PrimeThread extends Thread {
public void run() {
out= SocketObject.getOut();
in = SocketObject.getIn();

// print rules
rulesFragment.setText((String)in.readObject());
//print tree
treeFragment.setText((String)in.readObject());

}
}
}

这是我的3个片段之一,其他2个几乎相同:

public class RulesFragment extends Fragment {
// Store instance variables
private String title;
private int page;
private TextView rulesView;

public static RulesFragment getInstance() {
RulesFragment rulesFragment = new RulesFragment();
return rulesFragment;
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view= inflater.inflate(R.layout.rules_fragment, container, false);
rulesView= (TextView) view.findViewById(R.id.textview_treerules);
rulesView.setMovementMethod(new ScrollingMovementMethod());
return view;
}
public void setText(String text){
rulesView.setText(text);
}
}

当执行rulesFragment.setText((String)in.readObject());时,我得到了这个错误:只有创建视图层次结构的原始线程才能接触到它的视图

这是因为我在onCreateView中创建了文本视图,但我在setText中编辑它,对吗?问题是,在程序执行过程中,我需要多次编辑该文本,并且我无法在onCreateView中传输部分代码(我想是为了让它像一个单独的线程一样运行吗?(,因为我需要按顺序从Socket中检索输入。

有别的办法吗?

此外,假设我在第三个片段中有一个Spinner;发送";。当用户点击Send时,我应该将每个片段中的每个文本视图重置为空,并且我需要在LearnTree类的PrimeThread中重新启动执行。我该怎么做?有没有办法从主活动中检测发送按钮的onClick事件?

前面的答案非常完整。但是,您可以尝试调用:

Device.BeginInvokeOnMainThread(
() => { lblStatus.Text = "Updating..."; }
);

要回答您的主要问题,所发生的事情是创建视图的线程是主UI线程。因此,每当您想从不同的线程(在您的情况下是PrimeThread(更改UI上的某些内容时,都应该使用runOnUiThread来执行这些函数。

这意味着在你的代码中你应该有:

String rules = (String)in.readObject()
String tree = (String)in.readObject()
requireActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
// print rules
rulesFragment.setText(rules);
//print tree
treeFragment.setText(tree);
}
});

对于你最后一个关于让听众点击按钮的问题,你可以这样做:

Button buttonY = (Button)findViewById(R.id.buttonYName);
// Register the onClick listener with the implementation above
buttonY.setOnClickListener(new OnClickListener() {
public void onClick(View v)
{
(LearnTree)getActivity().primeThread.start(); // Assuming this is executed in the context of a Fragment
} 
});

如果你想在LearnTree活动中重新启动线程,你需要将线程存储在一个类变量中:

public LearnTree.PrimeThread primeThread;

或者将其声明为私有并拥有getter/setter,这取决于您。


此外,您应该像这样创建ViewPagerAdapter,否则您将出现崩溃:

public class ViewPagerAdapter extends FragmentPagerAdapter {
public ViewPagerAdapter(FragmentManager fragmentManager) {
super(fragmentManager);
}
@Override
public Fragment getItem(int position) {
if(position == 0) return new RulesFragment();
if(position == 1) return new TreeFragment();
if(position == 2) return new PredictionFragment();
throw new IllegalStateException("Unexpected position " + position);
}
@Override
public int getCount() {
return 3;
}
@Override
public CharSequence getPageTitle(int position) {
if(position == 0) return "TREE RULES";
if(position == 1) return "REGRESSION TREE";
if(position == 2) return "PREDICTION";

throw new IllegalStateException("Unexpected position " + position);
}
}

要获得对ViewPager创建的Fragment的引用,请使用以下findFragmentByTag方案:

Fragment fragment = supportFragmentManager.findFragmentByTag("android:switcher:" + viewPager.getId() + ":" + fragmentPosition)

最新更新