这不是上面发布的问题的重复。当HAndlerThread启动一个新线程并且我收到NetworkOnMainThread异常时,我认为这是一个奇怪的错误。解决正常的网络主线程异常是一个全新的问题。请取消标记。
嗨,首先,我正在练习HandlerThread的。我已经使用 Fragment 启动了一个处理程序线程并向线程发送消息。在处理程序线程的句柄消息中,我使用网络调用来下载图像。然后,我使用 MainThread 的处理程序将下载的图像发布到 UI 线程。但是在运行此应用程序时,我得到一个 NetworkOnMainThread 异常。下面是片段和处理程序线程的代码。
片段:
public class LoaderFragment extends Fragment {
Button loaderButton;
LoaderThread loadThread;
Handler loaderThreadHandler;
Handler mainHandler;
String[] queArray;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mainHandler = new Handler(Looper.getMainLooper());
loadThread = new LoaderThread("LoaderThread",mainHandler);
queArray = new String[]{"http://www.paynekillers.com/downloads/screens/17_screen05.jpg",
"http://www.hdwallpapers.in/walls/jacob_frye_assassins_creed_syndicate-wide.jpg",
"http://www.percivalconstantine.com/wp-content/uploads/2015/03/Tomb-Raider-Lara-Croft-Summit-2013.jpg",
"http://orig00.deviantart.net/f904/f/2014/155/e/a/batman_arkham_knight_hd_wallpaper_1_by_rajivcr7-d7l19pt.jpg",
"http://static5.gamespot.com/uploads/original/536/5360430/2753139-15774024117_9026e0a43c_o.jpg"};
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View loaderView = inflater.inflate(R.layout.loader_layout, container, false);
this.loaderButton = (Button) loaderView.findViewById(R.id.proc_button);
return loaderView;
}
@Override
public void onResume() {
super.onResume();
loaderButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
loadThread.start();
loaderThreadHandler = loadThread.requestHandler();
Message msg = Message.obtain(loaderThreadHandler, 1, queArray);
msg.sendToTarget();
}
});
}
@Override
public void onDestroy() {
super.onDestroy();
loadThread.quit();
} }
处理程序线程 :
public class LoaderThread extends HandlerThread implements Handler.Callback{
Handler imageHandler;
Handler loaderHandler;
Map<Integer,String> queMap;
HandlerActivity activity;
public LoaderThread(String name, Handler handler) {
super(name);
imageHandler= handler;
Log.d("inside : ", name);
}
Handler requestHandler(){
loaderHandler = new Handler(this.getLooper(),this);
return loaderHandler;
}
@Override
public boolean handleMessage(Message msg) {
String[] que = (String[]) msg.obj;
queMap = new HashMap<Integer,String>();
if(que != null){Log.d("",que[3]);}
for (int i=0;i<=4; i++){
String url = que[i];
queMap.put(i,url);
Log.d("1",url);
}
Log.d("THR : ", String.valueOf(Thread.currentThread()));
Random rand = new Random();
String link = queMap.get(rand.nextInt(5));
loadImages(link);
return true;
}
void loadImages(final String url){
Log.d("inside Load :","Inside Load");
try {
HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
final Bitmap image = BitmapFactory.decodeStream(connection.getInputStream());
imageHandler.post(new Runnable() {
@Override
public void run() {
activity.loadImage(image, url);
}
});
} catch (IOException e) {
e.printStackTrace();
}
} }
活动的加载图像方法:
public void loadImage(Bitmap image, String url) {
Bitmap img = image;
String link = url;
ft = fmg.beginTransaction();
ft.add(R.id.frag_container,imgFrag,"ImageFragment");
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
ft.show(imgFrag);
ft.commit();
imgFrag.loadImg(img,link);
}
此外,当我使用 log 检查我在哪个线程中(在 HandlerThread 中的句柄消息中)时,我会收到一条日志消息,因为我在 Main 中。怎么可能?我做错了什么吗?
LoaderFragment
的变化来自
mainHandler = new Handler(Looper.getMainLooper());
loadThread = new LoaderThread("LoaderThread",mainHandler);
自
loadThread = new LoaderThread("LoaderThread");
然后在LoaderThread
public LoaderThread(String name, Handler handler) {
super(name);
Log.d("inside : ", name);
}
@Override
protected void onLooperPrepared() {
imageHandler = new Handler(getLooper(), this);
}
您收到错误,因为您正在将 UI 线程循环器传递给 LoaderThread,您在网络访问requestHandler()
再次传递该线程。因此,您的网络操作由 UI 线程浏览器取消排队。
我遇到了同样的问题。然后我在名为 onLooperPrepared()
的覆盖方法中设置了我的HandlerThread's
处理程序,并且不再收到该异常,因此您应该尝试在 LoaderThread
类中执行以下操作:
@Override
protected void onLooperPrepared() {
super.onLooperPrepared();
loaderHandler = new Handler(this.getLooper(),this);
}
onLooperPrepared
,根据文档,我引用:回调方法,如果需要在 Looper 循环之前执行某些设置,可以显式覆盖该方法。请在这里告诉这是否适合您。
对于Android中的任何网络操作,建议在AsyncTask中编写该代码。