最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

android - How to automatically upload data to a shared sheet when Internet becomes available? - Stack Overflow

programmeradmin3浏览0评论

Context I am making an app that takes basic user inputs and puts them in a spreadsheet (using Apache POI and excel right now, but google sheets would work, too).

Right now, the program writes the data to an excel file in the documents section of my phone, and to access it on my computer I have to email it to myself. I can't input the data directly to an online google sheet, because I use the app in areas where I don't have internet connection.

Actual question My app currently stores data locally. Can I code the app to automatically upload this data to a shared sheet when internet becomes available?

Current code My current code simply creates a local XSSF Workbook (or accesses an existing one if it exists) and inputs the data into it. This is a bit of a simplified version (the real version creates separate sheets to group different types of data, adds titles and headers, etc.) but the basic mechanics are the same.


int rowCount = sheet.getLastRowNum();

Workbook workbook;
Sheet sheet;

// make workbook or get existing one
if (filePath.exists()) {
    FileInputStream fis = new FileInputStream(filePath);
    workbook = new XSSFWorkbook(fis);
    fis.close();
} else {
    workbook = new XSSFWorkbook();
}

//enter data into spreadsheet from rowList
sheet = workbook.getSheet(0)
for (int i = 0; i < rowList.size(); i += 3) {
    Row row = sheet.createRow(++rowCount);
    for (int j = 0; j < 3; j++) {
        Cell cell = row.createCell(j);
        cell.setCellValue(rowList.get(i + j));
    }
}

FileOutputStream fos = new FileOutputStream(filePath);
workbook.write(fos);
fos.close();
workbook.close();

Context I am making an app that takes basic user inputs and puts them in a spreadsheet (using Apache POI and excel right now, but google sheets would work, too).

Right now, the program writes the data to an excel file in the documents section of my phone, and to access it on my computer I have to email it to myself. I can't input the data directly to an online google sheet, because I use the app in areas where I don't have internet connection.

Actual question My app currently stores data locally. Can I code the app to automatically upload this data to a shared sheet when internet becomes available?

Current code My current code simply creates a local XSSF Workbook (or accesses an existing one if it exists) and inputs the data into it. This is a bit of a simplified version (the real version creates separate sheets to group different types of data, adds titles and headers, etc.) but the basic mechanics are the same.


int rowCount = sheet.getLastRowNum();

Workbook workbook;
Sheet sheet;

// make workbook or get existing one
if (filePath.exists()) {
    FileInputStream fis = new FileInputStream(filePath);
    workbook = new XSSFWorkbook(fis);
    fis.close();
} else {
    workbook = new XSSFWorkbook();
}

//enter data into spreadsheet from rowList
sheet = workbook.getSheet(0)
for (int i = 0; i < rowList.size(); i += 3) {
    Row row = sheet.createRow(++rowCount);
    for (int j = 0; j < 3; j++) {
        Cell cell = row.createCell(j);
        cell.setCellValue(rowList.get(i + j));
    }
}

FileOutputStream fos = new FileOutputStream(filePath);
workbook.write(fos);
fos.close();
workbook.close();
Share Improve this question asked Mar 16 at 19:24 user29775581user29775581 33 bronze badges
Add a comment  | 

1 Answer 1

Reset to default 0

Doing something when network becomes available

Initial ideas that you shouldn't do / not necessary

