当前位置: 首页 > 知识库问答 >
问题:

Android片段-只有创建视图层次结构的原始线程才能接触其视图[重复]

魏彦
2023-03-14

这是我的主要活动:

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());

         
        }
    }
}

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

    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);
    }
}

当执行规则Fragment.setText((String)in.readObject());我得到这个错误:只有创建视图层次结构的原始线程可以触摸它的视图

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

还有别的办法吗?

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

共有2个答案

鱼志学
2023-03-14

为了回答您的主要问题,正在发生的事情是创建视图的线程是Main 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创建的片段的引用,请使用以下findFragmentByTag方案:

Fragment fragment = supportFragmentManager.findFragmentByTag("android:switcher:" + viewPager.getId() + ":" + fragmentPosition)
缪征
2023-03-14

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

        Device.BeginInvokeOnMainThread(
            () => { lblStatus.Text = "Updating..."; }
        );
 类似资料: