Android 如何每隔x分钟从api获取

Android 如何每隔x分钟从api获取,android,react-native-android,Android,React Native Android,我想在android上每隔x分钟运行一次fetch(使用React native) 我使用了文档中的示例,因为我还不确定如何进行这种获取 我甚至不知道我该如何开始(也许是做一个android原生处理器?)。我只找到了一个组件,但它是用于ios的您必须在获取回调的位置设置时间 ComponentWillMount() { AsyncStorage.getItem('accessToken').then((token) => { this.setState({

我想在android上每隔x分钟运行一次fetch(使用React native)

我使用了文档中的示例,因为我还不确定如何进行这种获取


我甚至不知道我该如何开始(也许是做一个android原生处理器?)。我只找到了一个组件,但它是用于ios的

您必须在获取回调的位置设置时间

ComponentWillMount() {
    AsyncStorage.getItem('accessToken').then((token) => {
      this.setState({
        isLoading: false,
         time :5000

      });
    });
  },
您可以创建一个AsyncTask(后台线程),从url获取json并在计时器循环中调用它,如下所示:

异步任务:

private class FetchAPI extends AsyncTask<String, String, String> {

    BufferedReader reader;
    HttpURLConnection conn;

    @Override
    protected String doInBackground(String... params) {

        String data = null;
        try {
            // Defined URL  where to send data
            URL url = new URL(YOURURL);
            conn = (HttpURLConnection) url.openConnection();
            conn.connect();

            // Get the server response
            reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
            // conn.disconnect();


        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return null;
    }

     protected void onPostExecute(String result) {
        try {
            StringBuilder sb = new StringBuilder();
            String line = null;

            while((line = reader.readLine()) != null)
            {
                sb.append(line + "\n");
            }

            String serverResponse = sb.toString(); //Your JSON

        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}
此代码将调用FetchAPI方法,该方法使用后台线程从URL获取json。当你得到了JSON,你可以用它做你想做的事情。该方法每5秒调用一次。根据需要编辑“5000”(间隔毫秒)


我希望这能帮助你和/或引导你朝正确的方向前进

如果你想在后台运行你的服务,那么你只有一个选择,那就是headless js或基于headless js的npm

 componentDidMount(){
  this.timer = setInterval(()=> this.getMovies(), 1000)
 }

async getMovies(){

 fetch('https://facebook.github.io/react-native/movies.json', {method: "GET"})
  .then((response) => response.json())
  .then((responseData) =>
  {
    //set your data here
     console.log(responseData);
  })
  .catch((error) => {
      console.error(error);
  });

}
无头基本服务的最小周期频率不得低于15

如果需要在5分钟内运行服务,那么您可以结合使用headless js和setinterval,如

   BackgroundTask.define(async () => { //headless based runs every 15 minute
        console.log('headless js service start')

         this._interval = setInterval(() => {
         console.log('setinterval for 5 minute start')
        // Your code
         }, 300000);

          BackgroundTask.finish()
     })
然后在您的任何组件方法(如componentwillmount)中,您需要安排后台任务,如

 componentDidMount() {
      BackgroundTask.schedule({
      period: 900, // Aim to run every 15mins 
      })
      }
您可以单独使用setinterval而不使用headless JS,但将被android停止以节省电池/资源


注意:要测试这些东西,你必须使用真实设备作为物理设备进入睡眠模式,或者像停止后台应用程序这样做,以节省电池/资源,这与模拟器不同

我参加聚会有点晚,但我必须做类似的事情。我向一台服务器发出了一个API请求,该服务器获取一系列位置,进行一些计算,并将数据传递给应用程序另一部分中的回调函数,以更新地图。我想让它每“x”秒运行一次。这就是我所做的:

我创建了一个自定义钩子,我从地图屏幕调用它。我想返回两个状态(businessLocations,error)。我在文件顶部创建了一个计时器,如下所示:

const [render, setRender] = useState(false);
 
useEffect(() => {
   setTimeout(() => {
      setRender(!render);
   }, 20000);
}, [isScreenFocused, render]);
const fetching = useRef(false);

useEffect(() => {

        const searchForLocations = async () => {

            fetching.current = true;

            await requestAllLocations()
                .then((locations) => {

                    const results = locations.map(loc => {
                        return createBusinessFromAPI(loc);
                    });

                    setBusinessLocations(results);
                    locationsCallback(results);

                    fetching.current = false;

                }).catch((error) => {
                    fetching.current = false;
                    throw error;
                });
        };

        if (!fetching.current) {
            searchForLocations().catch(error => setError(error));
        }

    }, [isScreenFocused, render]);
每次聚焦屏幕或更改渲染状态时,都会重新创建此选项。如您所见,我会在每次20秒结束时触发渲染状态更改,从而导致计时器重新启动

useffect
调用下面,我创建了第二个
useffect
调用,如下所示:

const [render, setRender] = useState(false);
 
useEffect(() => {
   setTimeout(() => {
      setRender(!render);
   }, 20000);
}, [isScreenFocused, render]);
const fetching = useRef(false);

useEffect(() => {

        const searchForLocations = async () => {

            fetching.current = true;

            await requestAllLocations()
                .then((locations) => {

                    const results = locations.map(loc => {
                        return createBusinessFromAPI(loc);
                    });

                    setBusinessLocations(results);
                    locationsCallback(results);

                    fetching.current = false;

                }).catch((error) => {
                    fetching.current = false;
                    throw error;
                });
        };

        if (!fetching.current) {
            searchForLocations().catch(error => setError(error));
        }

    }, [isScreenFocused, render]);
正如您在这里看到的,我使用hook
useRef
(在不同的渲染中不会改变)来确定最后一个请求是否仍在处理中。如果是,我不会在这个渲染周期中调用
searchForLocations()
,而只是等待下一个渲染周期。您还可以看到,整个
useffect
调用是在计时器启动时触发的,因为我在这里也将渲染状态用作依赖项

这可能不是一个完美的解决方案。我目前正在尝试对它进行一点改进。但是,到目前为止,它对我很有效

以下是整个文件:

import React, {useEffect, useRef, useState} from 'react';
import {requestAllLocations} from '../api/requests';
import {createBusinessFromAPI} from '../model/BusinessCreator';

export default (isScreenFocused, locationsCallback) => {

    const [businessLocations, setBusinessLocations] = useState([]);
    const [error, setError] = useState(null);
    const [render, setRender] = useState(false);

    const fetching = useRef(false);

    useEffect(() => {
        setTimeout(() => {
            setRender(!render);
        }, 20000);
    }, [isScreenFocused, render]);

    useEffect(() => {

        const searchForLocations = async () => {

            fetching.current = true;

            await requestAllLocations()
                .then((locations) => {

                    const results = locations.map(loc => {
                        return createBusinessFromAPI(loc);
                    });

                    setBusinessLocations(results);
                    locationsCallback(results);

                    fetching.current = false;

                }).catch((error) => {
                    fetching.current = false;
                    throw error;
                });
        };

        if (!fetching.current) {
            searchForLocations().catch(error => setError(error));
        }

    }, [isScreenFocused, render]);

    return [businessLocations, error];
};

好的,这是有道理的。但是我如何在后台运行计时器呢?我有类似的东西。或者我必须使用android本机方法我想你必须一次从api加载数据,然后根据你的业务需要显示。为什么我要问这个问题,是因为我需要每X分钟检查一次更改。所以,假设在这些时间间隔内,一个值大于另一个值。一条消息将出现在用户屏幕上。我想现在我将知道如何应对本机调用本机函数,并尝试使其工作。感谢您的代码应用程序在20-30秒后崩溃。我为一个因此问题而受阻的朋友问了这个问题,他在一小时前设法解决了。非常感谢您的回复。这不是解决方案。它将一直等到第一次抓取完成。我想我有办法确保最后一次抓取已经完成。见下面我的答案。希望它能帮助我成功地使用这种方法。唯一需要注意的是,在第一个
useffect
中调用
setRender
之前,需要检查组件是否已装入。我遇到了无法获得操作的问题,因为超时功能将被安排在我的组件卸载后运行。我使用中概述的方法修复了它