android - Android Fragments - 只有创建视图层次结构的原始线程才能接触其视图
问题描述
这是我的主要活动:
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 中创建了 textview 但我在 setText 中编辑它,对吗?问题是我需要在程序执行期间多次编辑该文本,并且我无法在 onCreateView 中传输部分代码(我猜是让它像一个单独的线程一样运行?)因为我需要按顺序从 Socket 检索输入。
还有另一种方法可以做到这一点吗?
此外,假设我在第三个片段中有一个 Spinner 和一个“发送”按钮。当用户点击发送时,我应该将每个片段中的每个 textview 重置为空,并且我需要在 LearnTree 类的 PrimeThread 中重新启动执行。我怎样才能做到这一点?有没有办法从 mainactivity 检测发送按钮的 onClick 事件?
解决方案
要回答您的主要问题,正在发生的事情是创建视图的线程是主 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 Activity 中重启线程,则需要将线程存储在类变量中:
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)
推荐阅读
- javascript - 假设我有一个端点的基本 url 作为 www.domain.com 那么如何配置基本 url 以便它接受 www.domain.com 和 domain.com 的请求
- javascript - 我的数组返回多次打印相同的对象,使用 await Promise.all 和 map()
- flutter - MissingPluginException(在频道 top.kikt/gps 上找不到方法 gps 的实现)
- jenkins - 码头工人:来自守护进程的错误响应:詹金斯的清单:最新未找到:清单未知:清单未知
- javascript - 如何通过 jquery 函数获取详细信息?
- postgresql - 如何根据整数列中postgres中的值范围添加前导零
- c# - 所以我试图编写一个代码,每 750 毫秒更改一次文本框中的文字字体(arial,times new roman 等),但我做不到
- javascript - Bootstrap React 模态组件不能动态工作
- wso2 - WSO2 API 管理器和分析未在 docker 上连接
- spring - 无需小时即可将 ZonedDateTime 保存在数据库中