简体   繁体   English

使用Thread / Handler / Looper for Worker Thread Android

[英]Using Thread/Handler/Looper for Worker Thread Android

Having some responsiveness issues when implementing the Thread/Handler/Looper ideology to process information in the background by passing messages. 实施Thread / Handler / Looper意识形态以通过传递消息在后台处理信息时,存在一些响应性问题。 I really don't want to use the AsyncTask class, since i already know how to use that to accomplish what I am trying to do. 我真的不想使用AsyncTask类,因为我已经知道如何使用它来完成我想做的事情。

Can someone help me with the following code that downloads the Apache License using the GooglePlayServicesUtil class and displays it in a TextView inside a DialogFragment ? 有人可以帮我使用以下代码,这些代码使用GooglePlayServicesUtil类下载Apache许可证,并在DialogFragment内的TextView中显示它吗?

My biggest issue is that when i launch it, sometimes it is fast but others it is very slow to show the DialogFragment. 我最大的问题是,当我启动它时,有时显示DialogFragment的速度很快,但另一些则非常慢。 Maybe I am not following the best practice for loading the DialogFragment, i don't really know. 我真的不知道,也许我没有遵循最佳实践来加载DialogFragment。

Update Added code that is now working, but for some reason I still get a UI Freeze once in a while. 更新添加的代码现在可以正常工作,但是由于某种原因,我仍然会偶尔获得UI Freeze。 Does anyone know if this is device specific? 有人知道这是否特定于设备吗? I am currently on a Samsung GS3. 我目前正在使用三星GS3。 . .

My DialogFragment: 我的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;
    }

}
}

And i show this by using a switch statement as such: 我通过使用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);

}

And finally my case statement which calls this method: 最后是我的case语句,它调用此方法:

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

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

            // Break out of the Statement
            break;

Any help would be appreciated, this is kind of an annoying freeze delaying the experience, although its just to read the open source license. 任何帮助将不胜感激,尽管这只是阅读开放源代码许可证,但这是一种令人讨厌的冻结体验的延迟。

Again, please help me using the Thread/Handler/Looper ideology. 再次,请使用Thread / Handler / Looper意识形态帮助我。 I am trying to understand this concept as opposed to just using AsyncTask. 我试图理解这个概念,而不是仅仅使用AsyncTask。

Update 更新资料

I have found this to be working using Debug perspective. 我发现这可以使用Debug透视图进行工作。 My thread starts up and my handler processes all the messages and at the end of the lifecycle of my dialog fragment the background thread successfully joins. 我的线程启动,我的处理程序处理所有消息,并且在对话框片段的生命周期结束时,后台线程成功加入。 Am i forgetting something that needs to be cleaned up more? 我是否忘记了需要进一步清理的东西?

Thanks 谢谢

我找到了一种使用BroadcastReceiver做到这一点的更好方法,请参见此处的文章,以编程方式注册子类BroadcastReceiver onReceive(context,intent)不会在DialogFragment中被调用

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 在Android中的单独线程上使用弯针 - Using a looper on a separate thread in Android 使用循环程序使用自己的线程的Android Java对象 - Android Java object with own thread using looper 如何在不使用循环程序和处理程序的情况下安排特定线程中的任务? - How to schedule tasks in a specific thread without using a looper and a handler? Android:在工作线程中创建View和Handler是否安全? - Android : is it safe to create a View and a Handler in a worker thread Looper,工作线程和其他并发问题 - Looper, worker thread and other concurrency issues Android主线程循环器的关注 - Android Main Thread Looper concern Android Looper线程崩溃并出现NullPointerException - Android Looper thread crashes with NullPointerException Android线程错误-无法在未调用Looper.prepare()的线程内创建处理程序 - Android thread error - Can't create handler inside thread that has not called Looper.prepare() 无法在未调用Looper.prepare()Android的线程内创建处理程序 - Can't create handler inside thread that has not called Looper.prepare() Android java.lang.RuntimeException:无法在未在Android中调用Looper.prepare()的线程内创建处理程序 - java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare() in Android
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM