退出活动时调用AsyncTask(或者可能是另一种解决方案?)

时间:2018-04-14 06:27:30

标签: android android-asynctask google-drive-android-api

我正在编写一个应用程序,用户在名为TranslateActivity的活动中写入单词。我想将这些文字存储在与用户相关的谷歌硬盘上。

我使用AsyncTask实现了代码,该代码能够创建文件并将数据附加到驱动器等等。但是,每次用户写一个单词时我都不想将数据推送到驱动器,因为它需要一些时间。相反,我想做以下事情:

当用户按下back时,上传应在后台开始。但是,它对我不起作用。我假设android关闭了上下文等等,并且会破坏AsyncCall

当用户退出活动时我想要进行上传的原因是因为我知道不会有更多的输入。

代码看起来像

@Override
public void onBackPressed(){
    googleDriveWrite.execute(mAdapter.getWords());
    while(!mIsFinished){
    }
}
完成后,

GoogleDriveWrite会返回boolean。我不喜欢上面的尝试,但我想你明白我的尝试。

我正在寻找一种能够暂停"暂停"用户界面直到上传完成,例如显示进度条,或者在活动发生变化时继续工作的内容。

一种可能的解决方案是添加save - 按钮,但我希​​望它能在没有用户输入的情况下顺利运行。

我刚发现:https://www.androiddesignpatterns.com/2013/04/retaining-objects-across-config-changes.html可以使用

@Override
public void onAttach(Activity activity) {
    super.onAttach(activity);
    mCallbacks = (TaskCallbacks) activity;
}

在旋转等情况下附加片段的新活动。也许可以做一些类似于GoogleDriveWrite延伸AsyncTask的事情?虽然AsyncTask似乎不包含onAttach(Activity activity)

Context需要ActivityGoogleDriveWrite来调用Drive.getDriveResourceClient(Context, GoogleSignInAccount),问题可能出在哪里?

以下是GoogleDriveWrite.java

import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Context;
import android.os.AsyncTask;
import android.os.ParcelFileDescriptor;
import android.support.annotation.NonNull;
import android.util.Log;
import android.widget.Toast;

import com.google.android.gms.auth.api.signin.GoogleSignInAccount;
import com.google.android.gms.drive.Drive;
import com.google.android.gms.drive.DriveClient;
import com.google.android.gms.drive.DriveContents;
import com.google.android.gms.drive.DriveFile;
import com.google.android.gms.drive.DriveFolder;
import com.google.android.gms.drive.DriveResourceClient;
import com.google.android.gms.drive.Metadata;
import com.google.android.gms.drive.MetadataBuffer;
import com.google.android.gms.drive.MetadataChangeSet;
import com.google.android.gms.drive.query.Filters;
import com.google.android.gms.drive.query.Query;
import com.google.android.gms.drive.query.SearchableField;
import com.google.android.gms.tasks.OnFailureListener;
import com.google.android.gms.tasks.OnSuccessListener;
import com.google.android.gms.tasks.Task;
import com.google.android.gms.tasks.Tasks;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

public class GoogleDriveWrite extends AsyncTask<ArrayList<Words>,Void, Boolean> {
    private final String TAG = getClass().getSimpleName();
    final public static String PARENTNAME = "TAILOREDDICTIONARY";
    public final static int MAXTIME = 15000;
    private DriveResourceClient mDriveResourceClient;
    private DriveClient mDriveClient;
    private Context mContext;
    private BaseActivity mActivity;
    private ProgressDialog progressDialog;

    private GoogleSignInAccount mAccount;
    protected final static int NBROFITEMS = 6;
    protected final static String TEXTNAMES[] = {"w1.txt", "w2.txt", "score.txt", "ctr.txt", "time.txt", "isHidden.txt"};
    private GoogleDriveHelper mDriveHelper;
    String mKeyName;
    private void setUp() {
        mDriveClient = Drive.getDriveClient(mContext, mAccount);
        mDriveResourceClient = Drive.getDriveResourceClient(mContext, mAccount);
    }
    public GoogleDriveWrite(String keyName, GoogleSignInAccount account, Context context, BaseActivity activity){
        mKeyName = keyName;
        mAccount = account;
        mContext = context;
        mActivity = activity;
        mDriveHelper = new GoogleDriveHelper();
        setUp();
    }

