【问题标题】:Using Thread/Handler/Looper for Worker Thread Android为 Worker Thread Android 使用 Thread/Handler/Looper
【发布时间】:2014-03-26 20:06:15
【问题描述】:

在实现 Thread/Handler/Looper 思想以通过传递消息在后台处理信息时存在一些响应性问题。我真的不想使用 AsyncTask 类,因为我已经知道如何使用它来完成我想要做的事情。

有人可以帮助我使用以下代码使用 GooglePlayServicesUtil 类下载 Apache 许可证并将其显示在 DialogFragment 内的 TextView 中吗?

我最大的问题是,当我启动它时,有时它会很快,但有时显示 DialogFragment 很慢。也许我没有遵循加载 DialogFragment 的最佳做法,我真的不知道。

更新 添加了现在可以工作的代码,但由于某种原因,我仍然偶尔会遇到 UI 冻结。 有谁知道这是否是特定于设备的?我目前正在使用三星 GS3。 . .

我的 DialogFragment:

public class ApacheLicenseDialog extends DialogFragment implements Handler.Callback{

// Message Constants
private static final int MSG_DO_WORK        = 0;
private static final int MSG_START          = 1;
private static final int MSG_DONE           = 2;
private static final int MSG_SHUTDOWN       = 3;

// UI Elements
private TextView m_textApacheLicense        = null;
private Button m_btnOk                      = null;
private ProgressBar m_apacheProgress        = null;

// Background Processing Objects
private BackgroundThread m_bgThread         = null;
protected Handler m_handler                 = null;

// Apache String Object
private String apacheLicense                = null;

// ----------------------------------------------------------------------------
// New Instance Method invokes DialogFragment constructor

public static ApacheLicenseDialog newInstance(int counter) 
{
    // Create the Apache License Dialog
    ApacheLicenseDialog dialog = new ApacheLicenseDialog();

    Bundle data = new Bundle();
    data.putInt("Counter", counter);
    Log.d("COUNTER", "New Instance called: "+ Integer.toString(counter)+" times.");

    // Set the Arguments for the Dialog
    dialog.setArguments(data);

    // Return the Dialog
    return dialog;
}

// ---------------------------------------------------------------------------
// Class Overrides

/* (non-Javadoc)
 * @see android.support.v4.app.DialogFragment#onCreate(android.os.Bundle)
 */
@Override public void onCreate(Bundle savedInstanceState) 
{
    // Perform the Default Behavior
    super.onCreate(savedInstanceState);
    setRetainInstance(true);

    // Create a new Handler, Background thread, and Start the Thread
    m_handler = new Handler(this);
    m_bgThread = new BackgroundThread();
    m_bgThread.start();
}

/*
 * (non-Javadoc)
 * 
 * @see
 * android.support.v4.app.Fragment#onCreateView(android.view.LayoutInflater,
 * android.view.ViewGroup, android.os.Bundle)
 */
@Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) 
{
    // Set the Layout from XML Resource
    return inflater.inflate(R.layout.apache_dialog_fragment, null);
}

/*
 * (non-Javadoc)
 * 
 * @see
 * android.support.v4.app.DialogFragment#onActivityCreated(android.os.Bundle
 * )
 */
@Override public void onActivityCreated(Bundle savedInstanceState) 
{
    // Perform Default Behavior
    super.onActivityCreated(savedInstanceState);

    // Reference this Dialog and Set its Title
    getDialog().setTitle(getActivity().getResources().getString(R.string.text_Apache_License_Title));


    // Reference the UI Elements
    m_textApacheLicense = (TextView)    getView().findViewById(R.id.textViewApacheLicense);
    m_apacheProgress    = (ProgressBar) getView().findViewById(R.id.apacheProgress);
    m_btnOk             = (Button)      getView().findViewById(R.id.btnOkay);

    // Add a Listener to the Button
    m_btnOk.setOnClickListener(OkListener);

    // Starts the Message Sending 
    init();

}   

/* (non-Javadoc)
 * @see android.support.v4.app.DialogFragment#onDismiss(android.content.DialogInterface)
 */
@Override public void onDismiss(DialogInterface dialog) 
{
    // Cleaned up this code, and Added some logging to test my message passing
            m_bgThread.m_workerHandler.obtainMessage(MSG_SHUTDOWN).sendToTarget();

    Log.d("DISMISSING", "Dismissed called on ApacheLicenseDialog");


    try {
        m_bgThread.join();
        Log.d("JOINING_THREAD", "Attempting to join the Thread");
    } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }finally{
        Log.d("JOINED_THREAD", "Thread successfully joined");
    }

    // Perform the default behavior
    super.onDismiss(dialog);
}

// ----------------------------------------------------------
// Handler.Callback Interface

@Override public boolean handleMessage(Message msg) 
{
    switch(msg.what)
    {
    case MSG_START:
        // Set the ProgressBar View to Visible
        m_apacheProgress.setVisibility(View.VISIBLE);
        break;
    case MSG_DONE:
        updateUI(msg);
        break;
    }
    // return true
    return true;
}

// ---------------------------------------------------------------------------
// Private Class Method

private void init()
{   
    // Send the Message to this Classes Handler
    m_bgThread.m_workerHandler.obtainMessage(MSG_DO_WORK).sendToTarget();

}

private void updateUI(Message msg) 
{
    // Set the ProgressBar View to Invisible
    m_apacheProgress.setVisibility(View.INVISIBLE);
    // Update the UI
    m_textApacheLicense.setText(msg.obj.toString());
}

private void obtainApacheLicense()
{   
    // Send message that the operation is Starting
    m_bgThread.m_workerHandler.obtainMessage(MSG_START).sendToTarget();

    // Fetch the ApacheLicense
    apacheLicense = GooglePlayServicesUtil.getOpenSourceSoftwareLicenseInfo(getActivity());

    // Send Message the the operation is Done
    m_handler.obtainMessage(MSG_DONE, apacheLicense).sendToTarget();
}

// ---------------------------------------------------------------------------
// Listeners

private OnClickListener OkListener = new OnClickListener()
{
    @Override public void onClick(View v) 
    {   
        // Dismiss the Dialog
        dismiss();

    }

};

// ---------------------------------------------------------------------------
// BackgroundThread Class used to Fetch the Apache License from GooglePlayServicesUtil Class

private class BackgroundThread extends Thread implements Handler.Callback{

    // Looper and Handler for the Background Thread
    private Looper      m_workerLooper;
    protected Handler   m_workerHandler;

    @Override public void run()
    {
        // Do background Processing
        Looper.prepare();
        m_workerLooper = Looper.myLooper();
        m_workerHandler = new Handler(m_workerLooper, BackgroundThread.this);
        Looper.loop();
    }

    @Override public boolean handleMessage(Message msg) 
    {
        switch(msg.what)
        {
        case MSG_DO_WORK:
            // Run the obtainApacheLicenseFunction in this Thread
            obtainApacheLicense();
            break;
        case MSG_SHUTDOWN:
            // Clean up the Looper by calling quit() on it
            m_workerLooper.quit();
            Log.d("BACKGROUND_THREAD","Looper is shut down");
            break;
        }
        // Return true
        return true;
    }

}
}

我通过使用 switch 语句来展示这一点:

// Runs the Apache Source Code in the Background
private void launchApacheDialogFragment(FragmentManager fm,FragmentTransaction ft) 
{
    counter++;

    // Check if the Dialog Already Exists
    m_dialogFragment = (ApacheLicenseDialog) fm.findFragmentByTag(APACHE_FRAGMENT);

    if(m_dialogFragment != null)
    {
        ft.remove(m_dialogFragment);
    }
    ft.addToBackStack(APACHE_FRAGMENT);

    m_dialogFragment = ApacheLicenseDialog.newInstance(counter);

    m_dialogFragment.show(fm, APACHE_FRAGMENT);

}

最后是我调用这个方法的case语句:

// Case 3 =  Show the Apache Open Source License information
        case 3:

            // Launch the DialogFragment
            launchApacheDialogFragment(fm, ft);

            // Break out of the Statement
            break;

任何帮助将不胜感激,这是一种令人讨厌的冻结延迟体验,尽管它只是为了阅读开源许可证。

再次,请帮助我使用 Thread/Handler/Looper 思想。我试图理解这个概念,而不是仅仅使用 AsyncTask。

更新

我发现这是使用 Debug 透视图工作的。我的线程启动并且我的处理程序处理所有消息,并且在我的对话片段的生命周期结束时,后台线程成功加入。我是否忘记了需要更多清理的东西?

谢谢

【问题讨论】:

  • 我认为我的问题在于我用来显示对话框的父活动。 . .如果已经调用了dismiss,我如何完全清理片段?还是我正在做我需要做的一切?

标签: java android multithreading


【解决方案1】:

我找到了一种使用广播接收器的更好方法,请参阅此处的帖子Programmatically Registering Child Class BroadcastReceiver onReceive(context, intent) not getting called in DialogFragment

【讨论】:

    猜你喜欢
    • 2017-02-13
    • 2012-11-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-08
    • 1970-01-01
    • 2014-01-23
    相关资源
    最近更新 更多