마스터Q&A 안드로이드는 안드로이드 개발자들의 질문과 답변을 위한 지식 커뮤니티 사이트입니다. 안드로이드펍에서 운영하고 있습니다. [사용법, 운영진]

네트워크작업, Thread & AsyncTask, StrictMode 질문입니다ㅜ.ㅜ

0 추천

안녕하세요 ㅜ.ㅜ 한국소프트웨어기술진흥협회(KOSTA)에서 47기로 수료를 앞둔 교육생입니다.

안드로이드 앱 프로젝트를 진행중인데 네트워크를 통한 이미지 출력에서 막혀 질문드립니다.

 

이전 프로젝트에서 구축한 웹프로젝트 DB 서버에서 데이터를 Json형태로 추출,

ListVIew에 CustomView를 적용해 이미지와 텍스트를 출력하도록 구현해봤는데요.

   1. Handler를 인자로 가지는 Thread 생성 및 시작.

   2. Thread에서 서버로 Json형태의 데이터값 리턴 요청.

   3. 리턴받은 데이터를 객체화해 CustomView에 출력.

 

최초 구현시에 android.os.NetworkOnMainThreadException이 발생해

메인Thread외 Thread 구현이 잘못되었나 싶어 AsyncTask 형태로도 구현해봤는데도

동일한 에러메시지가 출력되어 StrictMode를 사용했습니다.

StrictMode를 적용하니 출력은 되는데.. 데이터값을 받아 출력하기까지의 시간이 너무 길어집니다.ㅜㅜ

외부Thread로 제대로 구현이 가능한 경우 StrictMode를 쓸 필요가 없는게 맞는거겠죠?

제 Thread구현에서 무엇인가 잘못된 점이 있는지 체크 부탁드립니다!

 

package com.everymarket.main;

import java.util.ArrayList;
import java.util.List;

import org.json.JSONArray;
import org.json.JSONObject;

import com.everymarket.adapter.JjimAdapter_ListView;
import com.everymarket.adapter.ProductAdapter_ListView;
import com.everymarket.adapter.TradeAdapter_ListView;
import com.everymarket.model.Product;
import com.everymarket.model.Trade;

import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.StrictMode;
import android.annotation.TargetApi;
import android.app.Activity;
import android.app.ProgressDialog;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.Spinner;
import android.widget.Toast;

@TargetApi(Build.VERSION_CODES.GINGERBREAD)
public class Launch extends Activity {
	LinearLayout main_listProduct,  main_memberInfo,  main_memberInfo_listJjim,
				 main_memberInfo_listBuy, main_memberInfo_listSell;
	ListView listViewProduct, listViewJjim, listViewBuy, listViewSell;
	ProgressDialog progressDialog;
	
	List<Product> listJjim, listProduct;
	List<Trade> listTrade;

	ProductAdapter_ListView productAdapter;
	JjimAdapter_ListView jjimAdapter;
	TradeAdapter_ListView buyingAdapter, sellingAdapter;
	
	private EditText searchtext;

	int target = 1;
	String targetCode = null;

	ArrayAdapter<CharSequence> adspin;

	private final static String projectURL = "http://xxx.xxx.x.xx:8081/EveryMarket_v2.1/";
	private final static int THREADCODE_PRODUCT = 1;
	private final static int THREADCODE_JJIM = 2;
	private final static int THREADCODE_TRADEBUY = 3;
	private final static int THREADCODE_TRADESELL = 4;
	NetworkThread networkThread;
	AsyncThread fuckingThread;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.layout_launch);
		
		StrictMode.enableDefaults();
		
		listViewJjim = (ListView) findViewById(R.id.listJjim);
	
		listJjim = new ArrayList<Product>();
		jjimAdapter = new JjimAdapter_ListView(listJjim, this, projectURL);
		listViewJjim.setAdapter(jjimAdapter);
	}

	public boolean onClickMemberInfoButton(View v) {
		switch (v.getId()) {
		case R.id.button_memberInfo_callJjimList:
			main_memberInfo_listJjim.setVisibility(View.VISIBLE);
			main_memberInfo_listBuy.setVisibility(View.INVISIBLE);
			main_memberInfo_listSell.setVisibility(View.INVISIBLE);

			listJjim.clear();
			target = THREADCODE_JJIM;
			fuckingThread = (AsyncThread) new AsyncThread().execute(100);			
			return true;
		}

		return false;
	}

	public class AsyncThread extends AsyncTask<Integer, Integer, Integer> {

		@Override
		protected void onPreExecute() {
			progressDialog = new ProgressDialog(Launch.this);
			progressDialog.setTitle("데이터 불러오는중..");
			progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
			progressDialog.setCancelable(false);
			progressDialog.setProgress(0);
			progressDialog.show();
		}

		@Override
		protected Integer doInBackground(Integer... params) {
			JSONObject jsonObject = null;
			JSONArray jsonArray = null;
			
			try{
				switch (target) {
				case THREADCODE_JJIM:
					jsonObject = JSONfunctions.getJSON(projectURL
							+ "m_getJjimList.do");
					jsonArray = jsonObject.getJSONArray("listJjim");

					for (int i = 0; i < jsonArray.length(); i++) {
						JSONObject data = jsonArray.getJSONObject(i);

						Product product = new Product();
						product.setP_img(data.getString("p_img"));
						product.setP_name(data.getString("p_name"));

						listJjim.add(product);
					}

					break;
				}
			}catch(Exception e){
				e.printStackTrace();
			}
			
			return null;
		}

		@Override
		protected void onProgressUpdate(Integer... values) {
			progressDialog.setProgress(values[0]);
			super.onProgressUpdate(values);
		}

		@Override
		protected void onPostExecute(Integer result) {
			switch (target) {
			case THREADCODE_JJIM:
				jjimAdapter.notifyDataSetChanged();				
				break;
			}
			
			progressDialog.dismiss();
		}

	}

}

아래는 CustomView Adapter클래스입니다!

package com.everymarket.adapter;

import java.io.BufferedInputStream;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.util.List;

import com.everymarket.main.R;
import com.everymarket.model.Product;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.webkit.WebView;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;

public class JjimAdapter_ListView extends BaseAdapter {
	String projectURL;
	List<Product> listJjim;
	Context context;
	LayoutInflater inflater;

	public JjimAdapter_ListView(List<Product> listJjim, Context context, String url) {
		this.listJjim = listJjim;
		this.context = context;
		this.projectURL = url;
		this.inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
	}

	@Override
	public int getCount() {
		return listJjim.size();
	}

	@Override
	public Object getItem(int position) {
		return listJjim.get(position);
	}

	@Override
	public long getItemId(int position) {
		if(listJjim == null){
			return -1;
		}else{
			return position;
		}
	}

	@Override
	public View getView(int position, View convertView, ViewGroup parent) {
		if(convertView == null){
			convertView = inflater.inflate(R.layout.layout_jjimadapter, parent, false);
		}
		
		String imageUrl = projectURL + "image_product/" + listJjim.get(position).getP_img();
		Bitmap bm = getPic(imageUrl);
		
		ImageView jjimRealImage = (ImageView)convertView.findViewById(R.id.jjimRealImage);
		jjimRealImage.setImageBitmap(bm);
		
		TextView jjimImage = (TextView)convertView.findViewById(R.id.jjimImage);
		jjimImage.setText(listJjim.get(position).getP_img());
		
		TextView jjimName = (TextView)convertView.findViewById(R.id.jjimName);
		jjimName.setText(listJjim.get(position).getP_name());
		
		return convertView;
	}
	
	public Bitmap getPic(String imageUrl){
		Bitmap bm = null;
		try{
			URL url = new URL(imageUrl);
			URLConnection con = url.openConnection();
			con.connect();
			
			BufferedInputStream bis = new BufferedInputStream(con.getInputStream());			
			bm = BitmapFactory.decodeStream(bis);
			
			bis.close();
		}catch(Exception e){
			e.printStackTrace();
		}
		
		return bm;
	}

}

 

부탁드립니다 ㅜ_ㅜ 프로젝트 시연할 때 텍스트 한줄 불러오는데에 5초씩 걸리고싶진 않아요 Ora

 

kitchu (170 포인트) 님이 2013년 6월 5일 질문
질문글을 작성하면서 가만 생각해보니 Thread를 외부로 분리하고서도
"메인스레드에서 놀지말라니까!" 에러가 계속 뜨는 이유가
Handler역할의 오버라이딩 메서드 안의 CustomViewAdapter 코드 내에서
또다시 네트워크 작업(이미지를 불러오는)을 하기 때문 아닐까, 생각해봤습니다.

맞을까요 ㅜㅜ 맞다면 이미지 로딩하는 네트워크 작업은 대체 어디서 구현해야하는걸까요..
CustomViewAdapter클래스 내에서 다시 쓰레드를 내부클래스로 만들어야할까요?
CustomViewAdapter클래스 내에서 다시 쓰레드를 내부클래스로 만들어야할까요?
생각하신대로 하시면 될듯하네요

1개의 답변

0 추천
 
채택된 답변
말씀하신대로 BaseAdapter 내부 getView에서 getBitmap에서 쓰래드안쓰고 그냥 네트워크 연결해서 비트맵 가져오려고하네요.

connection이 들어가는 부분은 반드시 thread로 감싸야됩니다.

thread내부에서 이미지 다운로드가 완료되었으면 return view를 하면 되지 않을까 싶은데요..
기초개발자 (24,060 포인트) 님이 2013년 6월 5일 답변
kitchu님이 2013년 6월 6일 채택됨
답변 감사드립니다 ㅜㅜ 감동

BaseAdapter 내부에서도 Thread를 작성해야한다는 말씀이시죠?
그럼 getPic메서드 자체를 thread로 옮겨 구현하면 될것같은데..

점심시간 끝나고 바로 해봐야겠네요 감사합니다 선배님! ^.^*
...