    protected void onPreExecute() {
        System.out.println("In pre execute");
        progressDialog = ProgressDialog.show(mActivity,"ProgressDialog","Wait for saving files");
    }

    protected void onPostExecute(Boolean result){
        System.out.println("In on PosteExecute");
        mActivity.setFinishedTask(result);
        progressDialog.dismiss();
    }
    @Override
    protected Boolean doInBackground(ArrayList<Words>... words) {
        DriveFolder rootFolder = mDriveHelper.getRootFolder(mDriveResourceClient);
        if (rootFolder == null){
            throw new IllegalStateException("rootFolder is null");
        } else {
            System.out.println("root is not null!");
        }
        // Search for parentName
        MetadataBuffer metadata = mDriveHelper.searchFolders(PARENTNAME, rootFolder, mDriveResourceClient);
        if (metadata == null){
            throw new IllegalStateException("metadata is null");
        }

        DriveFolder parentFolder = getFolderFromMeta(metadata, rootFolder, PARENTNAME);
        // Release metadatabuffer
        metadata.release();
        // Check parentFolder is not null
        if (parentFolder == null){
            throw new IllegalStateException("Parentfolder is null");
        } else {
            System.out.println("parentFolder is not null");
        }

        // Search for keyFolder
        metadata = mDriveHelper.searchFolders(mKeyName, parentFolder, mDriveResourceClient);
        DriveFolder keyFolder = getFolderFromMeta(metadata, parentFolder, mKeyName);
        if (keyFolder == null){
            throw new IllegalStateException("Keyfolder is null");
        } else {
            System.out.println(mKeyName);
            System.out.println("keyFolder is not null");
        }
        metadata.release();
        // Write new data to keyFolder
        writeFilesToData(keyFolder, words[0]);
//        progressDialog.dismiss();
        return true;
    }
    private ArrayList<ArrayList<String>> splitData(ArrayList<Words> words) {
        ArrayList<ArrayList<String>> data = new ArrayList<>();
        ArrayList<String> tmp[] = new ArrayList[NBROFITEMS];
        for (int i = 0; i < NBROFITEMS; ++i) {
            tmp[i] = new ArrayList<>();
        }

        for (int i = 0; i < words.size(); i++) {
            tmp[0].add(words.get(i).w1);
            tmp[1].add(words.get(i).w2);
            tmp[2].add(Double.toString(words.get(i).score));
            tmp[3].add(Double.toString(words.get(i).ctr));
            tmp[4].add(Double.toString(words.get(i).time));
            tmp[5].add(Boolean.toString(words.get(i).isHidden));
        }

        for (int i = 0; i < NBROFITEMS; i++) {
            data.add(tmp[i]);
        }
        return data;
    }
    private void writeFilesToData(DriveFolder folder, ArrayList<Words> words){
        System.out.println("Size words: " + words.size());
        ArrayList<ArrayList<String>> data = splitData(words);
        MetadataBuffer metadata = mDriveHelper.searchTextFiles(folder, mDriveResourceClient);
        ArrayList<DriveFile> driveFiles = mDriveHelper.getDriveFiles(metadata);
        // If files do not exist we must create them
        if (driveFiles.isEmpty()){
            driveFiles = mDriveHelper.createDriveFiles(folder, mDriveResourceClient);
            for (int i = 0; i < NBROFITEMS; i++){
                appendData(driveFiles.get(i), data.get(i));
            }

        } else {
            for (Metadata m : metadata) {
                if (m.getTitle().equals(TEXTNAMES[0])) {
                    appendData(driveFiles.get(0), data.get(0));
                }
                if (m.getTitle().equals(TEXTNAMES[1])) {
                    appendData(driveFiles.get(1), data.get(1));
                }
                if (m.getTitle().equals(TEXTNAMES[2])) {
                    appendData(driveFiles.get(2), data.get(2));
                }
                if (m.getTitle().equals(TEXTNAMES[3])) {
                    appendData(driveFiles.get(3), data.get(3));
                }
                if (m.getTitle().equals(TEXTNAMES[4])) {
                    appendData(driveFiles.get(4), data.get(4));
                }
                if (m.getTitle().equals(TEXTNAMES[5])) {
                    appendData(driveFiles.get(5), data.get(5));
                }
            }
        }
        metadata.release();
    }

    private void appendData(DriveFile driveFiles, ArrayList<String> data){
        DriveContents content = mDriveHelper.getTaskResult(mDriveResourceClient.openFile(driveFiles, DriveFile.MODE_READ_WRITE));
        if (content == null){
            throw new IllegalStateException("Content is null");
        }
        ParcelFileDescriptor pfd = content.getParcelFileDescriptor();
        long bytesToSkip = pfd.getStatSize();
        try (InputStream in = new FileInputStream(pfd.getFileDescriptor())) {
            // Skip to end of file
            while (bytesToSkip > 0) {
                long skipped = in.skip(bytesToSkip);
                bytesToSkip -= skipped;
            }
        } catch (IOException e){
            e.printStackTrace();
        }
        try (OutputStream out = new FileOutputStream(pfd.getFileDescriptor())) {
            appendToFile(out, data);
        } catch (IOException e){
            e.printStackTrace();
        }
        // [START commit_contents_with_metadata]
        MetadataChangeSet changeSet = new MetadataChangeSet.Builder()
                .setStarred(true)
                .setLastViewedByMeDate(new Date())
                .build();
       Task<Void> commitTask = mDriveResourceClient.commitContents(content, changeSet);
       commitTask.addOnSuccessListener(new OnSuccessListener<Void>() {
           @Override
           public void onSuccess(Void aVoid) {
               System.out.println("Files commits");
           }
       }).addOnFailureListener(new OnFailureListener() {
           @Override
           public void onFailure(@NonNull Exception e) {
               System.out.println("Failed to commit");
           }
       });
    }
    private void appendToFile(OutputStream out, ArrayList<String> data){
        try {
            for (int i = 0; i < data.size(); i++) {
                out.write((data.get(i) + "\n").getBytes());
            }
        } catch (Exception e){
            e.printStackTrace();
        }
    }

    private void createFile(ArrayList<String> data, String fileName, DriveFolder folder){

    }



    /**
     * Search metadata for folder. If found return existing fodler. If not found create new folder in rootFolder
     * @param metadata Buffer with found folders
     * @param rootFolder Folder to create new folder in
     * @return drivefolder with name folderName
     */
    private DriveFolder getFolderFromMeta(MetadataBuffer metadata, DriveFolder rootFolder, String folderName){
        // ArrayList is empty we must create ParentFolder
        ArrayList<String> titles = mDriveHelper.getTitles(metadata);
        DriveFolder folder = null;
        if (titles.isEmpty()){
            folder = createFolder(rootFolder,folderName);
        } else {
            folder = metadata.get(0).getDriveId().asDriveFolder();
        }
        return folder;
    }

    private DriveFolder createFolder(DriveFolder folder, String fileName){
        MetadataChangeSet changeSet = new MetadataChangeSet.Builder()
                .setTitle(fileName)
                .setMimeType(DriveFolder.MIME_TYPE)
                .build();
        Task<DriveFolder> newFolder = mDriveResourceClient.createFolder(folder, changeSet);
        DriveFolder driveFolder = mDriveHelper.getTaskResult(newFolder);
        return driveFolder;
    }

    private void showMessage(String txt) {
        Toast.makeText(mContext, txt, Toast.LENGTH_SHORT).show();
    }
}

2 个答案:

答案 0 :(得分:1)

在这种情况下,您可以做的最好的事情是使用JobScheduler Api安排工作。您可以创建需要网络连接的新作业来执行您的工作。系统将根据您设置的条件尽可能执行作业。 Docs

答案 1 :(得分:0)

您可以通过启动服务来完成任务。但是从Android O开始,允许服务在后台运行的持续时间有限制。

由于您的任务可能需要更长时间,因此您可以创建Foreground服务并执行任务。这种方法更可靠。

如果在尝试上传数据时无法使用互联网连接,则可以使用JobScheduler安排作业。您可以关注this link以获取有关它的更多信息。