简体   繁体   English

旋转前进行网络通话时,如何更新UI线程?

[英]How to update UI thread when Network call is placed before rotating?

Okay this is driving me nuts. 好吧,这真让我发疯。 I have a worker thread, (Network call) that needs to run separate of the UI thread, (Its actually a ThreadPoolExecutor but I simplified it to prove my point). 我有一个工作线程(网络调用),它需要与UI线程分开运行(它实际上是ThreadPoolExecutor,但我简化了以证明我的观点)。 If you run this code in portrait, without rotation, the text updates. 如果以纵向方式(无旋转)运行此代码,则文本将更新。 I put in the delay there to allow for rotations to show my issue. 我在那儿放了一些时间,以便轮流展示我的问题。 If you start in portrait and before text updates rotation to landscape the text does not update. 如果从纵向开始并且在文本更新之前旋转以横向,则文本不会更新。 If you comment the code you can see the listener fire but the text never updates. 如果对代码进行注释,则可以看到侦听器启动,但是文本永远不会更新。

I am trying to simulate a custom network call running in a separate thread that may take some time to come back if the user rotates in between then the data gets lost. 我正在尝试模拟在一个单独的线程中运行的自定义网络调用,如果用户在两次调用之间进行轮换可能会花费一些时间,然后数据会丢失。 We are trying to prevent multiple network calls to save data usage on a phone. 我们正在尝试阻止多个网络通话以节省手机上的数据使用量。

package com.example.test;

import android.os.Bundle;
import android.os.Handler;
import android.app.Activity;
import android.content.res.Configuration;
import android.view.Menu;
import android.widget.TextView;
public class MainActivity extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    int orientation = getResources().getConfiguration().orientation; 
    if (Configuration.ORIENTATION_LANDSCAPE == orientation) { 
        //Do SomeThing; // Landscape
    } else { 
        startBackgroundWork();
        //Do SomeThing;  // Portrait
    } 

}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.main, menu);
    return true;
}

private Handler mHandler = new Handler();

public void startBackgroundWork() {
    new WorkingThread(new SomeListener() {
        public void onSomethingDone(final Object result) {

            mHandler.post(new Runnable() {
                public void run() { 
                    ((TextView)findViewById(R.id.text)).setText((String)result);
                    //showMyDialog(result); 
                }
            });

        }    
    }).start();
}

public interface SomeListener {
    public void onSomethingDone(Object result);
}

public class WorkingThread extends Thread {
    private SomeListener mListener;

    public WorkingThread(SomeListener listener) {
        mListener = listener;
    }

    public void run() {
        /* do some work */
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        mListener.onSomethingDone("New Text");
    }
}
}

It's because on rotation, the activity is re created, therefore all your code is binded to the old activity. 这是因为在旋转时会重新创建活动,因此所有代码都绑定到了旧活动。 You should make a reference to your working thread : 您应该引用您的工作线程:

private static WorkingThread mWorkingThread;
public void startBackgroundWork() {
    mWorkingThread = new WorkingThread(new SomeListener() {
        public void onSomethingDone(final Object result) {

            mHandler.post(new Runnable() {
                public void run() { 
                    ((TextView)findViewById(R.id.text)).setText((String)result);
                    //showMyDialog(result); 
                }
            });

        }    
    }).start();
}

then onCreate update it : 然后onCreate更新它:

public class WorkingThread extends Thread {
    private SomeListener mListener;

    public WorkingThread(SomeListener listener) {
        mListener = listener;
    }

    public void run() {
        /* do some work */
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        mListener.onSomethingDone("New Text");
    }

    public void updateListener(SomeListener listener) {
        mListener = listener;
    }
}


@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    startBackgroundWork();
}

public void startBackgroundWork() {
    if (mWorkingThread == null || mWorkingThread.isFinished()) { // Use a boolean to know if it still running


    mWorkingThread  = new WorkingThread(new SomeListener() {
        public void onSomethingDone(final Object result) {

            mHandler.post(new Runnable() {
                public void run() { 
                    ((TextView)findViewById(R.id.text)).setText((String)result);
                    //showMyDialog(result); 
                }
            });

        }    
    });
        mWorkingThread.start();

    } else { 
        mWorkingThread.updateListener(new SomeListener() {
        public void onSomethingDone(final Object result) {

            mHandler.post(new Runnable() {
                public void run() { 
                    ((TextView)findViewById(R.id.text)).setText((String)result);
                    //showMyDialog(result); 
                }
            });

        }    
    });
    } 
}

But there is some improvments you could make : 但是您可以做一些改进:

  • The WorkingThread class should be static to avoid direct reference to the old activity : Java: Static vs non static inner class WorkingThread类应该是静态的,以避免直接引用旧的活动: Java:静态与非静态内部类

  • Then make a reference to the current activity, and update it when it is recreated 然后引用当前活动,并在重新创建活动时对其进行更新

  • Make a method for update of the text, instead of having the code directly in the listener 创建一种更新文本的方法,而不是将代码直接放在侦听器中

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM