将没有UI的片段添加到来自其他片段的活动

时间:2015-12-10 14:13:47

标签: android android-fragments android-optionsmenu fragmentmanager

我正在尝试从添加到Fragment的{​​{1}}向MainActivity添加一名工作人员FragmentFragment为其中包含的DownloadListener实现WebView,在调用Fragment时添加工作人员onDownloadStart()

@Override
public void onDownloadStart(String url, String userAgent, String contentDisposition,
            String mimeType, long contentLength) {
    getActivity().getSupportFragmentManager().beginTransaction()
        .add(new DownloadFragment().newInstance(url, contentDisposition, mimeType), null)
        .commit();
}

但是当我添加新的Fragment时,它似乎陷入无限循环,调用onCreateonCreateViewonCreateOptionsMenuonDownloadStart当前的Fragment。大约二十次拨打onCreateOptionsMenu()之后重复这些警告:

12-10 08:33:36.717 25582-25582/com.example.package W/cr.BindingManager: Cannot call determinedVisibility() - never saw a connection for the pid: 25582
12-10 08:33:36.732 25582-25582/com.example.package W/art: Attempt to remove non-JNI local reference, dumping thread
12-10 08:33:36.734 25582-25582/com.example.package W/AwContents: onDetachedFromWindow called when already detached. Ignoring

直到内存耗尽后才终止:

12-10 08:33:37.123 25582-25582/com.example.package I/chromium: [INFO:GrGLUtil.cpp(169)] NULL GL version string.
12-10 08:33:37.346 25582-25582/com.example.package W/cr.BindingManager: Cannot call determinedVisibility() - never saw a connection for the pid: 25582
12-10 08:33:37.440 25582-26194/com.example.package E/chromium: [ERROR:gl_in_process_context.cc(208)] Failed to initialize GLES2CmdHelper
12-10 08:33:37.464 25582-25582/com.example.package W/libc: pthread_create failed: could not allocate 1044480-bytes mapped space: Out of memory
12-10 08:33:37.464 25582-25582/com.example.package E/chromium: [ERROR:platform_thread_posix.cc(112)] pthread_create: Try again
12-10 08:33:37.722 25582-25582/com.example.package W/google-breakpad: ### ### ### ### ### ### ### ### ### ### ### ### ###
12-10 08:33:37.722 25582-25582/com.example.package W/google-breakpad: Chrome build fingerprint:
12-10 08:33:37.722 25582-25582/com.example.package W/google-breakpad: 1.9.1
12-10 08:33:37.722 25582-25582/com.example.package W/google-breakpad: 69
12-10 08:33:37.722 25582-25582/com.example.package W/google-breakpad: 45012863-7d3b-4c30-8ccf-e65394c57d85
12-10 08:33:37.722 25582-25582/com.example.package W/google-breakpad: ### ### ### ### ### ### ### ### ### ### ### ### ###
12-10 08:33:37.722 25582-25582/com.example.package A/libc: Fatal signal 11 (SIGSEGV), code 1, fault addr 0x0 in tid 25582 (example.package)

这是我DownloadFragment的当前代码:

public class DownloadFragment extends Fragment {

    private static final int REQUEST_CODE_STORAGE = 0;

    private static final String KEY_LINK = "link_key";
    private static final String KEY_DISPOSITION = "disposition_key";
    private static final String KEY_MIME_TYPE = "mime_type_key";

    private String mLink;
    private String mDisposition;
    private String mMimeType;

    public WebFragment newInstance(String link, String contentDisposition, String mimeType) {
        WebFragment fragment = new WebFragment();

        Bundle args = new Bundle();
        args.putString(KEY_LINK, link);
        args.putString(KEY_DISPOSITION, contentDisposition);
        args.putString(KEY_MIME_TYPE, mimeType);
        fragment.setArguments(args);

        return fragment;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setRetainInstance(true);

        mLink = getArguments().getString(KEY_LINK);
        mDisposition = getArguments().getString(KEY_DISPOSITION);
        mMimeType = getArguments().getString(KEY_MIME_TYPE);

        if(ContextCompat.checkSelfPermission(getContext(),
                Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
            if(shouldShowRequestPermissionRationale(Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
                // TODO: add request permission rationale dialog
                Timber.d("Should show request permission rationale");
            } requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_CODE_STORAGE);
        } else {
            downloadFile(mLink, mDisposition, mMimeType);
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[], @NonNull int[] grantResults) {
        switch (requestCode) {
            case REQUEST_CODE_STORAGE:
                if(grantResults[REQUEST_CODE_STORAGE] == PackageManager.PERMISSION_GRANTED) {
                    downloadFile(mLink, mDisposition, mMimeType);
                } else {
                    startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(mLink)));
                } break;
        }
    }

    public void downloadFile(String url, String contentDisposition, String mimeType) {
        String fileName = URLUtil.guessFileName(url, contentDisposition, mimeType);

        DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url));
        request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
        request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, fileName);
        request.allowScanningByMediaScanner();

        DownloadManager manager = (DownloadManager) getContext().getSystemService(Context.DOWNLOAD_SERVICE);
        manager.enqueue(request);

        getActivity().getSupportFragmentManager().beginTransaction().remove(this).commit();
    }
}

我还尝试添加onCreateView方法,将onCreate中的所有代码移到那里(setRetainInstance除外),但这会产生相同的结果。我无法弄清楚为什么会重复之前的Fragment,我错过了什么?

1 个答案:

答案 0 :(得分:1)

我建议您使用以下内容 - 不要直接从其他片段进行片段交易。这是一种不好的做法,限制了代码的灵活性和可维护性。此外,它将你的碎片相互耦合,这是你应该避免的。

使用侦听器接口通知托管活动它需要创建无头片段,如下所示:

public class WebViewFragment {

    private WebViewFragmentListener mListener;

    public void onAttach(Context context) {
        if (context instanceof WebViewFragmentListener) {
            mListener = (WebViewFragmentListener) context;
        } else {
            throw new IllegalStateException("Hosting activity doesn't implement the fragment listener interface");
        }        
    }

    // rest of fragment logic skipped

    @Override
    public void onDownloadStart(String url, String userAgent, String contentDisposition, String mimeType, long contentLength) {
        mListener.onDownloadStart(url, contentDisposition, mimeType);
    }

    public interface WebViewFragmentListener {
        void onDownloadStart(String url, String contentDisposition, String mimeType);
    }
}

然后,在您的活动中,您实现WebViewFragmentListener接口并处理工作片段的创建,并将其添加到onDownloadStart()方法中的活动中。

public class MainActivity extends AppCompatActivity implements WebViewFragmentListener {

    // rest of the activity logic...   

    @Override
    public void onDownloadStart(String url, String contentDisposition, String mimeType) {
        final DownloadFragment downloadFragment = DownloadFragment.newInstance(url, contentDisposition, mimeType);
        final FragmentManager fm = getSupportFragmentManager();
        fm.beginTransaction().add(downloadFragment, DownloadFragment.TAG).commit();
    }
}

下载完成后,您可以使用相同的方法通知活动,因此可以删除下载片段。

这种分离将使您的代码更有条理,更易于调试。