Fragment 如何从使用 http 和异步任务获取数据的 MainActivity 类中获取数据?

Posted

技术标签:

【中文标题】Fragment 如何从使用 http 和异步任务获取数据的 MainActivity 类中获取数据?【英文标题】:How Fragment can get data from MainActivity class that getting data using http and asycn task? 【发布时间】:2020-02-09 22:37:16 【问题描述】:

我正在使用 android Studio 创建一个 Android 应用。我正在使用导航抽屉模板。我想在主页片段中使用 http 和异步任务显示来自网络的数据。我从互联网上复制从网络获取数据的类的粘贴代码。

这是课程:

    class FetchThingspeakTask extends AsyncTask<Void, Void, String> 
        protected void onPreExecute() 
            Toast.makeText(getApplicationContext(), "Fetching Data from Server.Please Wait...", Toast.LENGTH_SHORT).show();
        
        protected String doInBackground(Void... urls) 
            try 
                URL url = new URL("https://api.thingspeak.com/channels.json?api_key=I9CEDD46LZX2HZTC");
                HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
                try 
                    BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
                    StringBuilder stringBuilder = new StringBuilder();
                    String line;
                    while ((line = bufferedReader.readLine()) != null) 
                        stringBuilder.append(line).append("\n");
                    
                    bufferedReader.close();
                    return stringBuilder.toString();
                
                finally
                    urlConnection.disconnect();
                
            
            catch(Exception e) 
                Log.e("ERROR", e.getMessage(), e);
                return null;
            
        
        protected void onPostExecute(String response) 
            if(response == null) 
                Toast.makeText(MainActivity.this, "There was an error", Toast.LENGTH_SHORT).show();
                return;
            
 // I want to get this response and use it in any fragment
            Toast.makeText(getApplicationContext(), response, Toast.LENGTH_LONG).show();
        
    

我将该类放在 MainActivity.java 中并在主要活动中执行它。我使用计时器和处理程序每​​分钟执行一次这个类。

我实际上得到了响应,但响应在片段中不可用。我想从调用 API 的类中获取数据并在所有片段中给出响应。

这是完整的主要活动代码:


public class MainActivity extends AppCompatActivity 

    private AppBarConfiguration mAppBarConfiguration;
    @Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        FloatingActionButton fab = findViewById(R.id.fab);
        fab.setOnClickListener(new View.OnClickListener() 
            @Override
            public void onClick(View view) 
                Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
                        .setAction("Action", null).show();
            
        );

        setRepeatingAsyncTask();

        DrawerLayout drawer = findViewById(R.id.drawer_layout);
        NavigationView navigationView = findViewById(R.id.nav_view);
        // Passing each menu ID as a set of Ids because each
        // menu should be considered as top level destinations.
        mAppBarConfiguration = new AppBarConfiguration.Builder(
                R.id.nav_home, R.id.nav_gallery, R.id.nav_slideshow,
                R.id.nav_tools, R.id.nav_share, R.id.nav_send)
                .setDrawerLayout(drawer)
                .build();
        NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);
        NavigationUI.setupActionBarWithNavController(this, navController, mAppBarConfiguration);
        NavigationUI.setupWithNavController(navigationView, navController);
    

    @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 onSupportNavigateUp() 
        NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);
        return NavigationUI.navigateUp(navController, mAppBarConfiguration)
                || super.onSupportNavigateUp();
    

    class FetchThingspeakTask extends AsyncTask<Void, Void, String> 
        protected void onPreExecute() 
            Toast.makeText(getApplicationContext(), "Fetching Data from Server.Please Wait...", Toast.LENGTH_SHORT).show();
        
        protected String doInBackground(Void... urls) 
            try 
                URL url = new URL("https://api.thingspeak.com/channels.json?api_key=I9CEDD46LZX2HZTC");
                HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
                try 
                    BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
                    StringBuilder stringBuilder = new StringBuilder();
                    String line;
                    while ((line = bufferedReader.readLine()) != null) 
                        stringBuilder.append(line).append("\n");
                    
                    bufferedReader.close();
                    return stringBuilder.toString();
                
                finally
                    urlConnection.disconnect();
                
            
            catch(Exception e) 
                Log.e("ERROR", e.getMessage(), e);
                return null;
            
        
        protected void onPostExecute(String response) 
            if(response == null) 
                Toast.makeText(MainActivity.this, "There was an error", Toast.LENGTH_SHORT).show();
                return;
            
            // I want to get this response and use it in any fragment
            Toast.makeText(getApplicationContext(), response, Toast.LENGTH_LONG).show();
        
    

    private void setRepeatingAsyncTask() 

        final Handler handler = new Handler();
        Timer timer = new Timer();

        TimerTask task = new TimerTask() 
            @Override
            public void run() 
                handler.post(new Runnable() 
                    public void run() 
                        try 
                            new FetchThingspeakTask().execute();
                        
                        catch(Exception e)
                            Log.e("ERROR", e.getMessage(), e);
                        
                    
                );
            
        ;

        timer.schedule(task, 0, 60*1000);  // interval of one minute

    


有什么建议吗?

更新:

我希望这个响应会在片段中动态更新

【问题讨论】:

【参考方案1】:

为片段声明全局变量

Fragment fragmentRef = new MyFragment() // your fragment name

现在在 onPostExecute() 内部

对于第一个 API 调用,使您的片段事务意味着从活动中膨胀片段

getFragmentManager().beginTransaction().replace(R.id.container, fragmentRef, "TAG).commit()

在片段中创建 setData() 方法并使用 fragmentRef 调用

fragmentRe.setData(response) //pass your data

现在对于下一个/后续 API 调用,使用 findFragmentByTag() 检查并从 fragmentManager 获取您的片段,一旦您获得片段引用,然后调用 setData() 方法

if( fragmentRef !=null)
    fragmentRef.setData(response)
  

【讨论】:

以上是关于Fragment 如何从使用 http 和异步任务获取数据的 MainActivity 类中获取数据?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用界面更新异步任务中的进度条

如何在没有 IdlingResource 的情况下在 Espresso 中等待异步任务

从 Activity 完成异步后在 Fragment 上填充 ListView

如何同步 2 个异步线程/任务

HTTP协议/AJAX异步请求-01

如何按预定义的秒数终止异步任务请求[重复]