Firstly, you could try to upload the data immediately (right there along or instead of your spreadsheet code, in the foreground), if Internet is available. I.e.

  • detect whether Internet is available (here's a modern Kotlin version)

  • if so, upload the data to the online spreadsheet

Otherwise, you could instruct Android, to upload the data whenever Internet becomes available. You could implement that by waiting for Internet with a Broadcast receiver as presented by the accepted answer in this SO post. That's unreliable though (close the app and the upload job is gone) and you need a lot of code just for getting to know when Internet is available.

The recommended approach is WorkManager, which allows you to define background work

  • that is guaranteed to be executed (even after closing the app or turning off the phone)

  • can be bound to conditions (like Internet being available, then the work waits for it)

  • is system-optimized (battery-efficient)

  • is reliable across all API versions

Doing such work in the background rather than the foreground is absolutely best practice, because you don't slow down the main thread and potentially cause the application's UI to lag.

AndroidManifest.xml:

<uses-permission android:name="android.permission.INTERNET" />

build.gradle.kts (app):

dependencies {
    val work_version = "2.10.0"
    // Kotlin + coroutines
    implementation("androidx.work:work-runtime-ktx:$work_version")
}

Note: Android Studio suggests to migrate that to the new Version Catalog format (Alt+Enter). That is cleaner. I just show the full definition in one file here, for shortness.

UploadWorker.kt:

class UploadWorker(
    context: Context,
    workerParams: WorkerParameters
): CoroutineWorker(context, workerParams) {

   override suspend fun doWork(): Result {
      try {
         // upload data to shared sheet here
         return Result.success()
      } catch (e: Exception) {
         return Result.retry()
      }
   }

}

MainActivity.kt or somewhere else (define work request):

val context = LocalContext.current

val constraints = Constraints.Builder()
   .setRequiredNetworkType(NetworkType.CONNECTED)
   .build()

val work: WorkRequest =
   OneTimeWorkRequestBuilder<UploadWorker>()
       .setConstraints(constraints)
       .build()

WorkManager.getInstance(context).enqueue(work)

If you want to dive deeper into WorkManager, I recommend Philipp Lackner's YouTube tutorial and this History of WorkManager article.

Uploading to an online spreadsheet

The easiest way to implement the data upload would be

  • pass your basic user input as input data to each work you enqueue

  • in the worker upload the data by making an API request to the Google Sheets API for example - place this code where I've put // upload data to shared sheet here

    • the API request can be done with Retrofit (e.g. see this tutorial)

    • the API details will be on the provider's website, e.g. Google Sheets API

Due to the lack of a specified provider, I can't provide you the exact code, but generally:

build.gradle.kts (app):

dependencies {
    val retrofit_version = "2.9.0"
    val gson_version = "2.9.0"
    // Retrofit
    implementation('com.squareup.retrofit2:retrofit:$retrofit_version')
    // Gson converter for JSON
    implementation('com.squareup.retrofit2:converter-gson:$gson_version')
}

ApiService.kt:

Depends on the API you talk to, but for example:

interface ApiService {
    @Headers("x-api-key: ...")
    @PUT("spreadsheets/1/...")
    suspend fun upload(@Body request: UploadRequest): retrofit2.Response<Unit>
}

UploadRequest.kt:

data class UploadRequest(
    val myInput: String,
    val myInput2: Double
)

in UploadWorker.kt where I've put the comment to insert code:

// Build Retrofit instance
val retrofit = Retrofit.Builder()
    .baseUrl("https://.../v4/")
    .addConverterFactory(GsonConverterFactory.create())
    .build()

val api = retrofit.create(ApiService::class.java)

val request = UploadRequest(
    myInput1 = ...,
    myInput2 = ...
)

val response = api.upload(request)
if (response.isSuccessful) {
    return Result.success()
} else {
    return Result.retry()
}

With this you're putting your data in the UploadRequest and the GsonConverterFactory will convert it to a JSON object before sending the API request.

Code examples for reference

Example projects I can offer you for reference:

  • a hobby project of mine: Tracker (Android app)

    • relevant: the app architecture diagram (just look how worker interacts with API), HomeScreen.kt (where work is scheduled), LocationWorker.kt and the api folder with TrackerApiService.kt and LocationUploadRequest.kt
  • a minimalist demo for Worker and Retrofit I've built:

    • relevant: MainActivity.kt, DemoWorker.kt, DemoApiService.kt (that's all)

    • don't mind the name of this demo project, I've just had a bug with my emulator where it often lacked Internet connection in the background - I've found that the issue was with the emulator. The code in the demo works perfectly well on real devices.

Rather use the code snippets above than copy and pasting my projects' code. They're better used e.g. for checking if you got the imports right or how to extract code to functions or composables.

发布评论

评论列表(0)

  1. 暂无评论