(1)在碎片的onCreateView填充根view的时候,使用
View rootVIew = inflater.inflate(R.layout.fragment_mail, container, false);
而不是
View rootVIew = inflater.inflate(R.layout.fragment_mail, container);(默认只要root != null 就加进去 )
最后一个属性表示不加入container,否则他是XML的根。这里他是Fragment的根,所以不能加,如果加了,报错,child已经有了
父类。
在Menu填充的时候,只写了两个参数,这个出错了
* @param resource ID for an XML layout resource to load (e.g., * <code>R.layout.main_page</code>) * @param root Optional view to be the parent of the generated hierarchy (if * <em>attachToRoot</em> is true), or else simply an object that * provides a set of LayoutParams values for root of the returned * hierarchy (if <em>attachToRoot</em> is false.) * @param attachToRoot Whether the inflated hierarchy should be attached to * the root parameter? If false, root is only used to create the * correct subclass of LayoutParams for the root view in the XML. * @return The root View of the inflated hierarchy. If root was supplied and * attachToRoot is true, this is root; otherwise it is the root of * the inflated XML file.
(2)对于ArrayAdapter,最后填充的是List,如果是数组,会调用Arrays.asList(objects),如下:
/** * Constructor * * @param context The current context. * @param resource The resource ID for a layout file containing a layout to use when * instantiating views. * @param textViewResourceId The id of the TextView within the layout resource to be populated * @param objects The objects to represent in the ListView. */ public ArrayAdapter(Context context, @LayoutRes int resource, @IdRes int textViewResourceId, @NonNull T[] objects) { this(context, resource, textViewResourceId, Arrays.asList(objects)); }
但是,如果要改变ArrayAdapter,调用clear方法的时候报错,只有直接使用List,然后
List<String> weekForecast = new ArrayList<String>(Arrays.asList(weathers)); adapter = new ArrayAdapter<String>(getActivity(), R.layout.list_item_forecast, R.id.list_item_forecast_textview,weekForecast);
可以这样修改:
adapter.clear(); for(String dayForecastStr : result) { adapter.add(dayForecastStr); }
如果为了提高效率,可以使用addALl,这样一个个添加,会每次调用重新绘制,影响效率吧。
(3)AsyncTask的使用
访问网络的进程,不能在UI进程中,必须新建一个,但是新建Thread的话,如果Thread所在活动死了,这个Thread也死了,
这个貌似在服务讲过,为什么要使用服务,这里我们还没有使用服务,使用了AsyncTask,然后他有三个参数,四个步骤:
The three types used by an asynchronous task are the following:
Params
, the type of the parameters sent to the task upon execution.Progress
, the type of the progress units published during the background computation.Result
, the type of the result of the background computation.When an asynchronous task is executed, the task goes through 4 steps:
onPreExecute()
, invoked on the UI thread before the task is executed. This step is normally used to setup the task, for instance by showing a progress bar in the user interface.doInBackground(Params...)
, invoked on the background thread immediately after onPreExecute()
finishes executing. This step is used to perform background computation that can take a long time. The parameters of the asynchronous task are passed to this step. The result of the computation must be returned by this step and will be passed back to the last step. This step can also use publishProgress(Progress...)
to publish one or more units of progress. These values are published on the UI thread, in the onProgressUpdate(Progress...)
step.onProgressUpdate(Progress...)
, invoked on the UI thread after a call to publishProgress(Progress...)
. The timing of the execution is undefined. This method is used to display any form of progress in the user interface while the background computation is still executing. For instance, it can be used to animate a progress bar or show logs in a text field.onPostExecute(Result)
, invoked on the UI thread after the background computation finishes. The result of the background computation is passed to this step as a parameter.There are a few threading rules that must be followed for this class to work properly:
JELLY_BEAN
.execute(Params...)
must be invoked on the UI thread.onPreExecute()
, onPostExecute(Result)
, doInBackground(Params...)
, onProgressUpdate(Progress...)
manually.一些规则:(1)异步类必须有UI线程加载,他的实例也要在UI线程中创建
(2)execute方法必须在主线程调用,而且只能执行一次
(3)四个步骤方法不要手工调用,会帮你处理
(4)Json解析
安卓可以实际使用JsonObject,get有很多方法,还是很方便的
(5)发送HTTP请求 HttpURLConnection
参看AsynTask的实现吧:
public class FetchWeatherTask extends AsyncTask<String, Void, String[]>{ private final String LOG_TAG = FetchWeatherTask.class.getSimpleName(); @Override protected String[] doInBackground(String... params) { HttpURLConnection urlConnection = null; BufferedReader reader = null; String forecastJson = null; String format = "json"; String units = "metric"; int numDays = 7; String appId = "67e276002083cdb92a83a126472abc2d"; try { final String FORECAST_BASE_URL = "http://api.openweathermap.org/data/2.5/forecast/daily?"; final String QUERY_PARAM = "q"; final String FORMAT_PARAM = "mode"; final String UNITS_PARAM = "units"; final String DAYS_PARAM = "cnt"; final String APPID_PARAM = "APPID"; Uri buildUri = Uri.parse(FORECAST_BASE_URL).buildUpon(). appendQueryParameter(QUERY_PARAM, params[0]) .appendQueryParameter(UNITS_PARAM, units) .appendQueryParameter(FORMAT_PARAM, format) .appendQueryParameter(DAYS_PARAM, Integer.toString(numDays)) .appendQueryParameter(APPID_PARAM, appId) .build(); URL url = new URL(buildUri.toString()); Log.e(LOG_TAG, buildUri.toString()); urlConnection = (HttpURLConnection) url.openConnection(); urlConnection.setRequestMethod("GET"); urlConnection.connect(); InputStream inputStream = urlConnection.getInputStream(); StringBuffer buffer = new StringBuffer(); if(inputStream == null){ return null; } reader = new BufferedReader(new InputStreamReader(inputStream)); String line; while ((line = reader.readLine()) != null){ buffer.append(line + "\n"); } if(buffer.length() == 0){ return null; } forecastJson = buffer.toString(); return getWeatherDataFromJson(forecastJson, numDays); } catch (Exception e) { Log.e(LOG_TAG, "Error ", e); }finally{ if (urlConnection != null) { urlConnection.disconnect(); } if (reader != null) { try { reader.close(); } catch (final IOException e) { Log.e(LOG_TAG, "Error closing stream", e); } } } return null; } @Override protected void onPostExecute(String[] result) { if (result != null) { adapter.clear(); for(String dayForecastStr : result) { adapter.add(dayForecastStr); } // New data is back from the server. Hooray! } } /** * Take the String representing the complete forecast in JSON Format and * pull out the data we need to construct the Strings needed for the wireframes. * * Fortunately parsing is easy: constructor takes the JSON string and converts it * into an Object hierarchy for us. */ private String[] getWeatherDataFromJson(String forecastJsonStr, int numDays) throws JSONException { // These are the names of the JSON objects that need to be extracted. final String OWM_LIST = "list"; final String OWM_WEATHER = "weather"; final String OWM_TEMPERATURE = "temp"; final String OWM_MAX = "max"; final String OWM_MIN = "min"; final String OWM_DESCRIPTION = "main"; JSONObject forecastJson = new JSONObject(forecastJsonStr); JSONArray weatherArray = forecastJson.getJSONArray(OWM_LIST); // OWM returns daily forecasts based upon the local time of the city that is being // asked for, which means that we need to know the GMT offset to translate this data // properly. // Since this data is also sent in-order and the first day is always the // current day, we're going to take advantage of that to get a nice // normalized UTC date for all of our weather. Time dayTime = new Time(); dayTime.setToNow(); // we start at the day returned by local time. Otherwise this is a mess. int julianStartDay = Time.getJulianDay(System.currentTimeMillis(), dayTime.gmtoff); // now we work exclusively in UTC dayTime = new Time(); String[] resultStrs = new String[numDays]; for(int i = 0; i < weatherArray.length(); i++) { // For now, using the format "Day, description, hi/low" String day; String description; String highAndLow; // Get the JSON object representing the day JSONObject dayForecast = weatherArray.getJSONObject(i); // The date/time is returned as a long. We need to convert that // into something human-readable, since most people won't read "1400356800" as // "this saturday". long dateTime; // Cheating to convert this to UTC time, which is what we want anyhow dateTime = dayTime.setJulianDay(julianStartDay+i); day = getReadableDateString(dateTime); // description is in a child array called "weather", which is 1 element long. JSONObject weatherObject = dayForecast.getJSONArray(OWM_WEATHER).getJSONObject(0); description = weatherObject.getString(OWM_DESCRIPTION); // Temperatures are in a child object called "temp". Try not to name variables // "temp" when working with temperature. It confuses everybody. JSONObject temperatureObject = dayForecast.getJSONObject(OWM_TEMPERATURE); double high = temperatureObject.getDouble(OWM_MAX); double low = temperatureObject.getDouble(OWM_MIN); highAndLow = formatHighLows(high, low); resultStrs[i] = day + " - " + description + " - " + highAndLow; } for (String s : resultStrs) { Log.e(LOG_TAG, "Forecast entry: " + s); } return resultStrs; } /* The date/time conversion code is going to be moved outside the asynctask later, * so for convenience we're breaking it out into its own method now. */ private String getReadableDateString(long time){ // Because the API returns a unix timestamp (measured in seconds), // it must be converted to milliseconds in order to be converted to valid date. SimpleDateFormat shortenedDateFormat = new SimpleDateFormat("EEE MMM dd"); return shortenedDateFormat.format(time); } /** * Prepare the weather high/lows for presentation. */ private String formatHighLows(double high, double low) { // For presentation, assume the user doesn't care about tenths of a degree. long roundedHigh = Math.round(high); long roundedLow = Math.round(low); String highLowStr = roundedHigh + "/" + roundedLow; return highLowStr; } }